Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6b241528b | ||
|
|
8b07b3ae12 | ||
|
|
13cd3875d3 | ||
|
|
6ce3ebbb91 | ||
|
|
b3c0855236 | ||
|
|
25e87240f9 | ||
|
|
761e9718ec | ||
|
|
2fd858c97e | ||
|
|
d930266fbf | ||
|
|
aced1aa3a6 | ||
|
|
0f4e97ff28 | ||
|
|
03fe8be556 | ||
|
|
c93a06868d | ||
|
|
c96f8e0fb3 | ||
|
|
ce420a54a7 | ||
|
|
3dbcf7a8e3 | ||
|
|
307b01c0e3 | ||
|
|
c8cc19e8e7 | ||
|
|
51d26aeee7 | ||
|
|
22dd73c37f | ||
|
|
c835667d3d | ||
|
|
ee63b80d36 | ||
|
|
6bd81cf8ff | ||
|
|
a534964575 | ||
|
|
98c5867e6a | ||
|
|
32fc63c695 | ||
|
|
98d0bd0688 | ||
|
|
969e7ab53c | ||
|
|
827d55dbee |
@@ -0,0 +1 @@
|
|||||||
|
.git
|
||||||
@@ -1 +1,6 @@
|
|||||||
/.idea/*
|
/.idea/*
|
||||||
|
/docs/*
|
||||||
|
|
||||||
|
|
||||||
|
# 运行日志
|
||||||
|
/resource/log/*
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
## 目录结构与职责(硬性约束)
|
||||||
|
|
||||||
|
> **`biz/` 是泛化占位名,不是固定目录命名**。表格中 `biz/` 代表「业务模块目录」,各项目必须按自身业务命名替换(本项目即 `biz/`),禁止新项目照抄 `biz/`;`data/`、`workspace/` 亦为本项目目录名,各项目按自身命名。
|
||||||
|
|
||||||
|
| 目录 | 职责 | 强约束 |
|
||||||
|
|---|---|---|
|
||||||
|
| common/ | 通用层:HTTP 服务与鉴权中间件、文件解析(parser + pdf/docx/html/text)、中文分词、向量 JSON、DAO 基类、查询缓存、协程池封装 | 不得依赖业务模块包;新增跨模块通用能力放这里 |
|
||||||
|
| biz/consts/ | 常量集中地:表名(table_name.go)、状态(status.go)、内容类型、默认参数与各协程池默认大小(consts.go) | 业务常量一律在此集中,禁止散落 magic number;新增池默认大小在此定义 |
|
||||||
|
| biz/model/ | entity(表结构,与 DAO 一一对应)、dto(请求/响应结构,`g.Meta` 内嵌定义路由)、domain(领域模型:跨表聚合与服务层组装值,可被 dto/entity 引用) | entity 只做表映射,不带业务逻辑;dto 是 controller 与 HTTP 的唯一出入口;domain 收纳不属于 dto 也不属于 entity 的类型(见下) |
|
||||||
|
| biz/dao/ | 单表数据访问,每表一个文件 | 无业务逻辑;查询经 base_dao 缓存 |
|
||||||
|
| biz/service/ | 业务逻辑:规则校验、文件读写、事务、跨表组装、调用 dao、LLM 编排 | 不直接写 HTTP 响应(例外见下);并行任务走 common 协程池 |
|
||||||
|
| biz/controller/ | 接口层:接收参数、调用 service、组装返回值 | 见「分层职责规范」;禁止调用 dao |
|
||||||
|
| 运行时数据目录 | SQLite 库、上传/解析文件(本项目 `data/` `workspace/`) | 不提交 git;删除即丢失数据,改动前先确认 |
|
||||||
|
|
||||||
|
## 分层职责规范(硬性要求)
|
||||||
|
|
||||||
|
严格分层 `controller → service → dao`,禁止跨层调用(controller 禁止直接调 dao)。
|
||||||
|
|
||||||
|
| 层 | 目录 | 职责 | 禁止 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| controller | biz/controller | 接收 dto 请求参数(依赖 DTO `v` tag 自动校验)调用 service,原样返回 service 结果(返回类型与 service 一致,即 dto);**传参方式:整个 `*dto.XxxReq` 直接传给 service,禁止从 dto 拆出多个属性逐个传参** | 直接调用 dao;任何组装/映射/字段搬运;手写业务规则校验(库表依赖/跨字段,应下沉 service);文件 IO;状态流转;跨表数据组装 |
|
||||||
|
| service | biz/service | 业务逻辑:规则校验、文件读写、事务、跨表组装、调用 dao;只允许返回 dto 类型(返回与 controller 输出一致的 `*dto.XxxRes`),派生值(如 scene_name/node_count)在 service 用 dto 组装 | 直接写 HTTP 响应(例外见下);返回裸 gdb.Record 或任何非 dto 类型 |
|
||||||
|
| dao | biz/dao | 构建 SQL 并执行;行→结构体转换在 dao 内部用 GoFrame 自带方法(`Record.Struct` / `Result.Structs`,按 `orm` tag)完成,对外只允许返回 entity(或单值如 int/map) | 业务逻辑;返回裸 gdb.Record——**裸 gdb.Record 不允许作为任何分层方法的返回值**(含 service 内事务读),转换只发生在 dao 内部,不外泄 |
|
||||||
|
|
||||||
|
**例外**:SSE 流式响应、HTML/文件导出等"直接写响应体"的场景由 controller 完成——这是"值返回"的流式形式,事件序列化、心跳属 HTTP 协议职责,保留在 controller。
|
||||||
|
|
||||||
|
**分层锚定原则(controller 反向锚定,防跑偏)**:controller 只透传 ⇒ 接口返回类型以 dto 为准 ⇒ service 返回类型被 dto 锁死 ⇒ dao 输出被 entity 锁死。任何一层若出现"为下一层做数据搬运"(controller 映射 service 结果、service 逐键取裸 Record 字段),即违反本原则,应向上收敛:转换在 dao 内部(Record→entity)、组装在 service(entity→dto)、透传在 controller。
|
||||||
|
|
||||||
|
**教训(此前偏离原因,开发时引以为戒)**:
|
||||||
|
1. 自定义中转层不得替代 dto:domain 只收"不进 HTTP 出入参"的纯领域值(如结算输入 SettleState/结算结果 FinalSettle);凡出现在接口出入参中的类型一律用 dto,由 service 直接产出——否则 controller 被迫承担映射,违反"controller 只透传"
|
||||||
|
2. dao 必须完成行→结构体转换:裸 gdb.Record 的 string 键取值是魔法值,拼错列名编译期不报错,且会把键取值扩散到 service/controller;GoFrame 自带 `Record.Struct`/`Result.Structs`(按 `orm` tag)即转换手段
|
||||||
|
3. 新分层先对齐框架惯例:GoFrame 原生分层即 dao 转 entity / service 返回 dto / controller 薄透传,自定义设计前先核对框架默认范式
|
||||||
|
|
||||||
|
## 分层文件对齐与代码模式(硬性要求)
|
||||||
|
|
||||||
|
- 每张业务表对应一组 `entity / dao / service / controller / dto` 文件,数量严格对齐(核验方式:每层目录文件数 = 分层表数,分层表数 = 总表数 − 豁免表数);虚拟表(向量 vec0 / FTS5)与**流水/记录类表(如 point_log)豁免分层对齐**:不建任何独立分层文件(含 entity/dao),建表由主表 dao 统一管理(同虚拟表模式),由使用方 service 事务内直写,禁止为只写不读的审计表造分层门面;无任何读写引用的死表连表带分层整套删除,启动时 DROP 库内残留表与代码保持一致
|
||||||
|
- **非表文件一律不进业务分层目录**:路由注册与中间件装配、表初始化列表(建表 + 死表 DROP)直接写在 `main.go`;鉴权等跨模块通用能力放 `common/`;跨表业务流程归入所属表文件(如闯关 Choose 属 level 表)——分层目录出现非表文件即违反对齐,禁止以非表名开独立分层文件
|
||||||
|
- **不建 parser/rag 等技术目录**:纯技术能力(文档解析、中文分词、向量序列化)平铺在 `common/`;业务编排(分块、检索、工作流)归入对应 service 文件
|
||||||
|
- entity:每文件一张表,`orm` 标签与列名一致,时间字段用 `*gtime.Time`,只做表映射
|
||||||
|
- dto:请求/响应结构,`g.Meta` 内嵌定义路由;只描述 HTTP 出入参,不承载领域逻辑
|
||||||
|
- **domain(目录 `biz/model/domain/`,package domain)**:仅收纳**不进 HTTP 出入参**的纯领域值(如结算输入 SettleState/结算结果 FinalSettle,service 内部流转 + 单测使用);判断标准:类型是否出现在接口出入参中——出现即用 dto。entity 对表、dto 对 HTTP、domain 对纯领域;service 返回 dto(允许 import dto),dao 返回 entity(禁止外泄 gdb.Record)
|
||||||
|
- dao:单例 `var Xxx = &xxxDao{}`,`init()` 内 `CREATE TABLE IF NOT EXISTS` + 索引 + 迁移;通用 CRUD 复用 `common/base_dao.go`(InsertAndReturnId / GetOneByPk / UpdateByPk)
|
||||||
|
- controller:路由**反射注册**(`common.BindController`),path/method 唯一来源为 dto 的 `g.Meta`(携带 path/method/summary);新增接口只需写 dto + controller 方法,禁止在 main.go 手动逐条注册;跨组方法以 `H5` 前缀命名(h5 组只注册 H5 开头方法,admin 组跳过)
|
||||||
|
- **接口只允许 GET / POST**:写操作传 JSON body(或 multipart),读操作走 query params;无 PUT/DELETE
|
||||||
|
- dao 查询缓存:查询用 `gdb.CacheOption`(TTL 来自配置),**写操作后必须清对应缓存**,否则出现"库里已改、查询还是旧值"
|
||||||
|
|
||||||
|
## 错误处理规范(硬性要求)
|
||||||
|
|
||||||
|
- 所有可能失败的调用必须显式处理返回的 error:向上返回(保留上下文用 `gerror.Wrap`/`Newf`)或记录日志,禁止 `_, _ =` 静默丢弃——吞错会掩盖故障根因,修复问题必须先定位错误路径,不得以忽略 error 换取编译通过
|
||||||
|
- defer 关闭等无法向上返回的资源清理错误,用 `defer func() { _ = x.Close() }()` 显式声明忽略意图,禁止裸 `defer x.Close()` 隐式吞错
|
||||||
|
|
||||||
|
## 并发规范
|
||||||
|
|
||||||
|
- **可并行的场景**:纯 IO 任务——读查询、LLM/Embedding 调用、文件读取。SQLite 写一律回主 goroutine 串行(无 WAL 时并发写会 `database is locked`,锁定风险归零,并发只赢在 IO 等待上)
|
||||||
|
- **新增并行点的固定三处**:common 加池封装(grpool)→ `biz/consts` 加默认大小 → `config.yml` 加 `key: 并发度`(缺失或非法时回退默认值)
|
||||||
|
- 禁止直接用裸 `go` 启动并行工作负载,一律走 `common` 的池
|
||||||
|
- **防死锁**:等待链单向「主 → A池 → B池」,被等待池的任务内不得再等待任何池(会饿死 worker);池无 Wait 方法,等待用调用方 `sync.WaitGroup`,任务结果经 buffered channel 回主 goroutine
|
||||||
|
- **共享状态安全(内存)**:池内任务并发执行,共享实例(service 单例、model 句柄等)只允许**只读**访问;可变字段必须在**提交池之前**由主 goroutine 一次性预置,任务内禁止写共享字段——Go map 并发写直接 `fatal error: concurrent map writes`,无锁、无降级、不可恢复,只能崩溃重启。需要可变共享状态时按优先级:① 无共享(任务内新建、buffered channel 传递结果)② 锁(`sync.Mutex`/`RWMutex`,锁内只做内存操作,LLM/DB 等 IO 放锁外)③ `sync/atomic`(仅限 int 类标量计数/标志,如 `atomic.AddInt64`,并发计数禁用普通 `++`;复合结构不要用 atomic,指针 CAS 属例外)
|
||||||
|
- **锁的使用**:互斥场景唯一入口是 `common.WithLock[T any](ctx, key, expire, retries, retryInterval, fn func() (T, error)) (T, error)`——泛型回调,业务返回值经 T 原样透出给下游;内部按 config.yml 自动选择锁实现(配置了 `redis` 节点 → redis 锁,跨实例互斥,SET NX EX + token 对比删除防误删他人锁;未配置 → gcache 内存锁,单实例互斥),禁止直接用 gcache/gredis 自己实现加锁。拿不到锁(被占用,`ErrLockHeld`)最多重试 `retries` 次、每次间隔 `retryInterval`(`retries=0` 立即失败;ctx 取消/超时同样终止等待);中间件故障不重试直接返回。锁自动释放:无论 fn 成功、失败还是 panic,defer 释放。`expire` 必须 > 0(进程崩溃兜底不死锁),fn 耗时必须在 expire 前完成,fn 内禁止长耗时 IO(LLM/DB 调用);锁粒度按业务唯一键尽量小
|
||||||
|
- **裸 `go` 允许的例外**:`go func(){ wg.Wait(); close(ch) }()` 收尾惯用法、SSE 心跳、流式管道(Stream 读写)等长生命周期/非工作负载协程
|
||||||
|
|
||||||
|
## 文档职责(三文档体系)
|
||||||
|
|
||||||
|
| 文档 | 职责 | 何时补充/更新 |
|
||||||
|
|---|---|---|
|
||||||
|
| CLAUDE.md(本文件) | 公司通用开发规范:分层职责、代码模式、并发/事务/缓存约束、流程 | 规范变化时 |
|
||||||
|
| README.md | 项目功能介绍:架构、数据流、表清单、功能模块、API 清单、使用说明 | 功能增减时 |
|
||||||
|
| 技术设计.md | 实现细节与技术决策:DDL、检索参数、风险与备选方案 | 关键技术决策/参数变化时 |
|
||||||
|
|
||||||
|
## 开发流程(文档驱动,硬性要求)
|
||||||
|
|
||||||
|
永远以文档驱动开发:用户提出开发需求 → 先给出实现方案(技术选型、影响面、改动清单) → **用户确认后先补充文档再动手写代码**。补充哪个文档取决于内容性质:规范 → 本文件,功能 → README,实现细节/技术决策 → 技术设计.md。禁止未经确认直接开发,禁止先写代码后补文档。
|
||||||
|
|
||||||
|
## 数据访问规范(硬性要求)
|
||||||
|
|
||||||
|
- **事务**:涉及多张表的增删改操作必须包数据库事务,禁止逐表裸调用。**事务必须在 service 层**(`g.DB().Transaction` 包裹与事务内写方法如 `XxxInTx`,service 持有 tx 句柄编排多表),dao 层只做单表无状态 CRUD,不持事务;`tx.Begin` 后必须用 `defer` 防护已提交后的二次 Rollback
|
||||||
|
- **SQL 单表约束**:每个 SQL 只允许访问一张表,禁止 JOIN 与跨表子查询(`IN (SELECT ...)` / `EXISTS`);跨表数据一律拆为多条单表 SQL + 应用层内存组装——先取外键 id 列表,再对目标表 `IN` 查询;`IN` 参数须按 ≤100 分批(SQLite 变量数上限 999)
|
||||||
|
- **禁止 N+1 查询**:禁止在循环中逐条查库。循环场景一律改为批处理——一次 `ListByXxx` 取回后按外键在内存分组
|
||||||
|
- **缓存一致性**:DAO 查询走缓存(TTL 来自 `database.cache.ttl`),写操作后必须清对应缓存
|
||||||
|
- **批处理 SQL**:批量写入用 `InsertAll` 类方法,批量删除用 `IN` 子句,禁止循环单条 INSERT/DELETE
|
||||||
|
- **配置即使用**:config.yml 中出现 redis / mq 等中间件配置时,代码必须实际接入使用,禁止"配置了但代码不用"或"代码写死但配置缺失"
|
||||||
|
- **消息/回调幂等**:接入 MQ / Webhook 时,消费与回调处理必须幂等——MQ 至少一次语义、webhook 失败重试都可能重复投递同一事件,禁止依赖"只投一次"假设。幂等手段:以业务唯一键(如 `任务ID + 事件类型`)先查重或建唯一约束再落库,重复事件直接忽略;重试与补偿逻辑同样要防重复执行
|
||||||
|
|
||||||
|
## 运维部署规范(硬性要求)
|
||||||
|
|
||||||
|
- **部署形态**:Docker Compose 单机部署,前后端一体单端口;运行时数据目录挂载持久化,容器重建不丢数据。部署文件在项目根目录(`Dockerfile` / `docker-compose.yml`),启动与使用见 README
|
||||||
|
- **数据即文件**:文件型存储,备份 = 打包「数据库目录(小而关键)+ 上传文件目录(大而可重建)」两个目录;迁移 = 拷贝到新机器即可
|
||||||
|
- **运行时数据与代码分离**:数据目录不提交 git;**删除即丢数据,改动前先确认**
|
||||||
|
- **配置即文件**:项目配置文件为唯一配置入口(监听端口、并发度等),环境变量覆盖无效
|
||||||
|
|
||||||
|
## 金额单位规范(硬性要求)
|
||||||
|
|
||||||
|
- **金额一律以「分」为单位存储与传输**:所有金额字段(零售价、进价、单价、小计、总金额)在数据库与接口中使用整数分(entity/dto 字段类型 `int64`),禁止浮点元
|
||||||
|
- **展示转换在前端**:前端展示 ÷100 转元保留两位小数,提交 ×100 转分;禁止后端做元↔分转换,后端只处理整数分
|
||||||
|
- **金额计算**:`数量(浮点克) × 单价(分)` 后必须 `common.RoundInt` 四舍五入到整数分,禁止裸浮点累加
|
||||||
|
- **量纲区分**:数量/库存/用量为浮点克(REAL),金额为整数分;混算时必须显式转换
|
||||||
|
- 存量库迁移以 `PRAGMA user_version` 版本化标记,禁止重复执行
|
||||||
|
|
||||||
|
## 约定
|
||||||
|
|
||||||
|
- controller 方法签名固定为 `(ctx, *dto.XxxReq) (*dto.XxxRes, error)`,实例注册模式 `var Xxx = &xxx{}`
|
||||||
|
- **参数校验优先用 GoFrame DTO 校验**:请求结构体用 `v` tag(required / regex / in 等)声明,框架自动校验并返回错误,controller 不手写校验;仅 DTO 表达不了的业务规则(跨字段依赖、查库校验如重名、取值范围依赖配置)放 service。JSON 格式解析可留在 controller 或下沉 service,但须保持与调用点一致
|
||||||
|
- 响应组装(实体 → DTO 字段映射)在 controller 进行
|
||||||
|
- service 方法签名 ctx 开头,错误统一用 `gerror`
|
||||||
|
- 编译验证:`go build ./...`
|
||||||
|
|
||||||
+21
-53
@@ -1,57 +1,25 @@
|
|||||||
FROM golang:1.25.3
|
# 阶段1: 构建
|
||||||
RUN go env -w GO111MODULE=on
|
FROM golang:alpine AS builder
|
||||||
RUN go env -w GOPROXY=https://goproxy.cn,direct
|
|
||||||
ENV WORKDIR /usr/local/bin/app
|
|
||||||
WORKDIR $WORKDIR
|
|
||||||
|
|
||||||
ENV TIME_ZONE=Asia/Seoul
|
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
|
||||||
RUN useradd -ms /bin/bash golang
|
apk add --no-cache git ca-certificates tzdata
|
||||||
|
|
||||||
|
ENV TZ=Asia/Shanghai
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
ENV GO111MODULE=on
|
||||||
|
ENV GOPROXY=https://goproxy.cn,direct
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
ENV GOTOOLCHAIN=auto
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN go mod download && go mod tidy
|
||||||
|
|
||||||
|
RUN go build -ldflags="-s -w" -o main ./main.go
|
||||||
|
|
||||||
|
|
||||||
RUN ln -sf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime \
|
EXPOSE 3001
|
||||||
&& chmod 0755 /usr/bin/wall \
|
|
||||||
&& chmod 0755 /usr/bin/passwd \
|
|
||||||
&& chmod 0755 /usr/bin/newgrp \
|
|
||||||
&& chmod 0755 /usr/bin/chfn \
|
|
||||||
&& chmod 0755 /usr/bin/chage \
|
|
||||||
&& chmod 0755 /usr/bin/gpasswd \
|
|
||||||
&& chmod 0755 /usr/bin/chsh \
|
|
||||||
&& chmod 0755 /usr/bin/expiry \
|
|
||||||
&& chmod 0755 /bin/umount \
|
|
||||||
&& chmod 0755 /bin/mount \
|
|
||||||
&& chmod 0755 /bin/su \
|
|
||||||
&& chmod 0755 /sbin/unix_chkpwd \
|
|
||||||
&& chmod 110 /usr/bin/chfn \
|
|
||||||
&& chmod 110 /usr/bin/passwd \
|
|
||||||
&& chmod 110 /usr/bin/newgrp \
|
|
||||||
&& chmod 110 /usr/bin/chsh \
|
|
||||||
&& chmod 110 /usr/bin/wall \
|
|
||||||
&& chmod 110 /usr/bin/gpasswd \
|
|
||||||
&& chmod 110 /usr/bin/expiry \
|
|
||||||
&& chmod 110 /usr/bin/chage \
|
|
||||||
&& chmod 110 /bin/mount \
|
|
||||||
&& chmod 110 /bin/umount \
|
|
||||||
&& chmod 110 /bin/su \
|
|
||||||
&& chmod 110 /sbin/unix_chkpwd \
|
|
||||||
&& chmod 110 /usr/lib/openssh/ssh-keysign \
|
|
||||||
&& chmod 110 /usr/bin/ssh-agent
|
|
||||||
|
|
||||||
COPY go.mod go.sum ./
|
CMD ["./main"]
|
||||||
# RUN chown -R golang:golang $WORKDIR
|
|
||||||
RUN go mod download && go mod verify
|
|
||||||
COPY ../../cid $WORKDIR
|
|
||||||
RUN chown -R golang:golang $WORKDIR
|
|
||||||
# Remove SetUID, SetGID
|
|
||||||
RUN chmod 0755 /usr/local/bin/app/api \
|
|
||||||
&& chmod 0755 /usr/local/bin/app/common \
|
|
||||||
&& chmod 0755 /usr/local/bin/app/middleware \
|
|
||||||
&& chmod 0755 /usr/local/bin/app/model \
|
|
||||||
&& rm -rf .git \
|
|
||||||
&& rm -rf .gitignore \
|
|
||||||
&& rm -rf .gitlab-ci.yml \
|
|
||||||
&& rm -rf Dockerfile.bak \
|
|
||||||
&& rm -rf config-local.yml
|
|
||||||
USER golang
|
|
||||||
RUN go build -v -o /usr/local/bin/app ./...
|
|
||||||
EXPOSE 3002
|
|
||||||
CMD ./cid
|
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
# CID
|
||||||
|
|
||||||
|
CID 服务,承载三块业务:
|
||||||
|
|
||||||
|
1. **内容审核(现有)**:将广告素材(图片/视频)提交易盾进行内容审核,提供 REST API、定时送检调度器和前端管理页
|
||||||
|
2. **投放平台(规划中)**:外投对接广告平台营销 API(巨量/聚光/磁力等)建计划、传素材、启停调优、拉报表;自有 DSP 投自有媒体流量(PD 直投/程序化直购 + RTB 实时竞价)
|
||||||
|
3. **CID 归因平台(规划中)**:连接投放与电商平台(京东/淘宝等),记录广告点击、归因转化、回传转化给广告平台(自有流量转化回流自身优化)
|
||||||
|
|
||||||
|
## 目录结构与业务模块
|
||||||
|
|
||||||
|
分层 + 业务模块结构:顶层按层分目录,每层下按业务域分子模块,各层模块目录严格镜像。
|
||||||
|
|
||||||
|
```
|
||||||
|
controller/ HTTP 接口层,按模块分子目录
|
||||||
|
service/ 业务逻辑层,按模块分子目录
|
||||||
|
dao/ 数据访问层,按模块分子目录(各模块 db.go 提供 Model helper 选择数据源库)
|
||||||
|
model/
|
||||||
|
├── entity/ 数据库表实体(每表一个文件:Entity + Col + Cols 三段式)
|
||||||
|
├── dto/ 请求/响应结构
|
||||||
|
└── event/ 事件体(MQ/ClickHouse 消息契约,规划中)
|
||||||
|
consts/ 常量(表名、状态),按模块分子目录
|
||||||
|
resource/frontend/ 静态前端页面
|
||||||
|
sql/ DDL 与迁移脚本
|
||||||
|
```
|
||||||
|
|
||||||
|
| 模块 | 业务域 | 主要表 |
|
||||||
|
|---|---|---|
|
||||||
|
| check/ | 内容审核(现有):易盾检测提交/回调/轮询、素材校验、送检调度 | tencent_image、tencent_video、material_verify_log、tencent_content_check_log、tencent_account_relation |
|
||||||
|
| delivery/ | 投放域(规划):计划树四层(计划/单元/广告/创意),本地实体 + 平台 ID 双轨同步 | campaign、ad_group、ad、creative |
|
||||||
|
| material/ | 素材域(规划):素材文件库与多通道审核状态机 | material、material_audit |
|
||||||
|
| dsp/ | 自有流量域(规划):自有媒体/广告位、PD 预订单、RTB 请求与展示计费 | media、ad_slot、placement、bid_request_log、auction_log |
|
||||||
|
| attribution/ | 归因域(规划):点击记录、CID 生成、订单归因与转化回传(点击→转化→回传为同一链路) | click_log、conversion_order、report_task |
|
||||||
|
| platform/ | 平台配置域(规划):广告账户(多级层级 + API 凭据 + 能力)、下游电商平台对接配置与商品映射 | ad_account、commerce_platform_config、item_mapping |
|
||||||
|
| report/ | 报表域(规划):统一消耗/效果汇总(外投平台报表 + DSP 聚合) | daily_report |
|
||||||
|
|
||||||
|
> 租户/广告主信息由 admin-go 承载,CID 各表以 `tenant_id` 隔离,不建账户/租户表。
|
||||||
|
|
||||||
|
## 数据流
|
||||||
|
|
||||||
|
**内容审核链路**:
|
||||||
|
|
||||||
|
```
|
||||||
|
素材表(tencent_image/tencent_video, dataengine库)
|
||||||
|
→ 定时送检调度器 / 手动送检
|
||||||
|
→ 易盾检测(回调模式或轮询模式)
|
||||||
|
→ 结果写入 material_verify_log(cid库) + 回填素材表审核状态
|
||||||
|
```
|
||||||
|
|
||||||
|
**投放链路(规划)**:
|
||||||
|
|
||||||
|
```
|
||||||
|
外投:CID 创建计划(campaign/单元/广告/创意,本地草稿)
|
||||||
|
→ 同步平台营销 API(计划/单元/广告/创意/素材上传)
|
||||||
|
→ 平台审核(素材审核状态机)→ 启停/调价 → 拉取平台报表 → daily_report
|
||||||
|
|
||||||
|
自有DSP:PD直投(placement 预订单)或 RTB 竞价(bid_request_log → auction_log)
|
||||||
|
→ 展示/点击计费 → 点击进归因链路(channel=self_dsp)
|
||||||
|
```
|
||||||
|
|
||||||
|
**CID 归因链路(规划)**:
|
||||||
|
|
||||||
|
```
|
||||||
|
用户点击广告 → 广告平台/自有媒体跳转 CID(携带广告参数)
|
||||||
|
→ 生成 click_id、记录点击(click_log)→ 302 跳转电商平台(URL 带 click_id)
|
||||||
|
→ 用户下单支付 → 电商平台回调 CID(订单 + click_id)
|
||||||
|
→ 归因去重(conversion_order,幂等)→ 回传转化给广告平台(report_task 队列 + 失败重试)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 表清单
|
||||||
|
|
||||||
|
### check 模块(现有)
|
||||||
|
|
||||||
|
| 表 | 库 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| tencent_image | dataengine | 图片素材(外部系统共享) |
|
||||||
|
| tencent_video | dataengine | 视频素材(外部系统共享) |
|
||||||
|
| material_verify_log | cid | 素材校验日志(易盾结果落库) |
|
||||||
|
| tencent_content_check_log | cid | 送检日志 |
|
||||||
|
| tencent_account_relation | cid | 腾讯广告账户关系 |
|
||||||
|
|
||||||
|
### 投放/归因模块(规划,DDL 见技术设计.md)
|
||||||
|
|
||||||
|
| 表 | 库 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| ad_account | cid | 广告账户(多级层级 + API 凭据 + 能力,由 ad_platform_account 改造) |
|
||||||
|
| campaign / ad_group / ad / creative | cid | 计划树四层(本地实体 + 平台 ID 双轨) |
|
||||||
|
| material / material_audit | cid | 素材库 + 多通道审核状态机 |
|
||||||
|
| media / ad_slot / placement | cid | 自有媒体/广告位/PD 预订单 |
|
||||||
|
| bid_request_log / auction_log | cid | RTB 请求日志 / 展示计费(按 day 分区) |
|
||||||
|
| click_log | cid | 点击日志(不可变事件),按 day 分区 |
|
||||||
|
| conversion_order | cid | 转化订单(归因与回传状态) |
|
||||||
|
| report_task | cid | 转化回传任务队列(失败退避重试) |
|
||||||
|
| daily_report | cid | 统一消耗/效果汇总(外投报表 + DSP 聚合) |
|
||||||
|
| commerce_platform_config | cid | 下游电商平台对接配置 |
|
||||||
|
| item_mapping | cid | 广告商品 ↔ 电商商品映射 |
|
||||||
|
|
||||||
|
## API 清单
|
||||||
|
|
||||||
|
路由由 common 库 `http.RouteRegister` 反射注册:路径按控制器结构体名 + 方法名自动派生(如 `YidunController` 的 `DetectText` → `/yidun/controller/detect-text`)。main.go 注册的控制器:
|
||||||
|
|
||||||
|
| 控制器 | 职责 |
|
||||||
|
|---|---|
|
||||||
|
| check.YidunController | 文本/图片/视频检测提交、结果查询 |
|
||||||
|
| check.YidunCallback | 易盾回调接收、结果轮询 |
|
||||||
|
| check.ContentCheck | 送检调度器启停、状态查询、手动送检 |
|
||||||
|
| check.MaterialVerify | 素材校验列表/统计/人工审核/导出 |
|
||||||
|
|
||||||
|
## 构建与运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 构建
|
||||||
|
docker build -t cid .
|
||||||
|
|
||||||
|
# 本地运行(需 Go 1.26)
|
||||||
|
go mod download && go mod tidy
|
||||||
|
go run main.go
|
||||||
|
|
||||||
|
# 编译
|
||||||
|
go build -ldflags="-s -w" -o main ./main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
配置入口为 `config.yml`(易盾凭据、callback_mode、content_check 调度参数、数据库连接等)。
|
||||||
+103
-8
@@ -1,18 +1,58 @@
|
|||||||
server:
|
server:
|
||||||
address : ":3001"
|
address : ":3001"
|
||||||
name: "cid"
|
name: "cid"
|
||||||
|
workerId: 1
|
||||||
|
logPath: "resource/log/server"
|
||||||
|
logStdout: true
|
||||||
|
errorStack: true
|
||||||
rate:
|
rate:
|
||||||
limit: 200
|
limit: 200
|
||||||
burst: 300
|
burst: 300
|
||||||
mongo:
|
|
||||||
logger:
|
# Database.
|
||||||
level: "all"
|
database:
|
||||||
stdout: true
|
cid:
|
||||||
address: "mongodb://116.204.74.41:27017/cid_service?retryWrites=true"
|
- type: "pgsql"
|
||||||
|
host: "192.168.0.83"
|
||||||
|
port: "15432"
|
||||||
|
user: "sql9f15b63fd203b36e"
|
||||||
|
pass: "1ec94b1acdaf57b66030242d418fad5a"
|
||||||
|
name: "cid"
|
||||||
|
role: "master"
|
||||||
|
maxIdle: "5"
|
||||||
|
maxOpen: "20"
|
||||||
|
maxLifetime: "60s"
|
||||||
|
charset: "utf8mb4"
|
||||||
|
debug: true
|
||||||
|
dryRun: false
|
||||||
|
createdAt: "created_at"
|
||||||
|
updatedAt: "updated_at"
|
||||||
|
deletedAt: "deleted_at"
|
||||||
|
timeMaintainDisabled: false
|
||||||
|
# data-engine 数据库配置(用于存放 tencent_image, tencent_video 等送检表)
|
||||||
|
dataEngine:
|
||||||
|
- type: "pgsql"
|
||||||
|
host: "192.168.0.83"
|
||||||
|
port: "15432"
|
||||||
|
user: "sql9f15b63fd203b36e"
|
||||||
|
pass: "1ec94b1acdaf57b66030242d418fad5a"
|
||||||
|
name: "engine"
|
||||||
|
role: "master"
|
||||||
|
maxIdle: "5"
|
||||||
|
maxOpen: "20"
|
||||||
|
maxLifetime: "60s"
|
||||||
|
charset: "utf8mb4"
|
||||||
|
debug: true
|
||||||
|
dryRun: false
|
||||||
|
createdAt: "created_at"
|
||||||
|
updatedAt: "updated_at"
|
||||||
|
deletedAt: "deleted_at"
|
||||||
|
timeMaintainDisabled: false
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
# 集群模式配置方法
|
# 集群模式配置方法
|
||||||
default:
|
default:
|
||||||
address: 116.204.74.41:6379
|
address: 192.168.0.83:6379
|
||||||
db: 0
|
db: 0
|
||||||
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/1m/1d
|
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/1m/1d
|
||||||
maxConnLifetime: "90s" #连接最长存活时间,使用时间字符串例如30s/1m/1d
|
maxConnLifetime: "90s" #连接最长存活时间,使用时间字符串例如30s/1m/1d
|
||||||
@@ -22,7 +62,62 @@ redis:
|
|||||||
writeTimeout: "30s" #TCP的Write操作超时时间,使用时间字符串例如30s/1m/1d
|
writeTimeout: "30s" #TCP的Write操作超时时间,使用时间字符串例如30s/1m/1d
|
||||||
maxActive: 100
|
maxActive: 100
|
||||||
consul:
|
consul:
|
||||||
address: 116.204.74.41:8500
|
address: 192.168.0.83:8500
|
||||||
# pass: jiahui8888
|
# pass: jiahui8888
|
||||||
jaeger: #链路追踪
|
jaeger: #链路追踪
|
||||||
addr: 116.204.74.41:4318
|
addr: 192.168.0.83:4318
|
||||||
|
|
||||||
|
yidun:
|
||||||
|
# 回调模式开关: true=使用回调模式(需要公网地址), false=使用轮询模式
|
||||||
|
callback_mode: false
|
||||||
|
# 易盾回调 IP 白名单(逗号分隔),留空则不校验
|
||||||
|
callback_allowed_ips: ""
|
||||||
|
|
||||||
|
# 视频检测配置
|
||||||
|
video:
|
||||||
|
secret_id: "f58a38341ca6227014df7c3bf0e6f16f"
|
||||||
|
secret_key: "526aa631ba5d518aedeb70b5a3b67371"
|
||||||
|
region: "cn-hangzhou"
|
||||||
|
protocol: "https"
|
||||||
|
max_retry_count: 3
|
||||||
|
# 易盾回调地址(用于接收检测结果推送)
|
||||||
|
# 替换为实际可访问的地址
|
||||||
|
callback_url: "http://your-domain.com:3001/yidun/callback/receiveVideo"
|
||||||
|
|
||||||
|
# 图片检测配置
|
||||||
|
image:
|
||||||
|
business_id: "20acccc525cbc5cb6bed3d8f6f6b2f77"
|
||||||
|
secret_id: "9a82f90bfec61eb40d1c95605b894817"
|
||||||
|
secret_key: "f73a78954417a3713c36ec2d14eb2b5f"
|
||||||
|
region: "cn-hangzhou"
|
||||||
|
protocol: "https"
|
||||||
|
max_retry_count: 3
|
||||||
|
# 易盾回调地址(用于接收检测结果推送)
|
||||||
|
# 替换为实际可访问的地址
|
||||||
|
callback_url: "http://your-domain.com:3001/yidun/callback/receiveImage"
|
||||||
|
|
||||||
|
# 文本检测配置(如需要请补充)
|
||||||
|
text:
|
||||||
|
business_id: "YOUR_TEXT_BUSINESS_ID"
|
||||||
|
secret_id: "YOUR_TEXT_SECRET_ID"
|
||||||
|
secret_key: "YOUR_TEXT_SECRET_KEY"
|
||||||
|
region: "cn-hangzhou"
|
||||||
|
protocol: "https"
|
||||||
|
max_retry_count: 3
|
||||||
|
# 易盾回调地址(用于接收检测结果推送)
|
||||||
|
# 替换为实际可访问的地址
|
||||||
|
callback_url: "http://your-domain.com:3001/yidun/callback/receiveText"
|
||||||
|
|
||||||
|
# 内容送检定时任务配置
|
||||||
|
content_check:
|
||||||
|
# 是否启动定时送检任务(true=启动定时任务自动送检,false=不启动,仅通过API手动送检)
|
||||||
|
scheduler_enabled: false
|
||||||
|
# 每批处理数量
|
||||||
|
batch_size: 10
|
||||||
|
# 是否启用图片检测
|
||||||
|
image_enabled: false
|
||||||
|
# 是否启用视频检测
|
||||||
|
video_enabled: false
|
||||||
|
# 定时任务执行间隔(秒)
|
||||||
|
interval_seconds: 30
|
||||||
|
poll_interval: 60
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// AdFormatType 广告格式类型枚举
|
|
||||||
type AdFormatType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AdFormatTypeBanner AdFormatType = "banner" // 横幅广告
|
|
||||||
AdFormatTypeVideo AdFormatType = "video" // 视频广告
|
|
||||||
AdFormatTypeNative AdFormatType = "native" // 原生广告
|
|
||||||
AdFormatTypeInterstitial AdFormatType = "interstitial" // 插屏广告
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllAdFormatTypes 获取所有广告格式类型
|
|
||||||
func GetAllAdFormatTypes() []AdFormatType {
|
|
||||||
return []AdFormatType{
|
|
||||||
AdFormatTypeBanner,
|
|
||||||
AdFormatTypeVideo,
|
|
||||||
AdFormatTypeNative,
|
|
||||||
AdFormatTypeInterstitial,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdFormatTypeKeyValue struct {
|
|
||||||
Key AdFormatType
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
AdFormatTypeBannerKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeBanner, Value: "横幅广告"}
|
|
||||||
AdFormatTypeVideoKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeVideo, Value: "视频广告"}
|
|
||||||
AdFormatTypeNativeKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeNative, Value: "原生广告"}
|
|
||||||
AdFormatTypeInterstitialKeyValue = AdFormatTypeKeyValue{Key: AdFormatTypeInterstitial, Value: "插屏广告"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllAdFormatTypeKeyValue() []AdFormatTypeKeyValue {
|
|
||||||
return []AdFormatTypeKeyValue{
|
|
||||||
AdFormatTypeBannerKeyValue,
|
|
||||||
AdFormatTypeVideoKeyValue,
|
|
||||||
AdFormatTypeNativeKeyValue,
|
|
||||||
AdFormatTypeInterstitialKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var adFormatTypeValueMap = map[AdFormatType]string{
|
|
||||||
AdFormatTypeBanner: AdFormatTypeBannerKeyValue.Value,
|
|
||||||
AdFormatTypeVideo: AdFormatTypeVideoKeyValue.Value,
|
|
||||||
AdFormatTypeNative: AdFormatTypeNativeKeyValue.Value,
|
|
||||||
AdFormatTypeInterstitial: AdFormatTypeInterstitialKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAdFormatTypeValueByKey(key AdFormatType) (value string) {
|
|
||||||
value, exists := adFormatTypeValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知广告格式"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// AdSourceHealth 广告源健康状态枚举
|
|
||||||
type AdSourceHealth string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AdSourceHealthHealthy AdSourceHealth = "healthy" // 健康
|
|
||||||
AdSourceHealthDegraded AdSourceHealth = "degraded" // 降级
|
|
||||||
AdSourceHealthUnhealthy AdSourceHealth = "unhealthy" // 不健康
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllAdSourceHealths 获取所有广告源健康状态
|
|
||||||
func GetAllAdSourceHealths() []AdSourceHealth {
|
|
||||||
return []AdSourceHealth{
|
|
||||||
AdSourceHealthHealthy,
|
|
||||||
AdSourceHealthDegraded,
|
|
||||||
AdSourceHealthUnhealthy,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdSourceHealthKeyValue struct {
|
|
||||||
Key AdSourceHealth
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
AdSourceHealthHealthyKeyValue = AdSourceHealthKeyValue{Key: AdSourceHealthHealthy, Value: "健康"}
|
|
||||||
AdSourceHealthDegradedKeyValue = AdSourceHealthKeyValue{Key: AdSourceHealthDegraded, Value: "降级"}
|
|
||||||
AdSourceHealthUnhealthyKeyValue = AdSourceHealthKeyValue{Key: AdSourceHealthUnhealthy, Value: "不健康"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllAdSourceHealthKeyValue() []AdSourceHealthKeyValue {
|
|
||||||
return []AdSourceHealthKeyValue{
|
|
||||||
AdSourceHealthHealthyKeyValue,
|
|
||||||
AdSourceHealthDegradedKeyValue,
|
|
||||||
AdSourceHealthUnhealthyKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var adSourceHealthValueMap = map[AdSourceHealth]string{
|
|
||||||
AdSourceHealthHealthy: AdSourceHealthHealthyKeyValue.Value,
|
|
||||||
AdSourceHealthDegraded: AdSourceHealthDegradedKeyValue.Value,
|
|
||||||
AdSourceHealthUnhealthy: AdSourceHealthUnhealthyKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAdSourceHealthValueByKey(key AdSourceHealth) (value string) {
|
|
||||||
value, exists := adSourceHealthValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知健康状态"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// AdSourceProvider 广告源提供商枚举
|
|
||||||
type AdSourceProvider string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AdSourceProviderGoogle AdSourceProvider = "google" // Google
|
|
||||||
AdSourceProviderBaidu AdSourceProvider = "baidu" // 百度
|
|
||||||
AdSourceProviderTencent AdSourceProvider = "tencent" // 腾讯
|
|
||||||
AdSourceProviderSelf AdSourceProvider = "self" // 自营
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllAdSourceProviders 获取所有广告源提供商
|
|
||||||
func GetAllAdSourceProviders() []AdSourceProvider {
|
|
||||||
return []AdSourceProvider{
|
|
||||||
AdSourceProviderGoogle,
|
|
||||||
AdSourceProviderBaidu,
|
|
||||||
AdSourceProviderTencent,
|
|
||||||
AdSourceProviderSelf,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdSourceProviderKeyValue struct {
|
|
||||||
Key AdSourceProvider
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
AdSourceProviderGoogleKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderGoogle, Value: "Google"}
|
|
||||||
AdSourceProviderBaiduKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderBaidu, Value: "百度"}
|
|
||||||
AdSourceProviderTencentKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderTencent, Value: "腾讯"}
|
|
||||||
AdSourceProviderSelfKeyValue = AdSourceProviderKeyValue{Key: AdSourceProviderSelf, Value: "自营"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllAdSourceProviderKeyValue() []AdSourceProviderKeyValue {
|
|
||||||
return []AdSourceProviderKeyValue{
|
|
||||||
AdSourceProviderGoogleKeyValue,
|
|
||||||
AdSourceProviderBaiduKeyValue,
|
|
||||||
AdSourceProviderTencentKeyValue,
|
|
||||||
AdSourceProviderSelfKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var adSourceProviderValueMap = map[AdSourceProvider]string{
|
|
||||||
AdSourceProviderGoogle: AdSourceProviderGoogleKeyValue.Value,
|
|
||||||
AdSourceProviderBaidu: AdSourceProviderBaiduKeyValue.Value,
|
|
||||||
AdSourceProviderTencent: AdSourceProviderTencentKeyValue.Value,
|
|
||||||
AdSourceProviderSelf: AdSourceProviderSelfKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAdSourceProviderValueByKey(key AdSourceProvider) (value string) {
|
|
||||||
value, exists := adSourceProviderValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知提供商"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// AdSourceStatus 广告源状态枚举
|
|
||||||
type AdSourceStatus string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AdSourceStatusActive AdSourceStatus = "active" // 活跃
|
|
||||||
AdSourceStatusInactive AdSourceStatus = "inactive" // 非活跃
|
|
||||||
AdSourceStatusMaintenance AdSourceStatus = "maintenance" // 维护中
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllAdSourceStatuses 获取所有广告源状态
|
|
||||||
func GetAllAdSourceStatuses() []AdSourceStatus {
|
|
||||||
return []AdSourceStatus{
|
|
||||||
AdSourceStatusActive,
|
|
||||||
AdSourceStatusInactive,
|
|
||||||
AdSourceStatusMaintenance,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdSourceStatusKeyValue struct {
|
|
||||||
Key AdSourceStatus
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
AdSourceStatusActiveKeyValue = AdSourceStatusKeyValue{Key: AdSourceStatusActive, Value: "活跃"}
|
|
||||||
AdSourceStatusInactiveKeyValue = AdSourceStatusKeyValue{Key: AdSourceStatusInactive, Value: "非活跃"}
|
|
||||||
AdSourceStatusMaintenanceKeyValue = AdSourceStatusKeyValue{Key: AdSourceStatusMaintenance, Value: "维护中"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllAdSourceStatusKeyValue() []AdSourceStatusKeyValue {
|
|
||||||
return []AdSourceStatusKeyValue{
|
|
||||||
AdSourceStatusActiveKeyValue,
|
|
||||||
AdSourceStatusInactiveKeyValue,
|
|
||||||
AdSourceStatusMaintenanceKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var adSourceStatusValueMap = map[AdSourceStatus]string{
|
|
||||||
AdSourceStatusActive: AdSourceStatusActiveKeyValue.Value,
|
|
||||||
AdSourceStatusInactive: AdSourceStatusInactiveKeyValue.Value,
|
|
||||||
AdSourceStatusMaintenance: AdSourceStatusMaintenanceKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAdSourceStatusValueByKey(key AdSourceStatus) (value string) {
|
|
||||||
value, exists := adSourceStatusValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知状态"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// AdSourceType 广告源类型枚举
|
|
||||||
type AdSourceType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AdSourceTypeSelf AdSourceType = "self" // 自营
|
|
||||||
AdSourceTypeThirdParty AdSourceType = "third_party" // 第三方
|
|
||||||
AdSourceTypeExchange AdSourceType = "exchange" // 广告交易平台
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllAdSourceTypes 获取所有广告源类型
|
|
||||||
func GetAllAdSourceTypes() []AdSourceType {
|
|
||||||
return []AdSourceType{
|
|
||||||
AdSourceTypeSelf,
|
|
||||||
AdSourceTypeThirdParty,
|
|
||||||
AdSourceTypeExchange,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdSourceTypeKeyValue struct {
|
|
||||||
Key AdSourceType
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
AdSourceTypeSelfKeyValue = AdSourceTypeKeyValue{Key: AdSourceTypeSelf, Value: "自营"}
|
|
||||||
AdSourceTypeThirdPartyKeyValue = AdSourceTypeKeyValue{Key: AdSourceTypeThirdParty, Value: "第三方"}
|
|
||||||
AdSourceTypeExchangeKeyValue = AdSourceTypeKeyValue{Key: AdSourceTypeExchange, Value: "广告交易平台"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllAdSourceTypeKeyValue() []AdSourceTypeKeyValue {
|
|
||||||
return []AdSourceTypeKeyValue{
|
|
||||||
AdSourceTypeSelfKeyValue,
|
|
||||||
AdSourceTypeThirdPartyKeyValue,
|
|
||||||
AdSourceTypeExchangeKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var adSourceTypeValueMap = map[AdSourceType]string{
|
|
||||||
AdSourceTypeSelf: AdSourceTypeSelfKeyValue.Value,
|
|
||||||
AdSourceTypeThirdParty: AdSourceTypeThirdPartyKeyValue.Value,
|
|
||||||
AdSourceTypeExchange: AdSourceTypeExchangeKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAdSourceTypeValueByKey(key AdSourceType) (value string) {
|
|
||||||
value, exists := adSourceTypeValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知类型"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// AuthType 认证类型枚举
|
|
||||||
type AuthType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
AuthTypeAPIKey AuthType = "api_key" // API密钥
|
|
||||||
AuthTypeOAuth AuthType = "oauth" // OAuth
|
|
||||||
AuthTypeBasic AuthType = "basic" // Basic认证
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllAuthTypes 获取所有认证类型
|
|
||||||
func GetAllAuthTypes() []AuthType {
|
|
||||||
return []AuthType{
|
|
||||||
AuthTypeAPIKey,
|
|
||||||
AuthTypeOAuth,
|
|
||||||
AuthTypeBasic,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuthTypeKeyValue struct {
|
|
||||||
Key AuthType
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
AuthTypeAPIKeyKeyValue = AuthTypeKeyValue{Key: AuthTypeAPIKey, Value: "API密钥"}
|
|
||||||
AuthTypeOAuthKeyValue = AuthTypeKeyValue{Key: AuthTypeOAuth, Value: "OAuth"}
|
|
||||||
AuthTypeBasicKeyValue = AuthTypeKeyValue{Key: AuthTypeBasic, Value: "Basic认证"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllAuthTypeKeyValue() []AuthTypeKeyValue {
|
|
||||||
return []AuthTypeKeyValue{
|
|
||||||
AuthTypeAPIKeyKeyValue,
|
|
||||||
AuthTypeOAuthKeyValue,
|
|
||||||
AuthTypeBasicKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var authTypeValueMap = map[AuthType]string{
|
|
||||||
AuthTypeAPIKey: AuthTypeAPIKeyKeyValue.Value,
|
|
||||||
AuthTypeOAuth: AuthTypeOAuthKeyValue.Value,
|
|
||||||
AuthTypeBasic: AuthTypeBasicKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAuthTypeValueByKey(key AuthType) (value string) {
|
|
||||||
value, exists := authTypeValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知认证类型"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// BiddingType 竞价类型枚举
|
|
||||||
type BiddingType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
BiddingTypeCPM BiddingType = "cpm" // 千次展示成本
|
|
||||||
BiddingTypeCPC BiddingType = "cpc" // 每次点击成本
|
|
||||||
BiddingTypeCPA BiddingType = "cpa" // 每次行动成本
|
|
||||||
BiddingTypeRTB BiddingType = "rtb" // 实时竞价
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllBiddingTypes 获取所有竞价类型
|
|
||||||
func GetAllBiddingTypes() []BiddingType {
|
|
||||||
return []BiddingType{
|
|
||||||
BiddingTypeCPM,
|
|
||||||
BiddingTypeCPC,
|
|
||||||
BiddingTypeCPA,
|
|
||||||
BiddingTypeRTB,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type BiddingTypeKeyValue struct {
|
|
||||||
Key BiddingType
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
BiddingTypeCPMKeyValue = BiddingTypeKeyValue{Key: BiddingTypeCPM, Value: "千次展示成本"}
|
|
||||||
BiddingTypeCPCKeypValue = BiddingTypeKeyValue{Key: BiddingTypeCPC, Value: "每次点击成本"}
|
|
||||||
BiddingTypeCPAKeyValue = BiddingTypeKeyValue{Key: BiddingTypeCPA, Value: "每次行动成本"}
|
|
||||||
BiddingTypeRTBKeyValue = BiddingTypeKeyValue{Key: BiddingTypeRTB, Value: "实时竞价"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllBiddingTypeKeyValue() []BiddingTypeKeyValue {
|
|
||||||
return []BiddingTypeKeyValue{
|
|
||||||
BiddingTypeCPMKeyValue,
|
|
||||||
BiddingTypeCPCKeypValue,
|
|
||||||
BiddingTypeCPAKeyValue,
|
|
||||||
BiddingTypeRTBKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var biddingTypeValueMap = map[BiddingType]string{
|
|
||||||
BiddingTypeCPM: BiddingTypeCPMKeyValue.Value,
|
|
||||||
BiddingTypeCPC: BiddingTypeCPCKeypValue.Value,
|
|
||||||
BiddingTypeCPA: BiddingTypeCPAKeyValue.Value,
|
|
||||||
BiddingTypeRTB: BiddingTypeRTBKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBiddingTypeValueByKey(key BiddingType) (value string) {
|
|
||||||
value, exists := biddingTypeValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知竞价类型"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// BillingModel 计费模式枚举
|
|
||||||
type BillingModel string
|
|
||||||
|
|
||||||
const (
|
|
||||||
BillingModelCPM BillingModel = "cpm" // 千次展示成本
|
|
||||||
BillingModelCPC BillingModel = "cpc" // 每次点击成本
|
|
||||||
BillingModelCPA BillingModel = "cpa" // 每次行动成本
|
|
||||||
BillingModelRevShare BillingModel = "rev_share" // 收入分成
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllBillingModels 获取所有计费模式
|
|
||||||
func GetAllBillingModels() []BillingModel {
|
|
||||||
return []BillingModel{
|
|
||||||
BillingModelCPM,
|
|
||||||
BillingModelCPC,
|
|
||||||
BillingModelCPA,
|
|
||||||
BillingModelRevShare,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type BillingModelKeyValue struct {
|
|
||||||
Key BillingModel
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
BillingModelCPMKeyValue = BillingModelKeyValue{Key: BillingModelCPM, Value: "千次展示成本"}
|
|
||||||
BillingModelCPCKeypValue = BillingModelKeyValue{Key: BillingModelCPC, Value: "每次点击成本"}
|
|
||||||
BillingModelCPAKeyValue = BillingModelKeyValue{Key: BillingModelCPA, Value: "每次行动成本"}
|
|
||||||
BillingModelRevShareKeyValue = BillingModelKeyValue{Key: BillingModelRevShare, Value: "收入分成"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllBillingModelKeyValue() []BillingModelKeyValue {
|
|
||||||
return []BillingModelKeyValue{
|
|
||||||
BillingModelCPMKeyValue,
|
|
||||||
BillingModelCPCKeypValue,
|
|
||||||
BillingModelCPAKeyValue,
|
|
||||||
BillingModelRevShareKeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var billingModelValueMap = map[BillingModel]string{
|
|
||||||
BillingModelCPM: BillingModelCPMKeyValue.Value,
|
|
||||||
BillingModelCPC: BillingModelCPCKeypValue.Value,
|
|
||||||
BillingModelCPA: BillingModelCPAKeyValue.Value,
|
|
||||||
BillingModelRevShare: BillingModelRevShareKeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBillingModelValueByKey(key BillingModel) (value string) {
|
|
||||||
value, exists := billingModelValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知计费模式"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
// 送检状态常量
|
||||||
|
const (
|
||||||
|
// SourceTable 来源表标识
|
||||||
|
SourceTableTencentImage = "tencent_image"
|
||||||
|
SourceTableTencentVideo = "tencent_video"
|
||||||
|
|
||||||
|
// CheckStatus 送检状态
|
||||||
|
CheckStatusPending = "PENDING" // 待送检
|
||||||
|
CheckStatusSubmitting = "SUBMITTING" // 送检中
|
||||||
|
CheckStatusSuccess = "SUCCESS" // 送检成功
|
||||||
|
CheckStatusFailed = "FAILED" // 送检失败
|
||||||
|
CheckStatusCompleted = "COMPLETED" // 检测完成
|
||||||
|
)
|
||||||
|
|
||||||
|
// Suggestion 处置建议
|
||||||
|
const (
|
||||||
|
SuggestionPass = 0 // 通过
|
||||||
|
SuggestionReview = 1 // 嫌疑,需人工审核
|
||||||
|
SuggestionBlock = 2 // 不通过
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
// PostgreSQL表名常量
|
||||||
|
const (
|
||||||
|
TencentImageTable = "tencent_image" // 图片送检表
|
||||||
|
TencentVideoTable = "tencent_video" // 视频送检表
|
||||||
|
TencentContentCheckLogTable = "tencent_content_check_log" // 送检日志表
|
||||||
|
TencentAccountRelationTable = "tencent_account_relation" // 腾讯广告账户关系表
|
||||||
|
)
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// MongoDB集合名称常量
|
|
||||||
const (
|
|
||||||
AdPositionCollection = "ad_position" // 广告位集合
|
|
||||||
AdSourceCollection = "ad_source" // 广告源集合
|
|
||||||
AdvertisementCollection = "advertisement" // 广告集合
|
|
||||||
AdvertiserCollection = "advertiser" // 广告主集合
|
|
||||||
ApplicationCollection = "application" // 应用集合
|
|
||||||
CidRequestCollection = "cid_request" // CID请求集合
|
|
||||||
StrategyCollection = "strategy" // 策略集合
|
|
||||||
AdCreativeCollection = "ad_creative" // 广告创意集合
|
|
||||||
AdPlatformCollection = "ad_platform" // 广告平台集合
|
|
||||||
AdTypeCollection = "ad_type" // 广告类型集合
|
|
||||||
AppPlatformConfigCollection = "app_platform_config" // 应用平台配置集合
|
|
||||||
PlatformDeliveryRuleCollection = "platform_delivery_rule" // 平台投放规则集合
|
|
||||||
TargetingCollection = "targeting" // 定向规则集合
|
|
||||||
)
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// 默认配置值
|
|
||||||
const (
|
|
||||||
DefaultTimeout = 5000 // 默认超时时间(毫秒)
|
|
||||||
DefaultRetryCount = 3 // 默认重试次数
|
|
||||||
DefaultPriority = 1 // 默认优先级
|
|
||||||
)
|
|
||||||
|
|
||||||
// 错误消息
|
|
||||||
const (
|
|
||||||
ErrAdSourceNotFound = "广告源不存在"
|
|
||||||
ErrAdSourceNameExists = "广告源名称已存在"
|
|
||||||
ErrAdSourceCodeExists = "广告源编码已存在"
|
|
||||||
ErrAdSourceInactive = "广告源非活跃状态"
|
|
||||||
ErrAdSourceUnhealthy = "广告源健康状态异常"
|
|
||||||
ErrRateLimitExceeded = "请求频率超限"
|
|
||||||
ErrInvalidConfiguration = "配置参数无效"
|
|
||||||
)
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// 注意:以下枚举常量已迁移到单独的枚举文件中,请使用新的枚举类型:
|
|
||||||
// - AdSourceStatus -> consts.AdSourceStatus (ad_source_status.go)
|
|
||||||
// - AdSourceHealth -> consts.AdSourceHealth (ad_source_health.go)
|
|
||||||
// - AdSourceType -> consts.AdSourceType (ad_source_type.go)
|
|
||||||
// - AdSourceProvider -> consts.AdSourceProvider (ad_source_provider.go)
|
|
||||||
// - AuthType -> consts.AuthType (auth_type.go)
|
|
||||||
// - BiddingType -> consts.BiddingType (bidding_type.go)
|
|
||||||
// - AdFormatType -> consts.AdFormatType (ad_format_type.go)
|
|
||||||
// - BillingModel -> consts.BillingModel (billing_model.go)
|
|
||||||
// - PaymentTerms -> consts.PaymentTerms (payment_terms.go)
|
|
||||||
|
|
||||||
// 配置值常量已迁移到 config.go 文件中
|
|
||||||
// 错误消息常量已迁移到 config.go 文件中
|
|
||||||
// MongoDB集合名称常量已迁移到 collections.go 文件中
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
// 广告管理错误码
|
|
||||||
const (
|
|
||||||
ErrAdNotFound = 1001 // 广告不存在
|
|
||||||
ErrAdStatusInvalid = 1002 // 广告状态无效
|
|
||||||
ErrAdAuditedRejected = 1003 // 广告审核被拒绝
|
|
||||||
ErrAdBudgetInsufficient = 1004 // 广告预算不足
|
|
||||||
)
|
|
||||||
|
|
||||||
// 广告主管理错误码
|
|
||||||
const (
|
|
||||||
ErrAdvertiserNotFound = 2001 // 广告主不存在
|
|
||||||
ErrAdvertiserStatusInvalid = 2002 // 广告主状态无效
|
|
||||||
ErrAdvertiserAuditedRejected = 2003 // 广告主审核被拒绝
|
|
||||||
ErrAdvertiserBalanceLow = 2004 // 广告主余额不足
|
|
||||||
ErrCreditLimitInvalid = 2005 // 授信额度无效
|
|
||||||
)
|
|
||||||
|
|
||||||
// 广告位管理错误码
|
|
||||||
const (
|
|
||||||
ErrAdPositionNotFound = 3001 // 广告位不存在
|
|
||||||
ErrAdPositionStatusInvalid = 3002 // 广告位状态无效
|
|
||||||
ErrAdPositionCodeExists = 3003 // 广告位编码已存在
|
|
||||||
ErrAdNotMatched = 3004 // 无匹配广告
|
|
||||||
)
|
|
||||||
|
|
||||||
// 报表管理错误码
|
|
||||||
const (
|
|
||||||
ErrReportNotFound = 4001 // 报表不存在
|
|
||||||
ErrReportNotGenerated = 4002 // 报表未生成
|
|
||||||
ErrReportExpired = 4003 // 报表已过期
|
|
||||||
ErrReportInvalidFormat = 4004 // 报表格式无效
|
|
||||||
)
|
|
||||||
|
|
||||||
// 配置验证错误
|
|
||||||
var (
|
|
||||||
ErrInvalidPriority = errors.New("优先级必须为非负数")
|
|
||||||
ErrInvalidWeight = errors.New("权重必须在0到1之间")
|
|
||||||
ErrInvalidBidAmount = errors.New("出价金额必须为非负数")
|
|
||||||
ErrInvalidBidRange = errors.New("最小出价不能大于最大出价")
|
|
||||||
ErrInvalidROAS = errors.New("ROAS必须为非负数")
|
|
||||||
ErrInvalidBudget = errors.New("预算金额必须为非负数")
|
|
||||||
ErrInvalidTimeRange = errors.New("开始时间不能大于结束时间")
|
|
||||||
ErrInvalidTimeout = errors.New("超时时间必须为正数")
|
|
||||||
ErrInvalidRetryCount = errors.New("重试次数必须为非负数")
|
|
||||||
ErrInvalidFileSize = errors.New("文件大小必须为正数")
|
|
||||||
ErrInvalidDuration = errors.New("时长必须为正数")
|
|
||||||
ErrInvalidRateLimit = errors.New("速率限制必须为正数")
|
|
||||||
ErrInvalidCommission = errors.New("佣金比例必须在0到1之间")
|
|
||||||
ErrInvalidRevShare = errors.New("收入分成比例必须在0到1之间")
|
|
||||||
ErrInvalidAge = errors.New("年龄必须为正数且最小年龄不能大于最大年龄")
|
|
||||||
ErrInvalidFrequency = errors.New("频次限制必须为非负数")
|
|
||||||
)
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
// PaymentTerms 支付条款枚举
|
|
||||||
type PaymentTerms string
|
|
||||||
|
|
||||||
const (
|
|
||||||
PaymentTermsNet30 PaymentTerms = "net_30" // 30天
|
|
||||||
PaymentTermsNet60 PaymentTerms = "net_60" // 60天
|
|
||||||
PaymentTermsNet90 PaymentTerms = "net_90" // 90天
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetAllPaymentTerms 获取所有支付条款
|
|
||||||
func GetAllPaymentTerms() []PaymentTerms {
|
|
||||||
return []PaymentTerms{
|
|
||||||
PaymentTermsNet30,
|
|
||||||
PaymentTermsNet60,
|
|
||||||
PaymentTermsNet90,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type PaymentTermsKeyValue struct {
|
|
||||||
Key PaymentTerms
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
PaymentTermsNet30KeyValue = PaymentTermsKeyValue{Key: PaymentTermsNet30, Value: "30天"}
|
|
||||||
PaymentTermsNet60KeyValue = PaymentTermsKeyValue{Key: PaymentTermsNet60, Value: "60天"}
|
|
||||||
PaymentTermsNet90KeyValue = PaymentTermsKeyValue{Key: PaymentTermsNet90, Value: "90天"}
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAllPaymentTermsKeyValue() []PaymentTermsKeyValue {
|
|
||||||
return []PaymentTermsKeyValue{
|
|
||||||
PaymentTermsNet30KeyValue,
|
|
||||||
PaymentTermsNet60KeyValue,
|
|
||||||
PaymentTermsNet90KeyValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var paymentTermsValueMap = map[PaymentTerms]string{
|
|
||||||
PaymentTermsNet30: PaymentTermsNet30KeyValue.Value,
|
|
||||||
PaymentTermsNet60: PaymentTermsNet60KeyValue.Value,
|
|
||||||
PaymentTermsNet90: PaymentTermsNet90KeyValue.Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetPaymentTermsValueByKey(key PaymentTerms) (value string) {
|
|
||||||
value, exists := paymentTermsValueMap[key]
|
|
||||||
if !exists {
|
|
||||||
value = "未知支付条款"
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package consts
|
|
||||||
|
|
||||||
const (
|
|
||||||
AdRequestLimitKeyPrefix = "ad_request_limit:" // 广告请求限流键前缀
|
|
||||||
RateLimitKeyPrefix = "rate_limit:" // 通用限流键前缀
|
|
||||||
SessionCacheKeyPrefix = "session_cache:" // 会话缓存键前缀
|
|
||||||
)
|
|
||||||
|
|
||||||
// 广告缓存键
|
|
||||||
const (
|
|
||||||
AdCacheKeyPrefix = "cid:ad:" // 广告缓存前缀
|
|
||||||
AdPositionCacheKeyPrefix = "cid:pos:" // 广告位缓存前缀
|
|
||||||
AdvertiserCacheKeyPrefix = "cid:adv:" // 广告主缓存前缀
|
|
||||||
)
|
|
||||||
|
|
||||||
// 广告匹配键
|
|
||||||
const (
|
|
||||||
AdMatchingKeyPrefix = "cid:match:" // 广告匹配键前缀
|
|
||||||
UserProfileKeyPrefix = "cid:user:" // 用户画像键前缀
|
|
||||||
)
|
|
||||||
|
|
||||||
// 限流键
|
|
||||||
const (
|
|
||||||
ApiRequestLimitKeyPrefix = "cid:limit:api:" // API请求限流键前缀
|
|
||||||
)
|
|
||||||
|
|
||||||
// Stream键
|
|
||||||
const (
|
|
||||||
AdEventStreamKey = "cid:stream:ad_event" // 广告事件流
|
|
||||||
UserBehaviorStreamKey = "cid:stream:user_behavior" // 用户行为流
|
|
||||||
)
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
type adPosition struct{}
|
|
||||||
|
|
||||||
var AdPosition = new(adPosition)
|
|
||||||
|
|
||||||
// Add 添加广告位
|
|
||||||
func (c *adPosition) Add(ctx context.Context, req *dto.AddAdPositionReq) (res *dto.AddAdPositionRes, err error) {
|
|
||||||
return service.AdPosition.Add(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告位
|
|
||||||
func (c *adPosition) Update(ctx context.Context, req *dto.UpdateAdPositionReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.AdPosition.Update(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus 更新广告位状态
|
|
||||||
func (c *adPosition) UpdateStatus(ctx context.Context, req *dto.UpdateAdPositionStatusReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.AdPosition.UpdateStatus(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取广告位详情
|
|
||||||
func (c *adPosition) GetOne(ctx context.Context, req *dto.GetAdPositionReq) (res *dto.GetAdPositionRes, err error) {
|
|
||||||
return service.AdPosition.GetOne(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告位列表
|
|
||||||
func (c *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (res *dto.ListAdPositionRes, err error) {
|
|
||||||
return service.AdPosition.List(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAvailableAdPositions 获取可用的广告位列表
|
|
||||||
func (c *adPosition) GetAvailableAdPositions(ctx context.Context, _ *dto.GetAvailableAdPositionsReq) (res *dto.GetAvailableAdPositionsRes, err error) {
|
|
||||||
list, err := service.AdPosition.GetAvailableAdPositions(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.GetAvailableAdPositionsRes{
|
|
||||||
List: list,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchAd 匹配广告
|
|
||||||
func (c *adPosition) MatchAd(ctx context.Context, req *dto.MatchAdReq) (res *dto.MatchAdRes, err error) {
|
|
||||||
ad, err := service.AdPosition.MatchAd(ctx, req.PositionCode, req.UserInfo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.MatchAdRes{
|
|
||||||
Advertisement: ad,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
var AdSource = new(adSource)
|
|
||||||
|
|
||||||
type adSource struct{}
|
|
||||||
|
|
||||||
// Create 创建广告源
|
|
||||||
func (c *adSource) Create(ctx context.Context, req *dto.CreateAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
|
||||||
id, err := service.AdSource.CreateAdSource(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
adSource, err := service.AdSource.GetAdSourceByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.GetAdSourceRes{
|
|
||||||
AdSource: adSource,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告源
|
|
||||||
func (c *adSource) Update(ctx context.Context, req *dto.UpdateAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
|
||||||
affected, err := service.AdSource.UpdateAdSource(ctx, req.Id, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if affected == 0 {
|
|
||||||
return nil, gerror.New("广告源更新失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
adSource, err := service.AdSource.GetAdSourceByID(ctx, req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.GetAdSourceRes{
|
|
||||||
AdSource: adSource,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete 删除广告源
|
|
||||||
func (c *adSource) Delete(ctx context.Context, req *dto.DeleteAdSourceReq) (res *dto.DeleteAdSourceRes, err error) {
|
|
||||||
affected, err := service.AdSource.DeleteAdSource(ctx, req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if affected == 0 {
|
|
||||||
return nil, gerror.New("广告源删除失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.DeleteAdSourceRes{
|
|
||||||
Success: true,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByID 根据ID获取广告源
|
|
||||||
func (c *adSource) GetByID(ctx context.Context, req *dto.GetAdSourceReq) (res *dto.GetAdSourceRes, err error) {
|
|
||||||
adSource, err := service.AdSource.GetAdSourceByID(ctx, req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if adSource == nil {
|
|
||||||
return nil, gerror.New("广告源不存在")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.GetAdSourceRes{
|
|
||||||
AdSource: adSource,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告源列表
|
|
||||||
func (c *adSource) List(ctx context.Context, req *dto.ListAdSourceReq) (res *dto.ListAdSourceRes, err error) {
|
|
||||||
adSources, err := service.AdSource.GetAvailableSources(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.ListAdSourceRes{
|
|
||||||
List: adSources,
|
|
||||||
Total: len(adSources),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
type advertisement struct{}
|
|
||||||
|
|
||||||
var Advertisement = new(advertisement)
|
|
||||||
|
|
||||||
// Add 添加广告
|
|
||||||
func (c *advertisement) Add(ctx context.Context, req *dto.AddAdvertisementReq) (res *dto.AddAdvertisementRes, err error) {
|
|
||||||
return service.Advertisement.Add(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告
|
|
||||||
func (c *advertisement) Update(ctx context.Context, req *dto.UpdateAdvertisementReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertisement.Update(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus 更新广告状态
|
|
||||||
func (c *advertisement) UpdateStatus(ctx context.Context, req *dto.UpdateAdStatusReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertisement.UpdateStatus(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audit 审核广告
|
|
||||||
func (c *advertisement) Audit(ctx context.Context, req *dto.AuditAdvertisementReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertisement.Audit(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取广告详情
|
|
||||||
func (c *advertisement) GetOne(ctx context.Context, req *dto.GetAdvertisementReq) (res *dto.GetAdvertisementRes, err error) {
|
|
||||||
return service.Advertisement.GetOne(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告列表
|
|
||||||
func (c *advertisement) List(ctx context.Context, req *dto.ListAdvertisementReq) (res *dto.ListAdvertisementRes, err error) {
|
|
||||||
return service.Advertisement.List(ctx, req)
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
type advertiser struct{}
|
|
||||||
|
|
||||||
var Advertiser = new(advertiser)
|
|
||||||
|
|
||||||
// Add 添加广告主
|
|
||||||
func (c *advertiser) Add(ctx context.Context, req *dto.AddAdvertiserReq) (res *dto.AddAdvertiserRes, err error) {
|
|
||||||
return service.Advertiser.Add(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告主
|
|
||||||
func (c *advertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertiser.Update(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus 更新广告主状态
|
|
||||||
func (c *advertiser) UpdateStatus(ctx context.Context, req *dto.UpdateAdvertiserStatusReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertiser.UpdateStatus(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audit 审核广告主
|
|
||||||
func (c *advertiser) Audit(ctx context.Context, req *dto.AuditAdvertiserReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertiser.Audit(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recharge 充值
|
|
||||||
func (c *advertiser) Recharge(ctx context.Context, req *dto.RechargeAdvertiserReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertiser.Recharge(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateCreditLimit 更新授信额度
|
|
||||||
func (c *advertiser) UpdateCreditLimit(ctx context.Context, req *dto.UpdateCreditLimitReq) (res *beans.ResponseEmpty, err error) {
|
|
||||||
err = service.Advertiser.UpdateCreditLimit(ctx, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取广告主详情
|
|
||||||
func (c *advertiser) GetOne(ctx context.Context, req *dto.GetAdvertiserReq) (res *dto.GetAdvertiserRes, err error) {
|
|
||||||
return service.Advertiser.GetOne(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告主列表
|
|
||||||
func (c *advertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (res *dto.ListAdvertiserRes, err error) {
|
|
||||||
return service.Advertiser.List(ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBalance 获取广告主余额
|
|
||||||
func (c *advertiser) GetBalance(ctx context.Context, req *dto.GetAdvertiserBalanceReq) (res *dto.GetAdvertiserBalanceRes, err error) {
|
|
||||||
balance, creditLimit, err := service.Advertiser.GetBalance(ctx, req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.GetAdvertiserBalanceRes{
|
|
||||||
Balance: balance,
|
|
||||||
CreditLimit: creditLimit,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Application = new(application)
|
|
||||||
|
|
||||||
type application struct{}
|
|
||||||
|
|
||||||
// CreateApplication 创建应用
|
|
||||||
func (c *application) CreateApplication(ctx context.Context, req *dto.CreateApplicationReq) (res *dto.CreateApplicationRes, err error) {
|
|
||||||
idStr, err := service.Application.CreateApplication(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将字符串ID转换为int64
|
|
||||||
id, _ := strconv.ParseInt(idStr, 10, 64)
|
|
||||||
|
|
||||||
return &dto.CreateApplicationRes{
|
|
||||||
ID: id,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateApplication 更新应用
|
|
||||||
func (c *application) UpdateApplication(ctx context.Context, req *dto.UpdateApplicationReq) (res *dto.UpdateApplicationRes, err error) {
|
|
||||||
affected, err := service.Application.UpdateApplication(ctx, strconv.FormatInt(req.ID, 10), req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.UpdateApplicationRes{
|
|
||||||
Success: affected > 0,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetApplication 获取应用信息
|
|
||||||
func (c *application) GetApplication(ctx context.Context, req *dto.GetApplicationReq) (res *dto.GetApplicationRes, err error) {
|
|
||||||
app, err := service.Application.GetApplicationByID(ctx, strconv.FormatInt(req.ID, 10))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
|
|
||||||
id, _ := strconv.ParseInt(app.Id.Hex(), 16, 64)
|
|
||||||
// Application实体中没有TenantId字段,暂时设为0
|
|
||||||
tenantID := int64(0)
|
|
||||||
|
|
||||||
return &dto.GetApplicationRes{
|
|
||||||
ID: id,
|
|
||||||
TenantID: tenantID,
|
|
||||||
Name: app.Name,
|
|
||||||
Code: app.Code,
|
|
||||||
Description: app.Description,
|
|
||||||
Platform: app.Platform,
|
|
||||||
PackageName: app.PackageName,
|
|
||||||
AppStoreURL: app.AppStoreURL,
|
|
||||||
Categories: app.Categories,
|
|
||||||
Tags: app.Tags,
|
|
||||||
AdTypes: app.AdTypes,
|
|
||||||
Status: app.Status,
|
|
||||||
AppKey: app.AppKey,
|
|
||||||
CallbackURL: app.CallbackURL,
|
|
||||||
CreatedAt: app.CreatedAt.Unix(),
|
|
||||||
UpdatedAt: app.UpdatedAt.Unix(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListApplications 获取应用列表
|
|
||||||
func (c *application) ListApplications(ctx context.Context, req *dto.ListApplicationsReq) (res *dto.ListApplicationsRes, err error) {
|
|
||||||
list, total, err := service.Application.GetApplicationsByTenant(ctx, strconv.FormatInt(req.TenantID, 10), req.Platform, req.Status, req.Page, req.Size)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转换为响应格式
|
|
||||||
appItems := make([]dto.ApplicationItem, len(list))
|
|
||||||
for i, app := range list {
|
|
||||||
id, _ := strconv.ParseInt(app.Id.Hex(), 16, 64)
|
|
||||||
appItems[i] = dto.ApplicationItem{
|
|
||||||
ID: id,
|
|
||||||
Name: app.Name,
|
|
||||||
Code: app.Code,
|
|
||||||
Description: app.Description,
|
|
||||||
Platform: app.Platform,
|
|
||||||
PackageName: app.PackageName,
|
|
||||||
Categories: app.Categories,
|
|
||||||
Tags: app.Tags,
|
|
||||||
AdTypes: app.AdTypes,
|
|
||||||
Status: app.Status,
|
|
||||||
DailyRequests: app.DailyRequests,
|
|
||||||
MonthlyRequests: app.MonthlyRequests,
|
|
||||||
CreatedAt: app.CreatedAt.Unix(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.ListApplicationsRes{
|
|
||||||
List: appItems,
|
|
||||||
Total: total,
|
|
||||||
Page: req.Page,
|
|
||||||
Size: req.Size,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetAPIKeys 重置API密钥
|
|
||||||
func (c *application) ResetAPIKeys(ctx context.Context, req *dto.ResetAPIKeysReq) (res *dto.ResetAPIKeysRes, err error) {
|
|
||||||
appKey, appSecret, err := service.Application.ResetAPIKeys(ctx, strconv.FormatInt(req.ID, 10))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.ResetAPIKeysRes{
|
|
||||||
AppKey: appKey,
|
|
||||||
AppSecret: appSecret,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateApplication 验证应用权限
|
|
||||||
func (c *application) ValidateApplication(ctx context.Context, req *dto.ValidateApplicationReq) (res *dto.ValidateApplicationRes, err error) {
|
|
||||||
app, err := service.Application.ValidateApplication(ctx, req.AppKey, req.AppSecret)
|
|
||||||
if err != nil {
|
|
||||||
return &dto.ValidateApplicationRes{
|
|
||||||
Valid: false,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将ObjectId的十六进制字符串转换为int64,如果失败则使用0
|
|
||||||
appID, _ := strconv.ParseInt(app.Id.Hex(), 16, 64)
|
|
||||||
// Application实体中没有TenantId字段,暂时设为0
|
|
||||||
tenantID := int64(0)
|
|
||||||
tentantName := ""
|
|
||||||
|
|
||||||
return &dto.ValidateApplicationRes{
|
|
||||||
Valid: true,
|
|
||||||
AppID: appID,
|
|
||||||
AppName: app.Name,
|
|
||||||
TenantID: tenantID,
|
|
||||||
TenantName: tentantName,
|
|
||||||
Platform: app.Platform,
|
|
||||||
AdTypes: app.AdTypes,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteApplication 删除应用
|
|
||||||
func (c *application) DeleteApplication(ctx context.Context, req *dto.DeleteApplicationReq) (res *dto.DeleteApplicationRes, err error) {
|
|
||||||
affected, err := service.Application.DeleteApplication(ctx, strconv.FormatInt(req.ID, 10))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.DeleteApplicationRes{
|
|
||||||
Success: affected > 0,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
dto "cid/model/dto/check"
|
||||||
|
check2 "cid/service/check"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContentCheckController 内容送检控制器
|
||||||
|
type ContentCheckController struct{}
|
||||||
|
|
||||||
|
// ContentCheck 内容送检控制器单例
|
||||||
|
var ContentCheck = new(ContentCheckController)
|
||||||
|
|
||||||
|
// StatusRes 状态响应
|
||||||
|
type StatusRes struct {
|
||||||
|
Running bool `json:"running"`
|
||||||
|
Config check2.ContentCheckConfig `json:"config"`
|
||||||
|
PendingStats map[string]int `json:"pending_stats"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start 启动送检服务
|
||||||
|
func (c *ContentCheckController) Start(ctx context.Context, req *dto.StartCheckReq) (res *beans.ResponseEmpty, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if check2.TencentContentCheck.IsRunning() {
|
||||||
|
return &beans.ResponseEmpty{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有配置参数,更新配置
|
||||||
|
if req.BatchSize > 0 || req.IntervalSeconds > 0 {
|
||||||
|
config := check2.ContentCheckConfig{
|
||||||
|
BatchSize: req.BatchSize,
|
||||||
|
ImageEnabled: req.ImageEnabled,
|
||||||
|
VideoEnabled: req.VideoEnabled,
|
||||||
|
IntervalSeconds: req.IntervalSeconds,
|
||||||
|
}
|
||||||
|
check2.TencentContentCheck.SetConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = check2.TencentContentCheck.Start(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &beans.ResponseEmpty{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop 停止送检服务
|
||||||
|
func (c *ContentCheckController) Stop(ctx context.Context, req *dto.EmptyReq) (res *beans.ResponseEmpty, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
check2.TencentContentCheck.Stop(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status 获取送检服务状态
|
||||||
|
func (c *ContentCheckController) Status(ctx context.Context, req *dto.EmptyReq) (res *StatusRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
res = &StatusRes{
|
||||||
|
Running: check2.TencentContentCheck.IsRunning(),
|
||||||
|
Config: check2.TencentContentCheck.GetConfig(),
|
||||||
|
PendingStats: check2.TencentContentCheck.GetPendingStats(ctx),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessImageCallback 处理图片检测回调
|
||||||
|
func (c *ContentCheckController) ProcessImageCallback(ctx context.Context, req *dto.ProcessImageCallbackReq) (res *beans.ResponseEmpty, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.CallbackData == "" {
|
||||||
|
return nil, fmt.Errorf("callbackData不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = check2.TencentContentCallback.ProcessImageCallback(ctx, req.CallbackData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessVideoCallback 处理视频检测回调
|
||||||
|
func (c *ContentCheckController) ProcessVideoCallback(ctx context.Context, req *dto.ProcessVideoCallbackReq) (res *beans.ResponseEmpty, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.CallbackData == "" {
|
||||||
|
return nil, fmt.Errorf("callbackData不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = check2.TencentContentCallback.ProcessVideoCallback(ctx, req.CallbackData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessImageResult 查询并处理图片检测结果(轮询模式)
|
||||||
|
func (c *ContentCheckController) ProcessImageResult(ctx context.Context, req *dto.ProcessImageResultReq) (res *beans.ResponseEmpty, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.TaskID == "" {
|
||||||
|
return nil, fmt.Errorf("taskId不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = check2.TencentContentCallback.ProcessImageResult(ctx, req.TaskID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessVideoResult 查询并处理视频检测结果(轮询模式)
|
||||||
|
func (c *ContentCheckController) ProcessVideoResult(ctx context.Context, req *dto.ProcessVideoResultReq) (res *beans.ResponseEmpty, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.TaskID == "" {
|
||||||
|
return nil, fmt.Errorf("taskId不能为空")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = check2.TencentContentCallback.ProcessVideoResult(ctx, req.TaskID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualSubmitImageByID 根据图片ID手动提交送检
|
||||||
|
func (c *ContentCheckController) ManualSubmitImageByID(ctx context.Context, req *dto.ManualSubmitImageByIDReq) (res *dto.ManualSubmitRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
result, err := check2.TencentContentCheck.SubmitImageByID(ctx, req.ImageID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &dto.ManualSubmitRes{
|
||||||
|
TaskID: result.TaskID,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualSubmitVideoByID 根据视频ID手动提交送检
|
||||||
|
func (c *ContentCheckController) ManualSubmitVideoByID(ctx context.Context, req *dto.ManualSubmitVideoByIDReq) (res *dto.ManualSubmitRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
result, err := check2.TencentContentCheck.SubmitVideoByID(ctx, req.VideoID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &dto.ManualSubmitRes{
|
||||||
|
TaskID: result.TaskID,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetImageCheckLogs 获取图片的送检日志
|
||||||
|
func (c *ContentCheckController) GetImageCheckLogs(ctx context.Context, req *dto.GetImageCheckLogsReq) (res *dto.GetCheckLogsRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
logs, err := check2.TencentContentCallback.GetCheckLogsByImageID(ctx, req.ImageID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &dto.GetCheckLogsRes{
|
||||||
|
List: logs,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVideoCheckLogs 获取视频的送检日志
|
||||||
|
func (c *ContentCheckController) GetVideoCheckLogs(ctx context.Context, req *dto.GetVideoCheckLogsReq) (res *dto.GetCheckLogsRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
logs, err := check2.TencentContentCallback.GetCheckLogsByVideoID(ctx, req.VideoID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = &dto.GetCheckLogsRes{
|
||||||
|
List: logs,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,634 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
consts "cid/consts/check"
|
||||||
|
dao "cid/dao/check"
|
||||||
|
entity "cid/model/entity/check"
|
||||||
|
serviceDataengine "cid/service/check"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaterialVerifyController 素材校验控制器
|
||||||
|
type MaterialVerifyController struct{}
|
||||||
|
|
||||||
|
// MaterialVerify 控制器单例
|
||||||
|
var MaterialVerify = new(MaterialVerifyController)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 请求/响应结构体
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ImageListReq 图片列表请求
|
||||||
|
type ImageListReq struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
AccountID int64 `json:"accountId"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"pageSize"`
|
||||||
|
StartTime int64 `json:"startTime"`
|
||||||
|
EndTime int64 `json:"endTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageListRes 图片列表响应
|
||||||
|
type ImageListRes struct {
|
||||||
|
List interface{} `json:"list"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsRes 统计响应
|
||||||
|
type StatsRes struct {
|
||||||
|
Pending int `json:"pending"`
|
||||||
|
Verified int `json:"verified"`
|
||||||
|
Rejected int `json:"rejected"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoListReq 视频列表请求
|
||||||
|
type VideoListReq struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
AccountID int64 `json:"accountId"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"pageSize"`
|
||||||
|
StartTime int64 `json:"startTime"`
|
||||||
|
EndTime int64 `json:"endTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoListRes 视频列表响应
|
||||||
|
type VideoListRes struct {
|
||||||
|
List interface{} `json:"list"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogListReq 日志列表请求
|
||||||
|
type LogListReq struct {
|
||||||
|
MaterialType string `json:"materialType"`
|
||||||
|
MaterialID string `json:"materialId"`
|
||||||
|
VerifyStatus string `json:"verifyStatus"`
|
||||||
|
AccountID int64 `json:"accountId"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PageSize int `json:"pageSize"`
|
||||||
|
StartTime int64 `json:"startTime"`
|
||||||
|
EndTime int64 `json:"endTime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualVerifyReq 手动校验请求
|
||||||
|
type ManualVerifyReq struct {
|
||||||
|
MaterialID string `json:"materialId" v:"required#素材ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TaskIDReq 任务ID请求
|
||||||
|
type TaskIDReq struct {
|
||||||
|
TaskID string `json:"taskId" v:"required#任务ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageCallbackReq 图片回调请求
|
||||||
|
type ImageCallbackReq struct {
|
||||||
|
CallbackData string `json:"callbackData"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoCallbackReq 视频回调请求
|
||||||
|
type VideoCallbackReq struct {
|
||||||
|
CallbackData string `json:"callbackData"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchVerifyReq 批量校验请求
|
||||||
|
type BatchVerifyReq struct {
|
||||||
|
Limit int `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 图片素材接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ListImage 图片素材列表
|
||||||
|
func (c *MaterialVerifyController) ListImage(ctx context.Context, req *ImageListReq) (res *ImageListRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.Page == 0 {
|
||||||
|
req.Page = 1
|
||||||
|
}
|
||||||
|
if req.PageSize == 0 {
|
||||||
|
req.PageSize = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
condition := make(map[string]interface{})
|
||||||
|
if req.Status != "" {
|
||||||
|
condition[entity.TencentImageCols.VerifyStatus] = req.Status
|
||||||
|
}
|
||||||
|
if req.AccountID > 0 {
|
||||||
|
condition[entity.TencentImageCols.AccountID] = req.AccountID
|
||||||
|
}
|
||||||
|
|
||||||
|
data, total, err := dao.TencentImage.GetByCondition(ctx, condition, req.Page, req.PageSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ImageListRes{
|
||||||
|
List: data,
|
||||||
|
Total: total,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsImage 图片素材统计
|
||||||
|
func (c *MaterialVerifyController) StatsImage(ctx context.Context, req *ImageListReq) (res *StatsRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
// 使用实体中定义的正确状态值:PENDING=待校验, VERIFIED=校验通过, REJECTED=校验不通过
|
||||||
|
pending, err := dao.TencentImage.CountByStatus(ctx, entity.VerifyStatusPending)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计待校验图片数量失败: %v", err)
|
||||||
|
}
|
||||||
|
verified, err := dao.TencentImage.CountByStatus(ctx, entity.VerifyStatusVerified)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计已通过图片数量失败: %v", err)
|
||||||
|
}
|
||||||
|
rejected, err := dao.TencentImage.CountByStatus(ctx, entity.VerifyStatusRejected)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计不通过图片数量失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StatsRes{
|
||||||
|
Pending: pending,
|
||||||
|
Verified: verified,
|
||||||
|
Rejected: rejected,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 视频素材接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ListVideo 视频素材列表
|
||||||
|
func (c *MaterialVerifyController) ListVideo(ctx context.Context, req *VideoListReq) (res *VideoListRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.Page == 0 {
|
||||||
|
req.Page = 1
|
||||||
|
}
|
||||||
|
if req.PageSize == 0 {
|
||||||
|
req.PageSize = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
condition := make(map[string]interface{})
|
||||||
|
if req.Status != "" {
|
||||||
|
condition[entity.TencentVideoCols.VerifyStatus] = req.Status
|
||||||
|
}
|
||||||
|
if req.AccountID > 0 {
|
||||||
|
condition[entity.TencentVideoCols.AccountID] = req.AccountID
|
||||||
|
}
|
||||||
|
|
||||||
|
data, total, err := dao.TencentVideo.GetByCondition(ctx, condition, req.Page, req.PageSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &VideoListRes{
|
||||||
|
List: data,
|
||||||
|
Total: total,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsVideo 视频素材统计
|
||||||
|
func (c *MaterialVerifyController) StatsVideo(ctx context.Context, req *VideoListReq) (res *StatsRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
// 使用实体中定义的正确状态值:PENDING=待校验, VERIFIED=校验通过, REJECTED=校验不通过
|
||||||
|
pending, err := dao.TencentVideo.CountByStatus(ctx, entity.VerifyStatusPending)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计待校验视频数量失败: %v", err)
|
||||||
|
}
|
||||||
|
verified, err := dao.TencentVideo.CountByStatus(ctx, entity.VerifyStatusVerified)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计已通过视频数量失败: %v", err)
|
||||||
|
}
|
||||||
|
rejected, err := dao.TencentVideo.CountByStatus(ctx, entity.VerifyStatusRejected)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计不通过视频数量失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StatsRes{
|
||||||
|
Pending: pending,
|
||||||
|
Verified: verified,
|
||||||
|
Rejected: rejected,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 校验日志接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ListLogRes 日志列表响应
|
||||||
|
type ListLogRes struct {
|
||||||
|
List interface{} `json:"list"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListLog 日志列表
|
||||||
|
func (c *MaterialVerifyController) ListLog(ctx context.Context, req *LogListReq) (res *ListLogRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.Page == 0 {
|
||||||
|
req.Page = 1
|
||||||
|
}
|
||||||
|
if req.PageSize == 0 {
|
||||||
|
req.PageSize = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
condition := make(map[string]interface{})
|
||||||
|
if req.MaterialType != "" {
|
||||||
|
condition[entity.MaterialVerifyLogCols.MaterialType] = req.MaterialType
|
||||||
|
}
|
||||||
|
if req.MaterialID != "" {
|
||||||
|
condition[entity.MaterialVerifyLogCols.MaterialID] = req.MaterialID
|
||||||
|
}
|
||||||
|
if req.VerifyStatus != "" {
|
||||||
|
condition[entity.MaterialVerifyLogCols.VerifyStatus] = req.VerifyStatus
|
||||||
|
}
|
||||||
|
if req.AccountID > 0 {
|
||||||
|
condition[entity.MaterialVerifyLogCols.AccountID] = req.AccountID
|
||||||
|
}
|
||||||
|
|
||||||
|
data, total, err := serviceDataengine.MaterialVerify.GetLogsByCondition(ctx, condition, req.Page, req.PageSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ListLogRes{
|
||||||
|
List: data,
|
||||||
|
Total: total,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogDetailRes 日志详情响应
|
||||||
|
type LogDetailRes struct {
|
||||||
|
*entity.MaterialVerifyLog
|
||||||
|
PreviewURL string `json:"previewURL"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogDetailReq 日志详情请求
|
||||||
|
type GetLogDetailReq struct {
|
||||||
|
Id int64 `json:"id" v:"required#日志ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogDetail 日志详情
|
||||||
|
func (c *MaterialVerifyController) GetLogDetail(ctx context.Context, req *GetLogDetailReq) (res *LogDetailRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
log, err := serviceDataengine.MaterialVerify.GetLogByID(ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if log == nil {
|
||||||
|
return nil, fmt.Errorf("日志不存在")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取来源数据预览
|
||||||
|
res = &LogDetailRes{
|
||||||
|
MaterialVerifyLog: log,
|
||||||
|
}
|
||||||
|
if log.SourceTable == consts.SourceTableTencentImage {
|
||||||
|
image, _ := dao.TencentImage.GetByID(ctx, log.SourceID)
|
||||||
|
if image != nil {
|
||||||
|
res.PreviewURL = image.PreviewURL
|
||||||
|
}
|
||||||
|
} else if log.SourceTable == consts.SourceTableTencentVideo {
|
||||||
|
video, _ := dao.TencentVideo.GetByID(ctx, log.SourceID)
|
||||||
|
if video != nil {
|
||||||
|
res.PreviewURL = video.PreviewURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsLogRes 日志统计响应
|
||||||
|
type StatsLogRes struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
Pending int `json:"pending"`
|
||||||
|
Verified int `json:"verified"`
|
||||||
|
Rejected int `json:"rejected"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatsLog 日志统计
|
||||||
|
func (c *MaterialVerifyController) StatsLog(ctx context.Context, req *LogListReq) (res *StatsLogRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
stats, err := serviceDataengine.MaterialVerify.GetStats(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &StatsLogRes{
|
||||||
|
Total: stats["total"],
|
||||||
|
Pending: stats["pending"],
|
||||||
|
Verified: stats["verified"],
|
||||||
|
Rejected: stats["rejected"],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 手动校验接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ManualVerifyImageRes 手动校验响应
|
||||||
|
type ManualVerifyImageRes struct {
|
||||||
|
Id int64 `json:"id"`
|
||||||
|
TaskID string `json:"taskId"`
|
||||||
|
SourceID string `json:"sourceId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualVerifyImage 手动校验图片
|
||||||
|
func (c *MaterialVerifyController) ManualVerifyImage(ctx context.Context, req *ManualVerifyReq) (res *ManualVerifyImageRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
log, err := serviceDataengine.MaterialVerify.VerifyImageByID(ctx, req.MaterialID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ManualVerifyImageRes{
|
||||||
|
Id: log.Id,
|
||||||
|
TaskID: log.TaskID,
|
||||||
|
SourceID: fmt.Sprintf("%d", log.SourceID),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualVerifyVideo 手动校验视频
|
||||||
|
func (c *MaterialVerifyController) ManualVerifyVideo(ctx context.Context, req *ManualVerifyReq) (res *ManualVerifyImageRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
log, err := serviceDataengine.MaterialVerify.VerifyVideoByID(ctx, req.MaterialID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ManualVerifyImageRes{
|
||||||
|
Id: log.Id,
|
||||||
|
TaskID: log.TaskID,
|
||||||
|
SourceID: fmt.Sprintf("%d", log.SourceID),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 批量校验接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// BatchVerifyRes 批量校验响应
|
||||||
|
type BatchVerifyRes struct {
|
||||||
|
Success int `json:"success"`
|
||||||
|
Fail int `json:"fail"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchVerifyImage 批量校验图片
|
||||||
|
func (c *MaterialVerifyController) BatchVerifyImage(ctx context.Context, req *BatchVerifyReq) (res *BatchVerifyRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.Limit <= 0 {
|
||||||
|
req.Limit = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
images, err := dao.TencentImage.GetPendingList(ctx, req.Limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
successCount := 0
|
||||||
|
failCount := 0
|
||||||
|
|
||||||
|
for _, image := range images {
|
||||||
|
_, err := serviceDataengine.MaterialVerify.VerifyImageByID(ctx, image.ImageID)
|
||||||
|
if err != nil {
|
||||||
|
failCount++
|
||||||
|
g.Log().Errorf(ctx, "图片校验失败: %s, error: %v", image.ImageID, err)
|
||||||
|
} else {
|
||||||
|
successCount++
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &BatchVerifyRes{
|
||||||
|
Success: successCount,
|
||||||
|
Fail: failCount,
|
||||||
|
Total: len(images),
|
||||||
|
Message: fmt.Sprintf("批量提交完成,成功: %d,失败: %d。请通过轮询接口获取检测结果", successCount, failCount),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BatchVerifyVideo 批量校验视频
|
||||||
|
func (c *MaterialVerifyController) BatchVerifyVideo(ctx context.Context, req *BatchVerifyReq) (res *BatchVerifyRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
if req.Limit <= 0 {
|
||||||
|
req.Limit = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
videos, err := dao.TencentVideo.GetPendingList(ctx, req.Limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
successCount := 0
|
||||||
|
failCount := 0
|
||||||
|
|
||||||
|
for _, video := range videos {
|
||||||
|
_, err := serviceDataengine.MaterialVerify.VerifyVideoByID(ctx, video.VideoID)
|
||||||
|
if err != nil {
|
||||||
|
failCount++
|
||||||
|
g.Log().Errorf(ctx, "视频校验失败: %s, error: %v", video.VideoID, err)
|
||||||
|
} else {
|
||||||
|
successCount++
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &BatchVerifyRes{
|
||||||
|
Success: successCount,
|
||||||
|
Fail: failCount,
|
||||||
|
Total: len(videos),
|
||||||
|
Message: fmt.Sprintf("批量提交完成,成功: %d,失败: %d。请通过轮询接口获取检测结果", successCount, failCount),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 账户列表接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ListAccountsReq 账户列表请求
|
||||||
|
type ListAccountsReq struct{}
|
||||||
|
|
||||||
|
// AccountItem 账户列表项
|
||||||
|
type AccountItem struct {
|
||||||
|
AccountID int64 `json:"accountId"`
|
||||||
|
CorporationName string `json:"corporationName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAccountsRes 账户列表响应
|
||||||
|
type ListAccountsRes struct {
|
||||||
|
List []AccountItem `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAccounts 获取所有启用的广告账户列表(用于前端下拉筛选)
|
||||||
|
func (c *MaterialVerifyController) ListAccounts(ctx context.Context, req *ListAccountsReq) (res *ListAccountsRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
accounts, err := dao.TencentAccountRelation.GetAll(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []AccountItem
|
||||||
|
for _, acc := range accounts {
|
||||||
|
items = append(items, AccountItem{
|
||||||
|
AccountID: acc.AccountID,
|
||||||
|
CorporationName: acc.CorporationName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ListAccountsRes{
|
||||||
|
List: items,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 导出接口 - 不通过数据
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ExportRejectedReq 导出不通过数据请求
|
||||||
|
type ExportRejectedReq struct {
|
||||||
|
MaterialType string `json:"materialType"` // IMAGE/VIDEO,为空则导出全部
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportRejectedItem 导出的不通过数据项
|
||||||
|
type ExportRejectedItem struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
MaterialID string `json:"materialId"`
|
||||||
|
AccountID int64 `json:"accountId"`
|
||||||
|
CorporationName string `json:"corporationName"`
|
||||||
|
PreviewURL string `json:"previewUrl"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
ErrorMsg string `json:"errorMsg"`
|
||||||
|
MaterialType string `json:"materialType"`
|
||||||
|
ImageUsage string `json:"imageUsage,omitempty"`
|
||||||
|
CreatedAt string `json:"createdAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportRejectedRes 导出不通过数据响应
|
||||||
|
type ExportRejectedRes struct {
|
||||||
|
Items []ExportRejectedItem `json:"items"`
|
||||||
|
Total int `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportRejected 导出不通过的图片/视频数据(含失败原因)
|
||||||
|
func (c *MaterialVerifyController) ExportRejected(ctx context.Context, req *ExportRejectedReq) (res *ExportRejectedRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
items, err := serviceDataengine.MaterialVerify.ExportRejectedData(ctx, req.MaterialType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为响应结构
|
||||||
|
var respItems []ExportRejectedItem
|
||||||
|
for _, item := range items {
|
||||||
|
respItems = append(respItems, ExportRejectedItem{
|
||||||
|
ID: item.ID,
|
||||||
|
MaterialID: item.MaterialID,
|
||||||
|
AccountID: item.AccountID,
|
||||||
|
CorporationName: item.CorporationName,
|
||||||
|
PreviewURL: item.PreviewURL,
|
||||||
|
Description: item.Description,
|
||||||
|
ErrorMsg: item.ErrorMsg,
|
||||||
|
MaterialType: item.MaterialType,
|
||||||
|
ImageUsage: item.ImageUsage,
|
||||||
|
CreatedAt: item.CreatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ExportRejectedRes{
|
||||||
|
Items: respItems,
|
||||||
|
Total: len(respItems),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 回调处理接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// CallbackRes 回调响应
|
||||||
|
type CallbackRes struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageCallback 图片校验回调
|
||||||
|
func (c *MaterialVerifyController) ImageCallback(ctx context.Context, req *ImageCallbackReq) (res *CallbackRes, err error) {
|
||||||
|
if !CheckCallbackIP(ctx) {
|
||||||
|
return &CallbackRes{Code: 403, Msg: "IP not allowed"}, nil
|
||||||
|
}
|
||||||
|
ctx = WithCallbackUser(ctx)
|
||||||
|
if req.CallbackData == "" {
|
||||||
|
return &CallbackRes{Code: 400, Msg: "callbackData不能为空"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = serviceDataengine.MaterialVerify.ProcessImageCallback(ctx, req.CallbackData)
|
||||||
|
if err != nil {
|
||||||
|
return &CallbackRes{Code: 500, Msg: err.Error()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CallbackRes{Code: 0, Msg: "处理成功"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoCallback 视频校验回调
|
||||||
|
func (c *MaterialVerifyController) VideoCallback(ctx context.Context, req *VideoCallbackReq) (res *CallbackRes, err error) {
|
||||||
|
if !CheckCallbackIP(ctx) {
|
||||||
|
return &CallbackRes{Code: 403, Msg: "IP not allowed"}, nil
|
||||||
|
}
|
||||||
|
ctx = WithCallbackUser(ctx)
|
||||||
|
if req.CallbackData == "" {
|
||||||
|
return &CallbackRes{Code: 400, Msg: "callbackData不能为空"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = serviceDataengine.MaterialVerify.ProcessVideoCallback(ctx, req.CallbackData)
|
||||||
|
if err != nil {
|
||||||
|
return &CallbackRes{Code: 500, Msg: err.Error()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &CallbackRes{Code: 0, Msg: "处理成功"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultRes 结果查询响应
|
||||||
|
type ResultRes struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageResult 图片校验结果查询(轮询模式)
|
||||||
|
func (c *MaterialVerifyController) ImageResult(ctx context.Context, req *TaskIDReq) (res *ResultRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
if req.TaskID == "" {
|
||||||
|
return &ResultRes{Code: 400, Msg: "taskId不能为空"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = serviceDataengine.MaterialVerify.ProcessImageResultByTask(ctx, req.TaskID)
|
||||||
|
if err != nil {
|
||||||
|
return &ResultRes{Code: 500, Msg: err.Error()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ResultRes{Code: 0, Msg: "处理成功"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoResult 视频校验结果查询(轮询模式)
|
||||||
|
func (c *MaterialVerifyController) VideoResult(ctx context.Context, req *TaskIDReq) (res *ResultRes, err error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
if req.TaskID == "" {
|
||||||
|
return &ResultRes{Code: 400, Msg: "taskId不能为空"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = serviceDataengine.MaterialVerify.ProcessVideoResultByTask(ctx, req.TaskID)
|
||||||
|
if err != nil {
|
||||||
|
return &ResultRes{Code: 500, Msg: err.Error()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ResultRes{Code: 0, Msg: "处理成功"}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Package internal 提供 controller 层的共享工具函数
|
||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WithAdminUser 在 context 中注入 admin 用户信息
|
||||||
|
func WithAdminUser(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, "user", &beans.User{UserName: "admin", TenantId: 1})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithCallbackUser 在 context 中注入 yidun_callback 用户信息
|
||||||
|
func WithCallbackUser(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, "user", &beans.User{UserName: "yidun_callback", TenantId: 1})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckCallbackIP 校验回调请求 IP 是否在白名单内
|
||||||
|
// 读取配置 check.callback_allowed_ips,若未配置则跳过校验
|
||||||
|
func CheckCallbackIP(ctx context.Context) bool {
|
||||||
|
r := ghttp.RequestFromCtx(ctx)
|
||||||
|
if r == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
allowedIPs := g.Cfg().MustGet(ctx, "check.callback_allowed_ips", "").String()
|
||||||
|
if allowedIPs == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
clientIP := r.GetClientIp()
|
||||||
|
for _, ip := range strings.Split(allowedIPs, ",") {
|
||||||
|
if strings.TrimSpace(ip) == clientIP {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.Log().Warningf(ctx, "回调IP不在白名单中, clientIP=%s, allowedIPs=%s", clientIP, allowedIPs)
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,382 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
dataengineService "cid/service/check"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// YidunCallbackController 易盾回调控制器
|
||||||
|
// 用于接收易盾检测结果的主动推送或手动轮询查询
|
||||||
|
type YidunCallbackController struct{}
|
||||||
|
|
||||||
|
// YidunCallback 易盾回调控制器单例
|
||||||
|
var YidunCallback = new(YidunCallbackController)
|
||||||
|
|
||||||
|
// CallbackResult 通用回调响应
|
||||||
|
type CallbackResult struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Data interface{} `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PollResult 轮询结果
|
||||||
|
type PollResult struct {
|
||||||
|
SuccessCount int `json:"success_count"`
|
||||||
|
FailCount int `json:"fail_count"`
|
||||||
|
PendingCount int `json:"pending_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 易盾主动推送模式回调接口
|
||||||
|
// 易盾会在检测完成后主动 POST 数据到这些接口
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ReceiveImageCallback 接收易盾图片检测结果推送
|
||||||
|
// 易盾回调格式: POST /check/callback/receiveImage
|
||||||
|
// Body: callbackData={"antispam":{...}}
|
||||||
|
func (c *YidunCallbackController) ReceiveImageCallback(r *ghttp.Request) {
|
||||||
|
// IP 白名单校验
|
||||||
|
if !CheckCallbackIP(r.Context()) {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 403, Msg: "IP not allowed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithCallbackUser(ctx)
|
||||||
|
|
||||||
|
// 易盾推送的数据在请求体中
|
||||||
|
var callbackData string
|
||||||
|
|
||||||
|
// 尝试从表单数据获取
|
||||||
|
callbackData = r.GetForm("callbackData", "").String()
|
||||||
|
if callbackData == "" {
|
||||||
|
// 尝试从请求体JSON获取
|
||||||
|
var reqBody map[string]interface{}
|
||||||
|
if err := r.Parse(&reqBody); err == nil {
|
||||||
|
if v, ok := reqBody["callbackData"]; ok {
|
||||||
|
callbackData = toString(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试直接从请求体获取原始数据
|
||||||
|
if callbackData == "" {
|
||||||
|
callbackData = string(r.GetBody())
|
||||||
|
}
|
||||||
|
|
||||||
|
if callbackData == "" {
|
||||||
|
g.Log().Warningf(ctx, "图片回调数据为空")
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 400, Msg: "callbackData不能为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Log().Infof(ctx, "收到易盾图片回调, data长度: %d", len(callbackData))
|
||||||
|
|
||||||
|
// 处理回调 - 更新 material_verify_log 和 tencent_image 表
|
||||||
|
err := dataengineService.MaterialVerify.ProcessImageCallback(ctx, callbackData)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "处理易盾图片回调失败: %v", err)
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 0, Msg: "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReceiveVideoCallback 接收易盾视频检测结果推送
|
||||||
|
// 易盾回调格式: POST /check/callback/receiveVideo
|
||||||
|
// Body: callbackData={"antispam":{...}}
|
||||||
|
func (c *YidunCallbackController) ReceiveVideoCallback(r *ghttp.Request) {
|
||||||
|
// IP 白名单校验
|
||||||
|
if !CheckCallbackIP(r.Context()) {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 403, Msg: "IP not allowed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithCallbackUser(ctx)
|
||||||
|
|
||||||
|
// 易盾推送的数据在请求体中
|
||||||
|
var callbackData string
|
||||||
|
|
||||||
|
// 尝试从表单数据获取
|
||||||
|
callbackData = r.GetForm("callbackData", "").String()
|
||||||
|
if callbackData == "" {
|
||||||
|
// 尝试从请求体JSON获取
|
||||||
|
var reqBody map[string]interface{}
|
||||||
|
if err := r.Parse(&reqBody); err == nil {
|
||||||
|
if v, ok := reqBody["callbackData"]; ok {
|
||||||
|
callbackData = toString(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试直接从请求体获取原始数据
|
||||||
|
if callbackData == "" {
|
||||||
|
callbackData = string(r.GetBody())
|
||||||
|
}
|
||||||
|
|
||||||
|
if callbackData == "" {
|
||||||
|
g.Log().Warningf(ctx, "视频回调数据为空")
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 400, Msg: "callbackData不能为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Log().Infof(ctx, "收到易盾视频回调, data长度: %d", len(callbackData))
|
||||||
|
|
||||||
|
// 处理回调 - 更新 material_verify_log 和 tencent_video 表
|
||||||
|
err := dataengineService.MaterialVerify.ProcessVideoCallback(ctx, callbackData)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "处理易盾视频回调失败: %v", err)
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 0, Msg: "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 轮询模式 - 手动查询检测结果
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// PollAllResults 轮询所有待查询的检测结果(图片+视频)
|
||||||
|
// 格式: POST /check/callback/poll
|
||||||
|
func (c *YidunCallbackController) PollAllResults(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
g.Log().Info(ctx, "开始轮询所有待查询的检测结果...")
|
||||||
|
|
||||||
|
// 先获取待处理数量
|
||||||
|
|
||||||
|
// 执行轮询
|
||||||
|
successCount, failCount, err := dataengineService.MaterialVerify.PollPendingResults(ctx)
|
||||||
|
|
||||||
|
// 轮询后再查一下剩余待处理的明细
|
||||||
|
pendingItems, _ := dataengineService.MaterialVerify.GetPendingResultsDetail(ctx, 50)
|
||||||
|
|
||||||
|
msg := fmt.Sprintf("✅ 成功处理 %d 条 | ❌ 失败 %d 条 | ⏳ 还剩 %d 条待处理",
|
||||||
|
successCount, failCount, len(pendingItems))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{
|
||||||
|
Code: 500,
|
||||||
|
Msg: fmt.Sprintf("部分完成,但有错误: %v", err),
|
||||||
|
Data: g.Map{
|
||||||
|
"summary": g.Map{"success": successCount, "fail": failCount, "pending": len(pendingItems)},
|
||||||
|
"pending_detail": pendingItems,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{
|
||||||
|
Code: 0,
|
||||||
|
Msg: msg,
|
||||||
|
Data: g.Map{
|
||||||
|
"summary": g.Map{"success": successCount, "fail": failCount, "pending": len(pendingItems)},
|
||||||
|
"pending_detail": pendingItems,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PollImageResults 轮询图片待查询的检测结果
|
||||||
|
// 格式: POST /check/callback/pollImage
|
||||||
|
func (c *YidunCallbackController) PollImageResults(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
g.Log().Info(ctx, "开始轮询图片待查询的检测结果...")
|
||||||
|
|
||||||
|
successCount, failCount, err := dataengineService.MaterialVerify.PollPendingImageResults(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{
|
||||||
|
Code: 500,
|
||||||
|
Msg: fmt.Sprintf("轮询失败: %v", err),
|
||||||
|
Data: PollResult{SuccessCount: successCount, FailCount: failCount},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{
|
||||||
|
Code: 0,
|
||||||
|
Msg: fmt.Sprintf("轮询完成,成功处理 %d 条,失败 %d 条", successCount, failCount),
|
||||||
|
Data: PollResult{SuccessCount: successCount, FailCount: failCount},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PollVideoResults 轮询视频待查询的检测结果
|
||||||
|
// 格式: POST /check/callback/pollVideo
|
||||||
|
func (c *YidunCallbackController) PollVideoResults(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
g.Log().Info(ctx, "开始轮询视频待查询的检测结果...")
|
||||||
|
|
||||||
|
successCount, failCount, err := dataengineService.MaterialVerify.PollPendingVideoResults(ctx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{
|
||||||
|
Code: 500,
|
||||||
|
Msg: fmt.Sprintf("轮询失败: %v", err),
|
||||||
|
Data: PollResult{SuccessCount: successCount, FailCount: failCount},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{
|
||||||
|
Code: 0,
|
||||||
|
Msg: fmt.Sprintf("轮询完成,成功处理 %d 条,失败 %d 条", successCount, failCount),
|
||||||
|
Data: PollResult{SuccessCount: successCount, FailCount: failCount},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PollByTaskID 根据任务ID查询单个检测结果
|
||||||
|
// 格式: POST /check/callback/pollTask
|
||||||
|
func (c *YidunCallbackController) PollByTaskID(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
taskID := r.Get("taskId", "").String()
|
||||||
|
taskType := r.Get("type", "").String() // image 或 video
|
||||||
|
|
||||||
|
if taskID == "" {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 400, Msg: "taskId不能为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Log().Infof(ctx, "查询单个检测结果, taskId=%s, type=%s", taskID, taskType)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if taskType == "video" || taskType == "" {
|
||||||
|
// 尝试视频
|
||||||
|
err = dataengineService.MaterialVerify.ProcessVideoResultByTask(ctx, taskID)
|
||||||
|
if err != nil {
|
||||||
|
// 如果失败且没有指定类型,尝试图片
|
||||||
|
if taskType == "" {
|
||||||
|
err = dataengineService.MaterialVerify.ProcessImageResultByTask(ctx, taskID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if taskType == "image" {
|
||||||
|
err = dataengineService.MaterialVerify.ProcessImageResultByTask(ctx, taskID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 0, Msg: "查询并处理成功"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// PendingListRes 待查询结果明细
|
||||||
|
type PendingListRes struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
List []dataengineService.PendingResultItem `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingDetail 获取待查询结果的明细
|
||||||
|
// 格式: GET /check/callback/pendingDetail
|
||||||
|
func (c *YidunCallbackController) GetPendingDetail(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
items, err := dataengineService.MaterialVerify.GetPendingResultsDetail(ctx, 50)
|
||||||
|
if err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(g.Map{
|
||||||
|
"code": 0,
|
||||||
|
"data": PendingListRes{
|
||||||
|
Total: len(items),
|
||||||
|
List: items,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingCount 获取待查询结果的数量
|
||||||
|
// 格式: GET /check/callback/pendingCount
|
||||||
|
func (c *YidunCallbackController) GetPendingCount(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
count, err := dataengineService.MaterialVerify.GetPendingResultsCount(ctx)
|
||||||
|
if err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(g.Map{
|
||||||
|
"code": 0,
|
||||||
|
"data": g.Map{
|
||||||
|
"pending_count": count,
|
||||||
|
"description": "待查询结果的日志数量(状态为pending且有taskID)",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 兼容旧接口(手动触发回调处理)
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ProcessImageCallback 手动处理图片回调(兼容旧接口)
|
||||||
|
// 格式: POST /check/callback/processImage
|
||||||
|
func (c *YidunCallbackController) ProcessImageCallback(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
CallbackData string `json:"callbackData" v:"required#回调数据不能为空"`
|
||||||
|
}
|
||||||
|
if err := r.Parse(&req); err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 400, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := dataengineService.MaterialVerify.ProcessImageCallback(ctx, req.CallbackData)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "处理图片回调失败: %v", err)
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 0, Msg: "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessVideoCallback 手动处理视频回调(兼容旧接口)
|
||||||
|
// 格式: POST /check/callback/processVideo
|
||||||
|
func (c *YidunCallbackController) ProcessVideoCallback(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
var req struct {
|
||||||
|
CallbackData string `json:"callbackData" v:"required#回调数据不能为空"`
|
||||||
|
}
|
||||||
|
if err := r.Parse(&req); err != nil {
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 400, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := dataengineService.MaterialVerify.ProcessVideoCallback(ctx, req.CallbackData)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "处理视频回调失败: %v", err)
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(CallbackResult{Code: 0, Msg: "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// toString 转换interface{}为string
|
||||||
|
func toString(v interface{}) string {
|
||||||
|
if s, ok := v.(string); ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cid/service/check"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
|
"github.com/yidun/yidun-golang-sdk/yidun/service/antispam/text/v5/check/async/single"
|
||||||
|
)
|
||||||
|
|
||||||
|
type yidunController struct{}
|
||||||
|
|
||||||
|
// YidunController 易盾控制器
|
||||||
|
var YidunController = new(yidunController)
|
||||||
|
|
||||||
|
// DetectTextReq 文本检测请求
|
||||||
|
type DetectTextReq struct {
|
||||||
|
DataID string `json:"data_id"`
|
||||||
|
Content string `json:"content" v:"required#待检测文本不能为空"`
|
||||||
|
IP string `json:"ip"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectImageReq 图片检测请求
|
||||||
|
type DetectImageReq struct {
|
||||||
|
DataID string `json:"data_id"`
|
||||||
|
ImageURL string `json:"image_url" v:"required#图片URL不能为空"`
|
||||||
|
CallbackURL string `json:"callback_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectVideoReq 视频检测请求
|
||||||
|
type DetectVideoReq struct {
|
||||||
|
DataID string `json:"data_id"`
|
||||||
|
VideoURL string `json:"video_url" v:"required#视频URL不能为空"`
|
||||||
|
CallbackURL string `json:"callback_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectText 文本检测
|
||||||
|
func (c *yidunController) DetectText(ctx context.Context, req *DetectTextReq) (string, error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
businessId := g.Cfg().MustGet(ctx, "check.text.business_id").String()
|
||||||
|
sdkReq := single.NewTextAsyncCheckRequest(businessId)
|
||||||
|
sdkReq.SetDataID(req.DataID)
|
||||||
|
sdkReq.SetContent(req.Content)
|
||||||
|
if req.IP != "" {
|
||||||
|
sdkReq.SetIP(req.IP)
|
||||||
|
}
|
||||||
|
if req.Token != "" {
|
||||||
|
sdkReq.SetToken(req.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
return check.TextDetection.DetectText(ctx, sdkReq)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectImage 图片检测
|
||||||
|
func (c *yidunController) DetectImage(ctx context.Context, req *DetectImageReq) (*check.ImageSubmitResult, error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
return check.ImageDetection.DetectImage(ctx, req.ImageURL, req.DataID, req.CallbackURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetectVideo 视频检测
|
||||||
|
func (c *yidunController) DetectVideo(ctx context.Context, req *DetectVideoReq) (*check.VideoSubmitResult, error) {
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
return check.VideoDetection.DetectVideo(ctx, req.VideoURL, req.DataID, req.CallbackURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImageCallbackResult 图片检测回调响应
|
||||||
|
type ImageCallbackResult struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReceiveImageCallback 接收图片检测结果推送
|
||||||
|
func (c *yidunController) ReceiveImageCallback(r *ghttp.Request) {
|
||||||
|
// IP 白名单校验
|
||||||
|
if !CheckCallbackIP(r.Context()) {
|
||||||
|
r.Response.WriteJson(ImageCallbackResult{Code: 403, Msg: "IP not allowed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
callbackData := r.GetForm("callbackData", "").String()
|
||||||
|
if callbackData == "" {
|
||||||
|
r.Response.WriteJson(ImageCallbackResult{Code: 400, Msg: "callbackData不能为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := check.MaterialVerify.ProcessImageCallback(ctx, callbackData)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "处理图片检测回调失败: %v", err)
|
||||||
|
r.Response.WriteJson(ImageCallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(ImageCallbackResult{Code: 0, Msg: "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// VideoCallbackResult 视频检测回调响应
|
||||||
|
type VideoCallbackResult struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReceiveVideoCallback 接收视频检测结果推送
|
||||||
|
func (c *yidunController) ReceiveVideoCallback(r *ghttp.Request) {
|
||||||
|
// IP 白名单校验
|
||||||
|
if !CheckCallbackIP(r.Context()) {
|
||||||
|
r.Response.WriteJson(VideoCallbackResult{Code: 403, Msg: "IP not allowed"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
callbackData := r.GetForm("callbackData", "").String()
|
||||||
|
if callbackData == "" {
|
||||||
|
r.Response.WriteJson(VideoCallbackResult{Code: 400, Msg: "callbackData不能为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := check.MaterialVerify.ProcessVideoCallback(ctx, callbackData)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "处理视频检测回调失败: %v", err)
|
||||||
|
r.Response.WriteJson(VideoCallbackResult{Code: 500, Msg: err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(VideoCallbackResult{Code: 0, Msg: "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVideoResult 获取视频检测结果
|
||||||
|
func (c *yidunController) GetVideoResult(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
taskId := r.Get("taskId", "").String()
|
||||||
|
if taskId == "" {
|
||||||
|
r.Response.WriteJson(g.Map{"code": 400, "msg": "taskId不能为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := check.VideoDetection.GetVideoResult(ctx, taskId)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "查询视频检测结果失败: %v", err)
|
||||||
|
r.Response.WriteJson(g.Map{"code": 500, "msg": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetImageResult 获取图片检测结果
|
||||||
|
func (c *yidunController) GetImageResult(r *ghttp.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = WithAdminUser(ctx)
|
||||||
|
|
||||||
|
taskId := r.Get("taskId", "").String()
|
||||||
|
if taskId == "" {
|
||||||
|
r.Response.WriteJson(g.Map{"code": 400, "msg": "taskId不能为空"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := check.ImageDetection.GetImageResult(ctx, taskId)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "查询图片检测结果失败: %v", err)
|
||||||
|
r.Response.WriteJson(g.Map{"code": 500, "msg": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Response.WriteJson(result)
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CID = new(cid)
|
|
||||||
|
|
||||||
type cid struct{}
|
|
||||||
|
|
||||||
// GenerateCID 生成CID广告
|
|
||||||
func (c *cid) GenerateCID(ctx context.Context, req *dto.GenerateCIDReq) (res *dto.GenerateCIDRes, err error) {
|
|
||||||
if req == nil {
|
|
||||||
return nil, gerror.New("请求参数不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.RequestType == "" {
|
|
||||||
req.RequestType = "default" // 默认请求类型
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := service.CID.GenerateCID(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCIDHistory 获取CID历史记录
|
|
||||||
func (c *cid) GetCIDHistory(ctx context.Context, req *dto.GetCIDHistoryReq) (res *dto.GetCIDHistoryRes, err error) {
|
|
||||||
if req == nil {
|
|
||||||
return nil, gerror.New("请求参数不能为空")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询历史记录
|
|
||||||
history, err := service.CID.GetCIDHistory(ctx, 1, req.Page, req.Size) // 临时使用固定用户ID
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return history, nil
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
)
|
|
||||||
|
|
||||||
var RateLimit = new(rateLimit)
|
|
||||||
|
|
||||||
type rateLimit struct{}
|
|
||||||
|
|
||||||
// SetTenantRateLimit 设置租户限流配置
|
|
||||||
func (c *rateLimit) SetTenantRateLimit(ctx context.Context, req *dto.SetTenantRateLimitReq) (res *dto.SetTenantRateLimitRes, err error) {
|
|
||||||
// 注意:实际使用的是config.yml中的全局配置,此接口仅用于兼容旧API
|
|
||||||
// 实际限流参数请修改config.yml中的tenantRateLimit部分
|
|
||||||
|
|
||||||
return &dto.SetTenantRateLimitRes{
|
|
||||||
Success: true,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTenantRateLimitUsage 获取租户限流使用情况
|
|
||||||
func (c *rateLimit) GetTenantRateLimitUsage(ctx context.Context, req *dto.GetTenantRateLimitUsageReq) (res *dto.GetTenantRateLimitUsageRes, err error) {
|
|
||||||
current, max, err := service.RateLimit.GetTenantCurrentUsage(ctx, req.TenantID, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.GetTenantRateLimitUsageRes{
|
|
||||||
TenantID: req.TenantID,
|
|
||||||
CurrentUsed: current,
|
|
||||||
MaxAllowed: max,
|
|
||||||
UsagePercent: float64(current) / float64(max) * 100,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/service"
|
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Strategy = new(strategy)
|
|
||||||
|
|
||||||
type strategy struct{}
|
|
||||||
|
|
||||||
// Create 创建策略
|
|
||||||
func (c *strategy) Create(ctx context.Context, req *dto.CreateStrategyReq) (res *dto.StrategyRes, err error) {
|
|
||||||
id, err := service.Strategy.CreateStrategy(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
strategy, err := service.Strategy.GetStrategyByID(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return strategy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新策略
|
|
||||||
func (c *strategy) Update(ctx context.Context, req *dto.UpdateStrategyReq) (res *dto.StrategyRes, err error) {
|
|
||||||
affected, err := service.Strategy.UpdateStrategy(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if affected == 0 {
|
|
||||||
return nil, gerror.New("策略更新失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
strategy, err := service.Strategy.GetStrategyByID(ctx, req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return strategy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete 删除策略
|
|
||||||
func (c *strategy) Delete(ctx context.Context, req *dto.DeleteStrategyReq) (res *dto.DeleteStrategyRes, err error) {
|
|
||||||
affected, err := service.Strategy.DeleteStrategy(ctx, req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if affected == 0 {
|
|
||||||
return nil, gerror.New("策略删除失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dto.DeleteStrategyRes{
|
|
||||||
Success: true,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByID 根据ID获取策略
|
|
||||||
func (c *strategy) GetByID(ctx context.Context, req *dto.GetStrategyReq) (res *dto.StrategyRes, err error) {
|
|
||||||
strategy, err := service.Strategy.GetStrategyByID(ctx, req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return strategy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetList 获取策略列表
|
|
||||||
func (c *strategy) GetList(ctx context.Context, req *dto.GetStrategyListReq) (res *dto.GetStrategyListRes, err error) {
|
|
||||||
return service.Strategy.GetStrategyList(ctx, req)
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/model/entity"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"gitea.com/red-future/common/db/mongo"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var AdPosition = &adPosition{}
|
|
||||||
|
|
||||||
type adPosition struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert 插入广告位
|
|
||||||
func (d *adPosition) Insert(ctx context.Context, req *dto.AddAdPositionReq) (ids []any, err error) {
|
|
||||||
var result entity.AdPosition
|
|
||||||
if err = gconv.Struct(req, &result); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ids, err = mongo.DB().Insert(ctx, []interface{}{&result}, entity.AdPositionCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告位
|
|
||||||
func (d *adPosition) Update(ctx context.Context, id *bson.ObjectID, updateData *entity.AdPosition) (err error) {
|
|
||||||
filter := bson.M{"_id": id}
|
|
||||||
|
|
||||||
if !g.IsEmpty(updateData) {
|
|
||||||
bsonm, err := mongo.BuildUpdateData(ctx, updateData)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
update := bson.M{"$set": bsonm}
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdPositionCollection)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus 更新广告位状态
|
|
||||||
func (d *adPosition) UpdateStatus(ctx context.Context, id *bson.ObjectID, status string) (err error) {
|
|
||||||
filter := bson.M{"_id": id}
|
|
||||||
update := bson.M{"$set": bson.M{"status": status}}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdPositionCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取单个广告位
|
|
||||||
func (d *adPosition) GetOne(ctx context.Context, id *bson.ObjectID) (adPosition *entity.AdPosition, err error) {
|
|
||||||
filter := bson.M{"_id": id}
|
|
||||||
|
|
||||||
adPosition = &entity.AdPosition{}
|
|
||||||
err = mongo.DB().FindOne(ctx, filter, adPosition, entity.AdPositionCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete 删除广告位
|
|
||||||
func (d *adPosition) Delete(ctx context.Context, id *bson.ObjectID) (err error) {
|
|
||||||
filter := bson.M{"_id": id}
|
|
||||||
_, err = mongo.DB().Delete(ctx, filter, entity.AdPositionCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildListFilter 构建列表查询的过滤条件
|
|
||||||
func (d *adPosition) buildListFilter(req *dto.ListAdPositionReq) bson.M {
|
|
||||||
filter := bson.M{}
|
|
||||||
|
|
||||||
if !g.IsEmpty(req.Name) {
|
|
||||||
filter["name"] = bson.M{"$regex": req.Name, "$options": "i"}
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.PositionCode) {
|
|
||||||
filter["positionCode"] = req.PositionCode
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.PageName) {
|
|
||||||
filter["page"] = req.PageName
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Section) {
|
|
||||||
filter["section"] = req.Section
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Status) {
|
|
||||||
filter["status"] = req.Status
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdFormat) {
|
|
||||||
filter["adFormat"] = req.AdFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理日期范围
|
|
||||||
if len(req.DateRange) == 2 {
|
|
||||||
startTime := gconv.Int64(req.DateRange[0])
|
|
||||||
endTime := gconv.Int64(req.DateRange[1])
|
|
||||||
filter["createdAt"] = bson.M{
|
|
||||||
"$gte": startTime,
|
|
||||||
"$lte": endTime,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告位列表
|
|
||||||
func (d *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (list []*entity.AdPosition, total int64, err error) {
|
|
||||||
// 构建查询过滤条件
|
|
||||||
filter := d.buildListFilter(req)
|
|
||||||
|
|
||||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
|
||||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.AdPositionCollection, req.Page, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAvailableAdPositions 获取可用的广告位列表
|
|
||||||
func (d *adPosition) GetAvailableAdPositions(ctx context.Context) (list []*entity.AdPosition, err error) {
|
|
||||||
filter := bson.M{
|
|
||||||
"status": "启用", // 只返回启用的广告位
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用空的Page参数获取所有数据
|
|
||||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
|
||||||
_, err = mongo.DB().Find(ctx, filter, &list, entity.AdPositionCollection, page, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/consts"
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"gitea.com/red-future/common/db/mongo"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var AdSource = &adSourceDao{}
|
|
||||||
|
|
||||||
type adSourceDao struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByName 根据名称获取广告源
|
|
||||||
func (d *adSourceDao) GetByName(ctx context.Context, name string) (adSource *entity.AdSource, err error) {
|
|
||||||
err = mongo.DB().FindOne(ctx, bson.M{"name": name}, &adSource, consts.AdSourceCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAvailableSources 获取可用的广告源
|
|
||||||
func (d *adSourceDao) GetAvailableSources(ctx context.Context) (list []*entity.AdSource, err error) {
|
|
||||||
// 使用空的Page参数获取所有数据
|
|
||||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
|
||||||
_, err = mongo.DB().Find(ctx, bson.M{"status": "active"}, &list, consts.AdSourceCollection, page, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSourcesByProvider 根据提供商获取广告源
|
|
||||||
func (d *adSourceDao) GetSourcesByProvider(ctx context.Context, provider string) (list []*entity.AdSource, err error) {
|
|
||||||
// 使用空的Page参数获取所有数据
|
|
||||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
|
||||||
_, err = mongo.DB().Find(ctx, bson.M{"provider": provider, "status": "active"}, &list, consts.AdSourceCollection, page, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create 创建广告源
|
|
||||||
func (d *adSourceDao) Create(ctx context.Context, adSource *entity.AdSource) (id string, err error) {
|
|
||||||
ids, err := mongo.DB().Insert(ctx, []interface{}{adSource}, consts.AdSourceCollection)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(ids) > 0 {
|
|
||||||
id = ids[0].(string)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告源
|
|
||||||
func (d *adSourceDao) Update(ctx context.Context, adSource *entity.AdSource) (affected int64, err error) {
|
|
||||||
result, err := mongo.DB().Update(ctx, bson.M{"_id": adSource.Id}, bson.M{"$set": adSource}, consts.AdSourceCollection)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete 删除广告源
|
|
||||||
func (d *adSourceDao) Delete(ctx context.Context, id string) (affected int64, err error) {
|
|
||||||
count, err := mongo.DB().Delete(ctx, bson.M{"_id": id}, consts.AdSourceCollection)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByID 根据ID获取广告源
|
|
||||||
func (d *adSourceDao) GetByID(ctx context.Context, id string) (adSource *entity.AdSource, err error) {
|
|
||||||
err = mongo.DB().FindOne(ctx, bson.M{"_id": id}, &adSource, consts.AdSourceCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateFields 更新广告源部分字段
|
|
||||||
func (d *adSourceDao) UpdateFields(ctx context.Context, id string, data *entity.AdSource) (affected int64, err error) {
|
|
||||||
result, err := mongo.DB().Update(ctx, bson.M{"_id": id}, bson.M{"$set": data}, consts.AdSourceCollection)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/model/entity"
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/mongo"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Advertisement = &advertisement{}
|
|
||||||
|
|
||||||
type advertisement struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert 插入广告
|
|
||||||
func (d *advertisement) Insert(ctx context.Context, advertisement *entity.Advertisement) (err error) {
|
|
||||||
// 获取stream消息
|
|
||||||
redis := g.Redis()
|
|
||||||
streamMsg, err := redis.Do(ctx, "XREAD", "STREAMS", "advertisement_stream", "$")
|
|
||||||
if err != nil {
|
|
||||||
g.Log().Errorf(ctx, "获取stream消息失败: %v", err)
|
|
||||||
} else {
|
|
||||||
g.Log().Infof(ctx, "获取到stream消息: %v", streamMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Insert(ctx, []interface{}{advertisement}, entity.AdvertisementCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告
|
|
||||||
func (d *advertisement) Update(ctx context.Context, req *dto.UpdateAdvertisementReq) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
|
|
||||||
// 构建动态更新字段
|
|
||||||
updateFields := bson.M{}
|
|
||||||
|
|
||||||
// 广告基本信息
|
|
||||||
if !g.IsEmpty(req.Title) {
|
|
||||||
updateFields["title"] = req.Title
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Description) {
|
|
||||||
updateFields["description"] = req.Description
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdvertiserId) {
|
|
||||||
updateFields["advertiserId"] = req.AdvertiserId
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdPositionId) {
|
|
||||||
updateFields["adPositionId"] = req.AdPositionId
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdType) {
|
|
||||||
updateFields["adType"] = req.AdType
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdFormat) {
|
|
||||||
updateFields["adFormat"] = req.AdFormat
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.MaterialUrl) {
|
|
||||||
updateFields["materialUrl"] = req.MaterialUrl
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.TargetUrl) {
|
|
||||||
updateFields["targetUrl"] = req.TargetUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
// 投放设置
|
|
||||||
if req.StartDate != nil {
|
|
||||||
updateFields["startDate"] = *req.StartDate
|
|
||||||
}
|
|
||||||
if req.EndDate != nil {
|
|
||||||
updateFields["endDate"] = *req.EndDate
|
|
||||||
}
|
|
||||||
if req.Budget != nil {
|
|
||||||
updateFields["budget"] = *req.Budget
|
|
||||||
}
|
|
||||||
if req.DailyBudget != nil {
|
|
||||||
updateFields["dailyBudget"] = *req.DailyBudget
|
|
||||||
}
|
|
||||||
if req.BidAmount != nil {
|
|
||||||
updateFields["bidAmount"] = *req.BidAmount
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.BillingType) {
|
|
||||||
updateFields["billingType"] = req.BillingType
|
|
||||||
}
|
|
||||||
|
|
||||||
// 投放条件
|
|
||||||
if req.Targeting != nil {
|
|
||||||
updateFields["targeting"] = req.Targeting
|
|
||||||
}
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
if req.Status != nil {
|
|
||||||
updateFields["status"] = *req.Status
|
|
||||||
}
|
|
||||||
if req.AuditStatus != nil {
|
|
||||||
updateFields["auditStatus"] = *req.AuditStatus
|
|
||||||
}
|
|
||||||
if req.AuditReason != nil {
|
|
||||||
updateFields["auditReason"] = *req.AuditReason
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(updateFields) > 0 {
|
|
||||||
update := bson.M{"$set": updateFields}
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus 更新广告状态
|
|
||||||
func (d *advertisement) UpdateStatus(ctx context.Context, id, status string) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
update := bson.M{"$set": bson.M{"status": status}}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audit 审核广告
|
|
||||||
func (d *advertisement) Audit(ctx context.Context, id, auditStatus, auditReason string) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
|
|
||||||
// 获取当前用户ID(实际项目中应从上下文获取)
|
|
||||||
auditBy := "system"
|
|
||||||
auditTime := time.Now().Unix()
|
|
||||||
|
|
||||||
update := bson.M{
|
|
||||||
"$set": bson.M{
|
|
||||||
"auditStatus": auditStatus,
|
|
||||||
"auditReason": auditReason,
|
|
||||||
"auditTime": auditTime,
|
|
||||||
"auditBy": auditBy,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatistics 更新广告统计数据
|
|
||||||
func (d *advertisement) UpdateStatistics(ctx context.Context, id string, stats map[string]interface{}) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
update := bson.M{"$set": stats}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertisementCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取单个广告
|
|
||||||
func (d *advertisement) GetOne(ctx context.Context, id string) (advertisement *entity.Advertisement, err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
|
|
||||||
advertisement = &entity.Advertisement{}
|
|
||||||
err = mongo.DB().FindOne(ctx, filter, advertisement, entity.AdvertisementCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildListFilter 构建列表查询的过滤条件
|
|
||||||
func (d *advertisement) buildListFilter(req *dto.ListAdvertisementReq) bson.M {
|
|
||||||
filter := bson.M{}
|
|
||||||
|
|
||||||
if !g.IsEmpty(req.AdvertiserId) {
|
|
||||||
filter["advertiserId"] = req.AdvertiserId
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdPositionId) {
|
|
||||||
filter["adPositionId"] = req.AdPositionId
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdType) {
|
|
||||||
filter["adType"] = req.AdType
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Status) {
|
|
||||||
filter["status"] = req.Status
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AuditStatus) {
|
|
||||||
filter["auditStatus"] = req.AuditStatus
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Title) {
|
|
||||||
filter["title"] = bson.M{"$regex": req.Title, "$options": "i"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理日期范围
|
|
||||||
if len(req.DateRange) == 2 {
|
|
||||||
startTime := gconv.Int64(req.DateRange[0])
|
|
||||||
endTime := gconv.Int64(req.DateRange[1])
|
|
||||||
filter["createdAt"] = bson.M{
|
|
||||||
"$gte": startTime,
|
|
||||||
"$lte": endTime,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkTotalCount 检查总数
|
|
||||||
func (d *advertisement) checkTotalCount(ctx context.Context, filter bson.M) (total int64, err error) {
|
|
||||||
total, err = mongo.DB().Count(ctx, filter, entity.AdvertisementCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告列表
|
|
||||||
func (d *advertisement) List(ctx context.Context, req *dto.ListAdvertisementReq) (list []*entity.Advertisement, total int64, err error) {
|
|
||||||
// 构建查询过滤条件
|
|
||||||
filter := d.buildListFilter(req)
|
|
||||||
|
|
||||||
// 检查总数
|
|
||||||
total, err = d.checkTotalCount(ctx, filter)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
|
||||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.AdvertisementCollection, req.Page, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,280 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/model/entity"
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/db/mongo"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
"github.com/gogf/gf/v2/util/gconv"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Advertiser = &advertiser{}
|
|
||||||
|
|
||||||
type advertiser struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert 插入广告主
|
|
||||||
func (d *advertiser) Insert(ctx context.Context, advertiser *entity.Advertiser) (err error) {
|
|
||||||
// 获取stream消息
|
|
||||||
redis := g.Redis()
|
|
||||||
streamMsg, err := redis.Do(ctx, "XREAD", "STREAMS", "advertiser_stream", "$")
|
|
||||||
if err != nil {
|
|
||||||
g.Log().Errorf(ctx, "获取stream消息失败: %v", err)
|
|
||||||
} else {
|
|
||||||
g.Log().Infof(ctx, "获取到stream消息: %v", streamMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Insert(ctx, []interface{}{advertiser}, entity.AdvertiserCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告主
|
|
||||||
func (d *advertiser) Update(ctx context.Context, req *dto.UpdateAdvertiserReq) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
|
|
||||||
// 构建动态更新字段
|
|
||||||
updateFields := bson.M{}
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
if !g.IsEmpty(req.Name) {
|
|
||||||
updateFields["name"] = req.Name
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.ContactName) {
|
|
||||||
updateFields["contactName"] = req.ContactName
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.ContactPhone) {
|
|
||||||
updateFields["contactPhone"] = req.ContactPhone
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.ContactEmail) {
|
|
||||||
updateFields["contactEmail"] = req.ContactEmail
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Company) {
|
|
||||||
updateFields["company"] = req.Company
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Industry) {
|
|
||||||
updateFields["industry"] = req.Industry
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Scale) {
|
|
||||||
updateFields["scale"] = req.Scale
|
|
||||||
}
|
|
||||||
|
|
||||||
// 证件信息
|
|
||||||
if !g.IsEmpty(req.BusinessLicenseUrl) {
|
|
||||||
updateFields["businessLicenseUrl"] = req.BusinessLicenseUrl
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.ICPLicenseUrl) {
|
|
||||||
updateFields["icpLicenseUrl"] = req.ICPLicenseUrl
|
|
||||||
}
|
|
||||||
if req.OtherLicenseUrls != nil {
|
|
||||||
updateFields["otherLicenseUrls"] = req.OtherLicenseUrls
|
|
||||||
}
|
|
||||||
|
|
||||||
// 财务信息
|
|
||||||
if !g.IsEmpty(req.BankName) {
|
|
||||||
updateFields["bankName"] = req.BankName
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.BankAccount) {
|
|
||||||
updateFields["bankAccount"] = req.BankAccount
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AccountName) {
|
|
||||||
updateFields["accountName"] = req.AccountName
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合同信息
|
|
||||||
if !g.IsEmpty(req.ContractId) {
|
|
||||||
updateFields["contractId"] = req.ContractId
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.ContractType) {
|
|
||||||
updateFields["contractType"] = req.ContractType
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.ContractUrl) {
|
|
||||||
updateFields["contractUrl"] = req.ContractUrl
|
|
||||||
}
|
|
||||||
if req.SignDate != nil {
|
|
||||||
updateFields["signDate"] = *req.SignDate
|
|
||||||
}
|
|
||||||
if req.ExpireDate != nil {
|
|
||||||
updateFields["expireDate"] = *req.ExpireDate
|
|
||||||
}
|
|
||||||
|
|
||||||
// 系统信息
|
|
||||||
if req.AccountBalance != nil {
|
|
||||||
updateFields["accountBalance"] = *req.AccountBalance
|
|
||||||
}
|
|
||||||
if req.CreditLimit != nil {
|
|
||||||
updateFields["creditLimit"] = *req.CreditLimit
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Remark) {
|
|
||||||
updateFields["remark"] = req.Remark
|
|
||||||
}
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
if req.Status != nil {
|
|
||||||
updateFields["status"] = *req.Status
|
|
||||||
}
|
|
||||||
if req.AuditStatus != nil {
|
|
||||||
updateFields["auditStatus"] = *req.AuditStatus
|
|
||||||
}
|
|
||||||
if req.AuditReason != nil {
|
|
||||||
updateFields["auditReason"] = *req.AuditReason
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(updateFields) > 0 {
|
|
||||||
update := bson.M{"$set": updateFields}
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus 更新广告主状态
|
|
||||||
func (d *advertiser) UpdateStatus(ctx context.Context, id, status string) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
update := bson.M{"$set": bson.M{"status": status}}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audit 审核广告主
|
|
||||||
func (d *advertiser) Audit(ctx context.Context, id, auditStatus, auditReason string) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
|
|
||||||
// 获取当前用户ID(实际项目中应从上下文获取)
|
|
||||||
auditBy := "system"
|
|
||||||
auditTime := time.Now().Unix()
|
|
||||||
|
|
||||||
update := bson.M{
|
|
||||||
"$set": bson.M{
|
|
||||||
"auditStatus": auditStatus,
|
|
||||||
"auditReason": auditReason,
|
|
||||||
"auditTime": auditTime,
|
|
||||||
"auditBy": auditBy,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recharge 充值
|
|
||||||
func (d *advertiser) Recharge(ctx context.Context, id string, amount int64, remark string) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
|
|
||||||
// 先获取当前余额
|
|
||||||
advertiser := &entity.Advertiser{}
|
|
||||||
err = mongo.DB().FindOne(ctx, filter, advertiser, entity.AdvertiserCollection)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新余额
|
|
||||||
newBalance := advertiser.AccountBalance + amount
|
|
||||||
update := bson.M{"$set": bson.M{"accountBalance": newBalance}}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateCreditLimit 更新授信额度
|
|
||||||
func (d *advertiser) UpdateCreditLimit(ctx context.Context, id string, creditLimit int64) (err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
update := bson.M{"$set": bson.M{"creditLimit": creditLimit}}
|
|
||||||
|
|
||||||
_, err = mongo.DB().Update(ctx, filter, update, entity.AdvertiserCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取单个广告主
|
|
||||||
func (d *advertiser) GetOne(ctx context.Context, id string) (advertiser *entity.Advertiser, err error) {
|
|
||||||
objectId, err := bson.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
filter := bson.M{"_id": objectId}
|
|
||||||
|
|
||||||
advertiser = &entity.Advertiser{}
|
|
||||||
err = mongo.DB().FindOne(ctx, filter, advertiser, entity.AdvertiserCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildListFilter 构建列表查询的过滤条件
|
|
||||||
func (d *advertiser) buildListFilter(req *dto.ListAdvertiserReq) bson.M {
|
|
||||||
filter := bson.M{}
|
|
||||||
|
|
||||||
if !g.IsEmpty(req.Name) {
|
|
||||||
filter["name"] = bson.M{"$regex": req.Name, "$options": "i"}
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.ContactName) {
|
|
||||||
filter["contactName"] = bson.M{"$regex": req.ContactName, "$options": "i"}
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Company) {
|
|
||||||
filter["company"] = bson.M{"$regex": req.Company, "$options": "i"}
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Industry) {
|
|
||||||
filter["industry"] = req.Industry
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Status) {
|
|
||||||
filter["status"] = req.Status
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AuditStatus) {
|
|
||||||
filter["auditStatus"] = req.AuditStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理日期范围
|
|
||||||
if len(req.DateRange) == 2 {
|
|
||||||
startTime := gconv.Int64(req.DateRange[0])
|
|
||||||
endTime := gconv.Int64(req.DateRange[1])
|
|
||||||
filter["createdAt"] = bson.M{
|
|
||||||
"$gte": startTime,
|
|
||||||
"$lte": endTime,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filter
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkTotalCount 检查总数
|
|
||||||
func (d *advertiser) checkTotalCount(ctx context.Context, filter bson.M) (total int64, err error) {
|
|
||||||
total, err = mongo.DB().Count(ctx, filter, entity.AdvertiserCollection)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告主列表
|
|
||||||
func (d *advertiser) List(ctx context.Context, req *dto.ListAdvertiserReq) (list []*entity.Advertiser, total int64, err error) {
|
|
||||||
// 构建查询过滤条件
|
|
||||||
filter := d.buildListFilter(req)
|
|
||||||
|
|
||||||
// 检查总数
|
|
||||||
total, err = d.checkTotalCount(ctx, filter)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
|
||||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.AdvertiserCollection, req.Page, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"gitea.com/red-future/common/db/mongo"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
// applicationDao 应用DAO
|
|
||||||
type applicationDao struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
var Application = &applicationDao{}
|
|
||||||
|
|
||||||
// Create 创建应用
|
|
||||||
func (d *applicationDao) Create(ctx context.Context, app *entity.Application) (string, error) {
|
|
||||||
ids, err := mongo.DB().Insert(ctx, []interface{}{app}, "application")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(ids) > 0 {
|
|
||||||
return ids[0].(string), nil
|
|
||||||
}
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByID 根据ID获取应用
|
|
||||||
func (d *applicationDao) GetByID(ctx context.Context, id string) (*entity.Application, error) {
|
|
||||||
var app *entity.Application
|
|
||||||
err := mongo.DB().FindOne(ctx, bson.M{"_id": id}, &app, "application")
|
|
||||||
return app, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByTenantID 根据租户ID获取应用列表
|
|
||||||
func (d *applicationDao) GetByTenantID(ctx context.Context, tenantID string) ([]*entity.Application, error) {
|
|
||||||
var apps []*entity.Application
|
|
||||||
// 使用空的Page参数获取所有数据
|
|
||||||
page := &beans.Page{PageNum: 1, PageSize: -1} // -1表示不分页
|
|
||||||
_, err := mongo.DB().Find(ctx,
|
|
||||||
bson.M{"tenantId": tenantID}, &apps, "application", page, nil)
|
|
||||||
return apps, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByAPIKey 根据API密钥获取应用
|
|
||||||
func (d *applicationDao) GetByAPIKey(ctx context.Context, apiKey string) (*entity.Application, error) {
|
|
||||||
var app *entity.Application
|
|
||||||
err := mongo.DB().FindOne(ctx,
|
|
||||||
bson.M{"appKey": apiKey}, &app, "application")
|
|
||||||
return app, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新应用
|
|
||||||
func (d *applicationDao) Update(ctx context.Context, app *entity.Application) error {
|
|
||||||
_, err := mongo.DB().Update(ctx, bson.M{"_id": app.Id}, bson.M{"$set": app}, "application")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete 删除应用
|
|
||||||
func (d *applicationDao) Delete(ctx context.Context, id string) error {
|
|
||||||
_, err := mongo.DB().Delete(ctx, bson.M{"_id": id}, "application")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 应用列表
|
|
||||||
func (d *applicationDao) List(ctx context.Context, tenantID string, page, pageSize int) ([]*entity.Application, int, error) {
|
|
||||||
filter := bson.M{}
|
|
||||||
if tenantID != "" {
|
|
||||||
filter["tenantId"] = tenantID
|
|
||||||
}
|
|
||||||
|
|
||||||
var apps []*entity.Application
|
|
||||||
total, err := mongo.DB().Count(ctx, filter, "application")
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用common/mongo的Find方法,自动处理分页、租户等
|
|
||||||
pageBean := &beans.Page{PageNum: int64(page), PageSize: int64(pageSize)}
|
|
||||||
total, err = mongo.DB().Find(ctx, filter, &apps, "application", pageBean, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return apps, int(total), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByName 根据名称获取应用
|
|
||||||
func (d *applicationDao) GetByName(ctx context.Context, name string) (*entity.Application, error) {
|
|
||||||
var app *entity.Application
|
|
||||||
err := mongo.DB().FindOne(ctx, bson.M{"name": name}, &app, "application")
|
|
||||||
return app, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateFields 更新应用部分字段
|
|
||||||
func (d *applicationDao) UpdateFields(ctx context.Context, id string, data *entity.Application) error {
|
|
||||||
_, err := mongo.DB().Update(ctx, bson.M{"_id": id}, bson.M{"$set": data}, "application")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Model 获取 dataEngine 数据库的 Model(GoFrame ORM)
|
||||||
|
// 配置文件中 dataEngine 对应的实际数据库名是 check
|
||||||
|
func Model(tableName string) *gdb.Model {
|
||||||
|
return g.DB("dataEngine").Model(tableName)
|
||||||
|
}
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
daoEntity "cid/model/entity/check"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/snowflake"
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaterialVerifyLogDAO 素材校验日志数据访问层
|
||||||
|
type MaterialVerifyLogDAO struct{}
|
||||||
|
|
||||||
|
// MaterialVerifyLog DAO单例
|
||||||
|
var MaterialVerifyLog = new(MaterialVerifyLogDAO)
|
||||||
|
|
||||||
|
// TableName 表名
|
||||||
|
const MaterialVerifyLogTable = "material_verify_log"
|
||||||
|
|
||||||
|
// Create 创建校验日志
|
||||||
|
func (d *MaterialVerifyLogDAO) Create(ctx context.Context, log *daoEntity.MaterialVerifyLog) (id int64, err error) {
|
||||||
|
// GoFrame v2.10.0 pgsql 驱动不支持 RETURNING/LastInsertId
|
||||||
|
// 且 gfdb insertHook 会覆盖 id,无法从外部获取钩子生成的 ID
|
||||||
|
// 手动生成 Snowflake ID 并直接插入(绕过 gfdb 钩子)
|
||||||
|
node, err := snowflake.NewNode(1)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "创建Snowflake节点失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
snowflakeID := node.Generate().Int64()
|
||||||
|
|
||||||
|
_, err = g.DB("cid").Model(MaterialVerifyLogTable).Data(g.Map{
|
||||||
|
"id": snowflakeID,
|
||||||
|
"tenant_id": log.TenantID,
|
||||||
|
"material_type": log.MaterialType,
|
||||||
|
"material_id": log.MaterialID,
|
||||||
|
"source_table": log.SourceTable,
|
||||||
|
"source_id": log.SourceID,
|
||||||
|
"account_id": log.AccountID,
|
||||||
|
"verify_status": log.VerifyStatus,
|
||||||
|
}).Insert()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "创建校验日志失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return snowflakeID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByID 根据ID获取日志
|
||||||
|
func (d *MaterialVerifyLogDAO) GetByID(ctx context.Context, id int64) (*daoEntity.MaterialVerifyLog, error) {
|
||||||
|
var result daoEntity.MaterialVerifyLog
|
||||||
|
r, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.Id, id).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByTaskID 根据任务ID获取日志
|
||||||
|
func (d *MaterialVerifyLogDAO) GetByTaskID(ctx context.Context, taskID string) (*daoEntity.MaterialVerifyLog, error) {
|
||||||
|
var result daoEntity.MaterialVerifyLog
|
||||||
|
r, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.TaskID, taskID).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByMaterialID 根据素材ID获取日志列表
|
||||||
|
func (d *MaterialVerifyLogDAO) GetByMaterialID(ctx context.Context, materialID string) ([]daoEntity.MaterialVerifyLog, error) {
|
||||||
|
var result []daoEntity.MaterialVerifyLog
|
||||||
|
r, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.MaterialID, materialID).
|
||||||
|
OrderDesc(daoEntity.MaterialVerifyLogCols.CreatedAt).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBySource 根据来源获取日志
|
||||||
|
func (d *MaterialVerifyLogDAO) GetBySource(ctx context.Context, sourceTable string, sourceID int64) ([]daoEntity.MaterialVerifyLog, error) {
|
||||||
|
var result []daoEntity.MaterialVerifyLog
|
||||||
|
r, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.SourceTable, sourceTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.SourceID, sourceID).
|
||||||
|
OrderDesc(daoEntity.MaterialVerifyLogCols.CreatedAt).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateVerifyResult 更新校验结果
|
||||||
|
func (d *MaterialVerifyLogDAO) UpdateVerifyResult(ctx context.Context, id int64, verifyStatus string, suggestion, label, resultType int, responseResult string, checkTime int64) error {
|
||||||
|
_, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.Id, id).
|
||||||
|
Data(g.Map{
|
||||||
|
daoEntity.MaterialVerifyLogCols.VerifyStatus: verifyStatus,
|
||||||
|
daoEntity.MaterialVerifyLogCols.Suggestion: suggestion,
|
||||||
|
daoEntity.MaterialVerifyLogCols.Label: label,
|
||||||
|
daoEntity.MaterialVerifyLogCols.ResultType: resultType,
|
||||||
|
daoEntity.MaterialVerifyLogCols.ResponseResult: responseResult,
|
||||||
|
daoEntity.MaterialVerifyLogCols.CheckTime: checkTime,
|
||||||
|
}).Update()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "更新校验日志结果失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateError 更新错误信息
|
||||||
|
func (d *MaterialVerifyLogDAO) UpdateError(ctx context.Context, id int64, verifyStatus string, errorMsg string) error {
|
||||||
|
_, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.Id, id).
|
||||||
|
Data(g.Map{
|
||||||
|
daoEntity.MaterialVerifyLogCols.VerifyStatus: verifyStatus,
|
||||||
|
daoEntity.MaterialVerifyLogCols.ErrorMsg: errorMsg,
|
||||||
|
}).Update()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "更新校验日志错误失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTaskID 更新任务ID
|
||||||
|
func (d *MaterialVerifyLogDAO) UpdateTaskID(ctx context.Context, id int64, taskID string) error {
|
||||||
|
_, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.Id, id).
|
||||||
|
Data(g.Map{
|
||||||
|
daoEntity.MaterialVerifyLogCols.TaskID: taskID,
|
||||||
|
}).Update()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDuration 更新处理耗时
|
||||||
|
func (d *MaterialVerifyLogDAO) UpdateDuration(ctx context.Context, id int64, durationMs int64) error {
|
||||||
|
_, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.Id, id).
|
||||||
|
Data(g.Map{
|
||||||
|
daoEntity.MaterialVerifyLogCols.DurationMs: durationMs,
|
||||||
|
}).Update()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRequestParams 更新请求参数
|
||||||
|
func (d *MaterialVerifyLogDAO) UpdateRequestParams(ctx context.Context, id int64, requestParams string) error {
|
||||||
|
_, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.Id, id).
|
||||||
|
Data(g.Map{
|
||||||
|
daoEntity.MaterialVerifyLogCols.RequestParams: requestParams,
|
||||||
|
}).Update()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByCondition 根据条件分页查询
|
||||||
|
func (d *MaterialVerifyLogDAO) GetByCondition(ctx context.Context, condition map[string]interface{}, page, pageSize int) ([]daoEntity.MaterialVerifyLog, int, error) {
|
||||||
|
var result []daoEntity.MaterialVerifyLog
|
||||||
|
m := g.DB("cid").Model(MaterialVerifyLogTable)
|
||||||
|
|
||||||
|
for k, v := range condition {
|
||||||
|
m.Where(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
total, err := m.Count()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := m.
|
||||||
|
OrderDesc(daoEntity.MaterialVerifyLogCols.CreatedAt).
|
||||||
|
Page(page, pageSize).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return result, int(total), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountByStatus 按状态统计
|
||||||
|
func (d *MaterialVerifyLogDAO) CountByStatus(ctx context.Context, verifyStatus string) (int, error) {
|
||||||
|
count, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.VerifyStatus, verifyStatus).
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(count), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStats 获取统计信息
|
||||||
|
func (d *MaterialVerifyLogDAO) GetStats(ctx context.Context) (map[string]int, error) {
|
||||||
|
stats := make(map[string]int)
|
||||||
|
|
||||||
|
statuses := []struct {
|
||||||
|
statusKey string
|
||||||
|
statusVal string
|
||||||
|
}{
|
||||||
|
{"pending", daoEntity.VerifyStatusPending},
|
||||||
|
{"verified", daoEntity.VerifyStatusVerified},
|
||||||
|
{"rejected", daoEntity.VerifyStatusRejected},
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalCount int
|
||||||
|
for _, item := range statuses {
|
||||||
|
count, err := d.CountByStatus(ctx, item.statusVal)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
stats[item.statusKey] = count
|
||||||
|
totalCount += count
|
||||||
|
}
|
||||||
|
|
||||||
|
stats["total"] = totalCount
|
||||||
|
return stats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPendingResults 获取待查询结果的日志(状态为pending且有taskID)
|
||||||
|
func (d *MaterialVerifyLogDAO) GetPendingResults(ctx context.Context, limit int) ([]daoEntity.MaterialVerifyLog, error) {
|
||||||
|
var result []daoEntity.MaterialVerifyLog
|
||||||
|
|
||||||
|
r, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.VerifyStatus, daoEntity.VerifyStatusPending).
|
||||||
|
WhereNotNull(daoEntity.MaterialVerifyLogCols.TaskID).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.TaskID + " != ''").
|
||||||
|
OrderAsc(daoEntity.MaterialVerifyLogCols.CreatedAt).
|
||||||
|
Limit(limit).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "查询待处理结果日志失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
g.Log().Errorf(ctx, "转换待处理结果日志失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLastRejectedLogByMaterialID 根据素材ID获取最后一条失败的校验日志
|
||||||
|
func (d *MaterialVerifyLogDAO) GetLastRejectedLogByMaterialID(ctx context.Context, materialID string, verifyStatus string) (*daoEntity.MaterialVerifyLog, error) {
|
||||||
|
var result daoEntity.MaterialVerifyLog
|
||||||
|
r, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.MaterialID, materialID).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.VerifyStatus, verifyStatus).
|
||||||
|
OrderDesc(daoEntity.MaterialVerifyLogCols.CreatedAt).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRiskDescription 更新风险描述
|
||||||
|
func (d *MaterialVerifyLogDAO) UpdateRiskDescription(ctx context.Context, id int64, riskDescription string) error {
|
||||||
|
_, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.Id, id).
|
||||||
|
Data(g.Map{
|
||||||
|
daoEntity.MaterialVerifyLogCols.RiskDescription: riskDescription,
|
||||||
|
}).Update()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "更新风险描述失败: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountPendingResults 统计待查询结果的数量
|
||||||
|
func (d *MaterialVerifyLogDAO) CountPendingResults(ctx context.Context) (int, error) {
|
||||||
|
count, err := g.DB("cid").Model(MaterialVerifyLogTable).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.VerifyStatus, daoEntity.VerifyStatusPending).
|
||||||
|
WhereNotNull(daoEntity.MaterialVerifyLogCols.TaskID).
|
||||||
|
Where(daoEntity.MaterialVerifyLogCols.TaskID + " != ''").
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(count), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
consts "cid/consts/check"
|
||||||
|
entity "cid/model/entity/check"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentAccountRelationDAO 腾讯广告账户关系数据访问层
|
||||||
|
type TencentAccountRelationDAO struct{}
|
||||||
|
|
||||||
|
// TencentAccountRelation DAO单例
|
||||||
|
var TencentAccountRelation = new(TencentAccountRelationDAO)
|
||||||
|
|
||||||
|
// GetAll 获取所有启用的账户列表
|
||||||
|
func (d *TencentAccountRelationDAO) GetAll(ctx context.Context) ([]entity.TencentAccountRelation, error) {
|
||||||
|
var result []entity.TencentAccountRelation
|
||||||
|
r, err := Model(consts.TencentAccountRelationTable).
|
||||||
|
WhereNull("deleted_at").
|
||||||
|
OrderAsc(entity.TencentAccountRelationCols.AccountID).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "查询账户关系表失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
g.Log().Errorf(ctx, "转换账户关系数据失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
consts "cid/consts/check"
|
||||||
|
entity "cid/model/entity/check"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/snowflake"
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentContentCheckLogDAO 送检日志数据访问层
|
||||||
|
type TencentContentCheckLogDAO struct{}
|
||||||
|
|
||||||
|
// TencentContentCheckLog 日志DAO单例
|
||||||
|
var TencentContentCheckLog = new(TencentContentCheckLogDAO)
|
||||||
|
|
||||||
|
// Create 创建送检日志
|
||||||
|
func (d *TencentContentCheckLogDAO) Create(ctx context.Context, log *entity.TencentContentCheckLog) (id int64, err error) {
|
||||||
|
// GoFrame v2.10.0 pgsql 驱动不支持 RETURNING/LastInsertId
|
||||||
|
node, err := snowflake.NewNode(1)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "创建Snowflake节点失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
snowflakeID := node.Generate().Int64()
|
||||||
|
|
||||||
|
_, err = g.DB("cid").Model(consts.TencentContentCheckLogTable).Data(g.Map{
|
||||||
|
"id": snowflakeID,
|
||||||
|
"source_table": log.SourceTable,
|
||||||
|
"source_id": log.SourceID,
|
||||||
|
"request_url": log.RequestURL,
|
||||||
|
"request_param": log.RequestParam,
|
||||||
|
"response_data": log.ResponseData,
|
||||||
|
"status": log.Status,
|
||||||
|
"check_time": log.CheckTime,
|
||||||
|
"fail_reason": log.FailReason,
|
||||||
|
"task_id": log.TaskID,
|
||||||
|
"suggestion": log.Suggestion,
|
||||||
|
"label": log.Label,
|
||||||
|
"result_type": log.ResultType,
|
||||||
|
"duration": log.Duration,
|
||||||
|
}).Insert()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "创建送检日志失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return snowflakeID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateStatus 更新送检状态
|
||||||
|
func (d *TencentContentCheckLogDAO) UpdateStatus(ctx context.Context, id int64, status string, responseData string, failReason string) error {
|
||||||
|
_, err := g.DB("cid").Model(consts.TencentContentCheckLogTable).
|
||||||
|
Where("id", id).
|
||||||
|
Data(g.Map{
|
||||||
|
"status": status,
|
||||||
|
"response_data": responseData,
|
||||||
|
"fail_reason": failReason,
|
||||||
|
}).Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateCheckResult 更新检测结果
|
||||||
|
func (d *TencentContentCheckLogDAO) UpdateCheckResult(ctx context.Context, id int64, suggestion, label, resultType int, checkTime int64) error {
|
||||||
|
_, err := g.DB("cid").Model(consts.TencentContentCheckLogTable).
|
||||||
|
Where("id", id).
|
||||||
|
Data(g.Map{
|
||||||
|
"status": consts.CheckStatusCompleted,
|
||||||
|
"suggestion": suggestion,
|
||||||
|
"label": label,
|
||||||
|
"result_type": resultType,
|
||||||
|
"check_time": checkTime,
|
||||||
|
}).Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByID 根据ID获取日志
|
||||||
|
func (d *TencentContentCheckLogDAO) GetByID(ctx context.Context, id int64) (*entity.TencentContentCheckLog, error) {
|
||||||
|
var result entity.TencentContentCheckLog
|
||||||
|
r, err := g.DB("cid").Model(consts.TencentContentCheckLogTable).
|
||||||
|
Where("id", id).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBySourceID 根据来源ID获取日志
|
||||||
|
func (d *TencentContentCheckLogDAO) GetBySourceID(ctx context.Context, sourceTable string, sourceID int64) ([]entity.TencentContentCheckLog, error) {
|
||||||
|
var result []entity.TencentContentCheckLog
|
||||||
|
r, err := g.DB("cid").Model(consts.TencentContentCheckLogTable).
|
||||||
|
Where("source_table", sourceTable).
|
||||||
|
Where("source_id", sourceID).
|
||||||
|
OrderDesc("created_at").
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByTaskID 根据任务ID获取日志
|
||||||
|
func (d *TencentContentCheckLogDAO) GetByTaskID(ctx context.Context, taskID string) (*entity.TencentContentCheckLog, error) {
|
||||||
|
var result entity.TencentContentCheckLog
|
||||||
|
r, err := g.DB("cid").Model(consts.TencentContentCheckLogTable).
|
||||||
|
Where("task_id", taskID).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListByStatus 根据状态获取日志列表
|
||||||
|
func (d *TencentContentCheckLogDAO) ListByStatus(ctx context.Context, status string, page, pageSize int) ([]entity.TencentContentCheckLog, int, error) {
|
||||||
|
var result []entity.TencentContentCheckLog
|
||||||
|
m := g.DB("cid").Model(consts.TencentContentCheckLogTable)
|
||||||
|
|
||||||
|
if status != "" {
|
||||||
|
m.Where("status", status)
|
||||||
|
}
|
||||||
|
|
||||||
|
total, err := m.Count()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := m.
|
||||||
|
OrderDesc("created_at").
|
||||||
|
Page(page, pageSize).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return result, int(total), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateDuration 更新耗时
|
||||||
|
func (d *TencentContentCheckLogDAO) UpdateDuration(ctx context.Context, id int64, duration int64) error {
|
||||||
|
_, err := g.DB("cid").Model(consts.TencentContentCheckLogTable).
|
||||||
|
Where("id", id).
|
||||||
|
Data("duration", duration).
|
||||||
|
Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTaskID 更新任务ID
|
||||||
|
func (d *TencentContentCheckLogDAO) UpdateTaskID(ctx context.Context, id int64, taskID string) error {
|
||||||
|
_, err := g.DB("cid").Model(consts.TencentContentCheckLogTable).
|
||||||
|
Where("id", id).
|
||||||
|
Data("task_id", taskID).
|
||||||
|
Update()
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
consts "cid/consts/check"
|
||||||
|
entity "cid/model/entity/check"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentImageDAO 图片素材数据访问层
|
||||||
|
type TencentImageDAO struct{}
|
||||||
|
|
||||||
|
// TencentImage 图片DAO单例
|
||||||
|
var TencentImage = new(TencentImageDAO)
|
||||||
|
|
||||||
|
// GetPendingList 获取待送检数据列表
|
||||||
|
func (d *TencentImageDAO) GetPendingList(ctx context.Context, limit int) ([]entity.TencentImage, error) {
|
||||||
|
var result []entity.TencentImage
|
||||||
|
r, err := Model(consts.TencentImageTable).
|
||||||
|
Where(entity.TencentImageCols.VerifyStatus, consts.CheckStatusPending).
|
||||||
|
WhereNull("deleted_at").
|
||||||
|
OrderAsc("created_time").
|
||||||
|
Limit(limit).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "查询待送检图片数据失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
g.Log().Errorf(ctx, "转换待送检图片数据失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByImageID 根据图片ID获取数据
|
||||||
|
func (d *TencentImageDAO) GetByImageID(ctx context.Context, imageID string) (*entity.TencentImage, error) {
|
||||||
|
var result entity.TencentImage
|
||||||
|
r, err := Model(consts.TencentImageTable).
|
||||||
|
Where(entity.TencentImageCols.ImageID, imageID).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByID 根据ID获取数据
|
||||||
|
func (d *TencentImageDAO) GetByID(ctx context.Context, id int64) (*entity.TencentImage, error) {
|
||||||
|
var result entity.TencentImage
|
||||||
|
r, err := Model(consts.TencentImageTable).
|
||||||
|
Where(entity.TencentImageCols.Id, id).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountPending 统计待送检数量
|
||||||
|
func (d *TencentImageDAO) CountPending(ctx context.Context) (int, error) {
|
||||||
|
count, err := Model(consts.TencentImageTable).
|
||||||
|
Where(entity.TencentImageCols.VerifyStatus, consts.CheckStatusPending).
|
||||||
|
WhereNull("deleted_at").
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计待送检图片数量失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(count), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountByStatus 根据状态统计数量
|
||||||
|
func (d *TencentImageDAO) CountByStatus(ctx context.Context, status string) (int, error) {
|
||||||
|
count, err := Model(consts.TencentImageTable).
|
||||||
|
Where(entity.TencentImageCols.VerifyStatus, status).
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(count), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByCondition 根据条件获取数据列表
|
||||||
|
func (d *TencentImageDAO) GetByCondition(ctx context.Context, condition map[string]interface{}, page, pageSize int) ([]entity.TencentImage, int, error) {
|
||||||
|
var result []entity.TencentImage
|
||||||
|
model := Model(consts.TencentImageTable)
|
||||||
|
|
||||||
|
for k, v := range condition {
|
||||||
|
model = model.Where(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
total, err := model.Count()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := model.
|
||||||
|
OrderDesc(entity.TencentImageCols.CreatedTime).
|
||||||
|
Page(page, pageSize).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return result, int(total), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClaimPending 原子地尝试将图片从 PENDING 状态转为 SUBMITTING
|
||||||
|
// 返回 true 表示成功抢到处理权,false 表示已被其他进程处理
|
||||||
|
func (d *TencentImageDAO) ClaimPending(ctx context.Context, id int64) (bool, error) {
|
||||||
|
result, err := Model(consts.TencentImageTable).
|
||||||
|
Where(entity.TencentImageCols.Id, id).
|
||||||
|
Where(entity.TencentImageCols.VerifyStatus, consts.CheckStatusPending).
|
||||||
|
Data(entity.TencentImageCols.VerifyStatus, consts.CheckStatusSubmitting).
|
||||||
|
Update()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "原子认领图片送检失败: %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
affected, _ := result.RowsAffected()
|
||||||
|
return affected > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateStatus 更新图片校验状态
|
||||||
|
func (d *TencentImageDAO) UpdateStatus(ctx context.Context, id int64, verifyStatus string) (int64, error) {
|
||||||
|
result, err := Model(consts.TencentImageTable).
|
||||||
|
Where(entity.TencentImageCols.Id, id).
|
||||||
|
Data(entity.TencentImageCols.VerifyStatus, verifyStatus).
|
||||||
|
Update()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "更新图片校验状态失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
affected, _ := result.RowsAffected()
|
||||||
|
return affected, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
consts "cid/consts/check"
|
||||||
|
entity "cid/model/entity/check"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentVideoDAO 视频素材数据访问层
|
||||||
|
type TencentVideoDAO struct{}
|
||||||
|
|
||||||
|
// TencentVideo 视频DAO单例
|
||||||
|
var TencentVideo = new(TencentVideoDAO)
|
||||||
|
|
||||||
|
// GetPendingList 获取待送检数据列表
|
||||||
|
func (d *TencentVideoDAO) GetPendingList(ctx context.Context, limit int) ([]entity.TencentVideo, error) {
|
||||||
|
var result []entity.TencentVideo
|
||||||
|
r, err := Model(consts.TencentVideoTable).
|
||||||
|
Where(entity.TencentVideoCols.VerifyStatus, consts.CheckStatusPending).
|
||||||
|
WhereNull("deleted_at").
|
||||||
|
OrderAsc("created_time").
|
||||||
|
Limit(limit).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "查询待送检视频数据失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
g.Log().Errorf(ctx, "转换待送检视频数据失败: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByVideoID 根据视频ID获取数据
|
||||||
|
func (d *TencentVideoDAO) GetByVideoID(ctx context.Context, videoID string) (*entity.TencentVideo, error) {
|
||||||
|
var result entity.TencentVideo
|
||||||
|
r, err := Model(consts.TencentVideoTable).
|
||||||
|
Where(entity.TencentVideoCols.VideoID, videoID).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByID 根据ID获取数据
|
||||||
|
func (d *TencentVideoDAO) GetByID(ctx context.Context, id int64) (*entity.TencentVideo, error) {
|
||||||
|
var result entity.TencentVideo
|
||||||
|
r, err := Model(consts.TencentVideoTable).
|
||||||
|
Where(entity.TencentVideoCols.Id, id).
|
||||||
|
One()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if r.IsEmpty() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if err = r.Struct(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountPending 统计待送检数量
|
||||||
|
func (d *TencentVideoDAO) CountPending(ctx context.Context) (int, error) {
|
||||||
|
count, err := Model(consts.TencentVideoTable).
|
||||||
|
Where(entity.TencentVideoCols.VerifyStatus, consts.CheckStatusPending).
|
||||||
|
WhereNull("deleted_at").
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "统计待送检视频数量失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(count), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountByStatus 根据状态统计数量
|
||||||
|
func (d *TencentVideoDAO) CountByStatus(ctx context.Context, status string) (int, error) {
|
||||||
|
count, err := Model(consts.TencentVideoTable).
|
||||||
|
Where(entity.TencentVideoCols.VerifyStatus, status).
|
||||||
|
Count()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(count), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByCondition 根据条件获取数据列表
|
||||||
|
func (d *TencentVideoDAO) GetByCondition(ctx context.Context, condition map[string]interface{}, page, pageSize int) ([]entity.TencentVideo, int, error) {
|
||||||
|
var result []entity.TencentVideo
|
||||||
|
model := Model(consts.TencentVideoTable)
|
||||||
|
|
||||||
|
for k, v := range condition {
|
||||||
|
model = model.Where(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
total, err := model.Count()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := model.
|
||||||
|
OrderDesc(entity.TencentVideoCols.CreatedTime).
|
||||||
|
Page(page, pageSize).
|
||||||
|
All()
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if err = r.Structs(&result); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return result, int(total), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClaimPending 原子地尝试将视频从 PENDING 状态转为 SUBMITTING
|
||||||
|
// 返回 true 表示成功抢到处理权,false 表示已被其他进程处理
|
||||||
|
func (d *TencentVideoDAO) ClaimPending(ctx context.Context, id int64) (bool, error) {
|
||||||
|
result, err := Model(consts.TencentVideoTable).
|
||||||
|
Where(entity.TencentVideoCols.Id, id).
|
||||||
|
Where(entity.TencentVideoCols.VerifyStatus, consts.CheckStatusPending).
|
||||||
|
Data(entity.TencentVideoCols.VerifyStatus, consts.CheckStatusSubmitting).
|
||||||
|
Update()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "原子认领视频送检失败: %v", err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
affected, _ := result.RowsAffected()
|
||||||
|
return affected > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateStatus 更新视频校验状态
|
||||||
|
func (d *TencentVideoDAO) UpdateStatus(ctx context.Context, id int64, verifyStatus string) (int64, error) {
|
||||||
|
result, err := Model(consts.TencentVideoTable).
|
||||||
|
Where(entity.TencentVideoCols.Id, id).
|
||||||
|
Data(entity.TencentVideoCols.VerifyStatus, verifyStatus).
|
||||||
|
Update()
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "更新视频校验状态失败: %v", err)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
affected, _ := result.RowsAffected()
|
||||||
|
return affected, nil
|
||||||
|
}
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"gitea.com/red-future/common/db/mongo"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var CIDRequest = &cidRequestDao{}
|
|
||||||
|
|
||||||
type cidRequestDao struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create 创建CID请求记录
|
|
||||||
func (d *cidRequestDao) Create(ctx context.Context, request *entity.CidRequest) (id string, err error) {
|
|
||||||
ids, err := mongo.DB().Insert(ctx, []interface{}{request}, entity.CidRequestCollection)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(ids) > 0 {
|
|
||||||
id = ids[0].(string)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHistory 获取CID请求历史
|
|
||||||
func (d *cidRequestDao) GetHistory(ctx context.Context, userId string, page, size int) (list []*entity.CidRequest, total int64, err error) {
|
|
||||||
filter := bson.M{"userId": userId}
|
|
||||||
|
|
||||||
// 分页查询,使用common/mongo的Find方法,自动处理分页、租户等
|
|
||||||
pageBean := &beans.Page{PageNum: int64(page), PageSize: int64(size)}
|
|
||||||
total, err = mongo.DB().Find(ctx, filter, &list, entity.CidRequestCollection, pageBean, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStatistics 获取统计信息
|
|
||||||
func (d *cidRequestDao) GetStatistics(ctx context.Context, userId string) (stats map[string]interface{}, err error) {
|
|
||||||
stats = make(map[string]interface{})
|
|
||||||
|
|
||||||
// 总请求数
|
|
||||||
totalRequests, err := mongo.DB().Count(ctx, bson.M{"userId": userId}, entity.CidRequestCollection)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stats["total_requests"] = totalRequests
|
|
||||||
|
|
||||||
// 成功请求数
|
|
||||||
successfulRequests, err := mongo.DB().Count(ctx, bson.M{"userId": userId, "status": "completed"}, entity.CidRequestCollection)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
stats["successful_requests"] = successfulRequests
|
|
||||||
|
|
||||||
// 平均处理时间需要单独计算,MongoDB聚合查询
|
|
||||||
// 这里简化处理,返回0
|
|
||||||
stats["average_process_time"] = 0
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"gitea.com/red-future/common/db/mongo"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Strategy = &strategyDao{}
|
|
||||||
|
|
||||||
type strategyDao struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByName 根据名称获取策略
|
|
||||||
func (d *strategyDao) GetByName(ctx context.Context, name string) (strategy *entity.Strategy, err error) {
|
|
||||||
err = mongo.DB().FindOne(ctx, bson.M{"name": name}, &strategy, "strategies")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByID 根据ID获取策略
|
|
||||||
func (d *strategyDao) GetByID(ctx context.Context, id string) (strategy *entity.Strategy, err error) {
|
|
||||||
err = mongo.DB().FindOne(ctx, bson.M{"_id": id}, &strategy, "strategies")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetByTenantLevel 根据租户级别获取策略
|
|
||||||
func (d *strategyDao) GetByTenantLevel(ctx context.Context, tenantLevel string) (strategy *entity.Strategy, err error) {
|
|
||||||
err = mongo.DB().FindOne(ctx, bson.M{"tenantLevel": tenantLevel, "status": "active"}, &strategy, "strategies")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create 创建策略
|
|
||||||
func (d *strategyDao) Create(ctx context.Context, strategy *entity.Strategy) (id string, err error) {
|
|
||||||
ids, err := mongo.DB().Insert(ctx, []interface{}{strategy}, "strategies")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(ids) > 0 {
|
|
||||||
id = ids[0].(string)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新策略
|
|
||||||
func (d *strategyDao) Update(ctx context.Context, strategy *entity.Strategy) (affected int64, err error) {
|
|
||||||
result, err := mongo.DB().Update(ctx, bson.M{"_id": strategy.Id}, bson.M{"$set": strategy}, "strategies")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete 删除策略
|
|
||||||
func (d *strategyDao) Delete(ctx context.Context, id string) (affected int64, err error) {
|
|
||||||
count, err := mongo.DB().Delete(ctx, bson.M{"_id": id}, "strategies")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return count, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetList 获取策略列表
|
|
||||||
func (d *strategyDao) GetList(ctx context.Context, page, size int, tenantLevel, status string) (list []*entity.Strategy, total int64, err error) {
|
|
||||||
filter := bson.M{}
|
|
||||||
|
|
||||||
// 筛选条件
|
|
||||||
if tenantLevel != "" {
|
|
||||||
filter["tenantLevel"] = tenantLevel
|
|
||||||
}
|
|
||||||
if status != "" {
|
|
||||||
filter["status"] = status
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取总数
|
|
||||||
total, err = mongo.DB().Count(ctx, filter, "strategies")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页查询,使用common/mongo的Find方法,自动处理分页、租户等
|
|
||||||
pageBean := &beans.Page{PageNum: int64(page), PageSize: int64(size)}
|
|
||||||
total, err = mongo.DB().Find(ctx, filter, &list, "strategies", pageBean, nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -1,34 +1,37 @@
|
|||||||
module cid
|
module cid
|
||||||
|
|
||||||
go 1.25.5
|
go 1.26.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.com/red-future/common v0.0.4
|
gitea.redpowerfuture.com/red-future/common v0.0.29
|
||||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.5
|
github.com/bwmarrin/snowflake v0.3.0
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2
|
||||||
github.com/gogf/gf/v2 v2.9.5
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2
|
||||||
go.mongodb.org/mongo-driver/v2 v2.4.1
|
github.com/gogf/gf/v2 v2.10.2
|
||||||
golang.org/x/net v0.47.0
|
github.com/yidun/yidun-golang-sdk v1.0.38
|
||||||
)
|
)
|
||||||
|
|
||||||
//replace gitea.com/red-future/common => ../common
|
//replace gitea.redpowerfuture.com/red-future/common => ../common
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||||
github.com/armon/go-metrics v0.4.1 // indirect
|
github.com/armon/go-metrics v0.4.1 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
|
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||||
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
|
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
|
||||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.19.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||||
|
github.com/go-ego/gse v1.0.2 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.6 // indirect
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 // indirect
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 // indirect
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 // indirect
|
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
@@ -37,55 +40,63 @@ require (
|
|||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/golang/snappy v1.0.0 // indirect
|
github.com/golang/snappy v1.0.0 // indirect
|
||||||
github.com/google/flatbuffers v1.12.1 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
|
github.com/google/flatbuffers v25.12.19+incompatible // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
|
||||||
github.com/hashicorp/consul/api v1.26.1 // indirect
|
github.com/hashicorp/consul/api v1.33.5 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||||
|
github.com/hashicorp/go-version v1.9.0 // indirect
|
||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
github.com/hashicorp/serf v0.10.1 // indirect
|
github.com/hashicorp/serf v0.10.1 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.6 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
|
github.com/lib/pq v1.12.3 // indirect
|
||||||
github.com/magiconair/properties v1.8.10 // indirect
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.24 // indirect
|
||||||
|
github.com/miekg/dns v1.1.72 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||||
github.com/olekukonko/errors v1.1.0 // indirect
|
github.com/olekukonko/errors v1.3.0 // indirect
|
||||||
github.com/olekukonko/ll v0.0.9 // indirect
|
github.com/olekukonko/ll v0.1.8 // indirect
|
||||||
github.com/olekukonko/tablewriter v1.1.0 // indirect
|
github.com/olekukonko/tablewriter v1.1.4 // indirect
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.12.1 // indirect
|
github.com/r3labs/diff/v2 v2.15.1 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/redis/go-redis/v9 v9.21.0 // indirect
|
||||||
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/tiger1103/gfast-token v1.0.10 // indirect
|
github.com/tiger1103/gfast-token v1.0.10 // indirect
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||||
github.com/xdg-go/scram v1.1.2 // indirect
|
github.com/vcaesar/cedar v0.30.0 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.44.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||||
golang.org/x/crypto v0.44.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae // indirect
|
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect
|
||||||
golang.org/x/sync v0.18.0 // indirect
|
golang.org/x/net v0.56.0 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/sys v0.46.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/text v0.38.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||||
google.golang.org/grpc v1.75.0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||||
google.golang.org/protobuf v1.36.8 // indirect
|
google.golang.org/grpc v1.79.3 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
gitea.com/red-future/common v0.0.2 h1:KjiIyZo0JeSN9ldXofuGkFifJ/H66kTybOU34Yew7R0=
|
gitea.redpowerfuture.com/red-future/common v0.0.29 h1:5McaN5pSewvrLUHQzWMX6EaUvD+B5I5bMYoU+clHJk4=
|
||||||
gitea.com/red-future/common v0.0.2/go.mod h1:CUurYN0elToJTwB2pX9wSnjQqZv9D/Vxbo5ueb7i9BI=
|
gitea.redpowerfuture.com/red-future/common v0.0.29/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY=
|
||||||
gitea.com/red-future/common v0.0.3/go.mod h1:mq4smQZFI5nYul6gvLH7ScnC/26bAOcTvR3hP625NYY=
|
|
||||||
gitea.com/red-future/common v0.0.4/go.mod h1:UI9N5UUjilbMPF7+/lypZSnqDVHigt14300oSRrAyZg=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
@@ -25,6 +23,8 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
|||||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
|
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
|
||||||
|
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
@@ -36,6 +36,10 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
|
|||||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||||
|
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -47,13 +51,11 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa
|
|||||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=
|
||||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
@@ -61,10 +63,12 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||||
|
github.com/go-ego/gse v1.0.2 h1:+27lYFPhQEhA9igtdOsJPRKYL/k3TwYsxBF5jr6KFv4=
|
||||||
|
github.com/go-ego/gse v1.0.2/go.mod h1:Fy35G+q7VV7Et1zIKO8o/sW1kkugV3znXap/lF/11zc=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
@@ -74,19 +78,21 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
|||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
|
||||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.5 h1:0+ZBYhi4sqwxXwL+hIBpp06a7G4m5nmjskQ3NNb8qYc=
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.5/go.mod h1:vyB7J/uJcLCrHD5lfFBzxhEEMkePIRzfhd33EcsuLa0=
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5 h1:Ku7p3CvGchxC7zPSgArf/tZs2w9Yb8tS/gH5ADN+p9g=
|
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5/go.mod h1:cjy18NsSLZQf5zaLAzuo7B2gr8GGjCTWDTEPY7T+6FI=
|
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 h1:u8EpP24GkprogROnJ7htMov9Fc66pTP1eVYrWxiCYOs=
|
||||||
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2/go.mod h1:GmvM3r8GVByVMi4RD2+MCs5+CfxVXPMeT8mVDkAaAXE=
|
||||||
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 h1:iTQegT+lEg/wDKvj2mi3W1wrdrwFarjokf88EXVVgu4=
|
||||||
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2/go.mod h1:ZRw3GNz5cq4uYrW4TPSVyrYWaoqzujKdWro/AOcGBaE=
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 h1:eUqwJ/qNH8lJ6yssiqskazgp1ACQuNU6zXlLOZVuXTQ=
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 h1:eUqwJ/qNH8lJ6yssiqskazgp1ACQuNU6zXlLOZVuXTQ=
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5/go.mod h1:sjQyMry9+0POYZCA6lHXBxO77WoNKkruJpRB4xKqk5k=
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5/go.mod h1:sjQyMry9+0POYZCA6lHXBxO77WoNKkruJpRB4xKqk5k=
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 h1:tHUEZYB5GTqEYYVDYnlGobf1xISARKDE4KHVlgjwTec=
|
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 h1:tHUEZYB5GTqEYYVDYnlGobf1xISARKDE4KHVlgjwTec=
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5/go.mod h1:cfzTn2HS9RDX8f5pUVkbGxUWcSosouqfNQ1G6cY0V88=
|
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5/go.mod h1:cfzTn2HS9RDX8f5pUVkbGxUWcSosouqfNQ1G6cY0V88=
|
||||||
github.com/gogf/gf/v2 v2.9.5 h1:1scfOdHbMP854oQaiLejl+eL+c4xfuvtWmmZiDJxbKs=
|
github.com/gogf/gf/v2 v2.10.2 h1:46IO0Uc8e85/FqdftJFskfDejJLBL0JBnGS5qOftUu8=
|
||||||
github.com/gogf/gf/v2 v2.9.5/go.mod h1:VUb5eyJKpvW77O/dXsbbLNO/Kjrg0UycIiq0lRiBjjo=
|
github.com/gogf/gf/v2 v2.10.2/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
@@ -102,22 +108,24 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
|||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
|
github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs=
|
||||||
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@@ -130,16 +138,16 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
|||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
|
||||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
|
||||||
github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM=
|
github.com/hashicorp/consul/api v1.33.5 h1:Nn6q87zudRU1rLBTJEgaWxz9STCNadilLCD7B8OA5aI=
|
||||||
github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A=
|
github.com/hashicorp/consul/api v1.33.5/go.mod h1:pa6fJOSHKLOzNHpUVeqLDtxA5+J1D7NNzLasuk8eRXA=
|
||||||
github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=
|
github.com/hashicorp/consul/sdk v0.17.3 h1:oZMMxzQGSsiT+ToOH50y3Qcs0nc9Ud+7L5lRx+EmMU0=
|
||||||
github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=
|
github.com/hashicorp/consul/sdk v0.17.3/go.mod h1:jnOmYjiNfVRpBaujQ1DFFVs0N6g3S1y6wygSjLTzYfc=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
@@ -169,11 +177,10 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
|||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
|
||||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
|
||||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||||
@@ -186,8 +193,10 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -197,6 +206,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
|
||||||
|
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
|
||||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
@@ -204,41 +215,44 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
|||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
|
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
|
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||||
|
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=
|
||||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
|
||||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U=
|
||||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||||
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
|
github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8=
|
||||||
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw=
|
||||||
|
github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I=
|
||||||
|
github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
@@ -260,13 +274,12 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
|
|||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
|
github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg=
|
||||||
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/redis/go-redis/v9 v9.21.0 h1:FPBE4hhbAke+TLmcY3WkpbDffJEomdqPn3HYiqAtL9E=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/redis/go-redis/v9 v9.21.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
@@ -274,51 +287,61 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s=
|
github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s=
|
||||||
github.com/tiger1103/gfast-token v1.0.10/go.mod h1:a/21mxmj7zFeNvjhZSC0XpEAFHfb1aT2k6DXnufFU1s=
|
github.com/tiger1103/gfast-token v1.0.10/go.mod h1:a/21mxmj7zFeNvjhZSC0XpEAFHfb1aT2k6DXnufFU1s=
|
||||||
|
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||||
|
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
github.com/vcaesar/cedar v0.30.0 h1:9fSDpM7FTjjUdPiBUUa0MWYMRGSEcqgFXvppZcZ4d7Y=
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
github.com/vcaesar/cedar v0.30.0/go.mod h1:lyuGvALuZZDPNXwpzv/9LyxW+8Y6faN7zauFezNsnik=
|
||||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
|
||||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
github.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=
|
||||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
github.com/yidun/yidun-golang-sdk v1.0.38 h1:4NjQdt2GGMgLToB2+zTA0L4YRpqY3ZQjVpl2ot1gwfk=
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
github.com/yidun/yidun-golang-sdk v1.0.38/go.mod h1:+JGdWbkUvLi9uKTtHI+nrxajulfZKA7BXDPlzt1RCsU=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
||||||
go.mongodb.org/mongo-driver/v2 v2.4.1 h1:hGDMngUao03OVQ6sgV5csk+RWOIkF+CuLsTPobNMGNI=
|
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||||
go.mongodb.org/mongo-driver/v2 v2.4.1/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
go.mongodb.org/mongo-driver/v2 v2.6.0 h1:b9sJOYrkmt4l8bY43ZenFBcPlhYIjaOfYHLtbB/5qi8=
|
||||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
go.mongodb.org/mongo-driver/v2 v2.6.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||||
|
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||||
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@@ -326,36 +349,35 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
|
||||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
|
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M=
|
||||||
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
|
golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY=
|
||||||
golang.org/x/exp v0.0.0-20250128144449-3edf0e91c1ae/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||||
|
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -364,9 +386,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -385,27 +406,20 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@@ -415,7 +429,8 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk=
|
||||||
|
golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -424,20 +439,24 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
|
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
|
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||||
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -447,8 +466,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -1,30 +1,137 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cid/controller"
|
"cid/controller/check"
|
||||||
|
serviceYidun "cid/service/check"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
_ "gitea.com/red-future/common/db/mongo"
|
_ "gitea.redpowerfuture.com/red-future/common/consul"
|
||||||
"gitea.com/red-future/common/http"
|
"gitea.redpowerfuture.com/red-future/common/http"
|
||||||
"gitea.com/red-future/common/jaeger"
|
"gitea.redpowerfuture.com/red-future/common/jaeger"
|
||||||
_ "gitea.com/red-future/common/ragflow" // RAGFlow 客户端自动初始化
|
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
|
||||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
|
||||||
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
||||||
"golang.org/x/net/context"
|
"github.com/gogf/gf/v2/frame/g"
|
||||||
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
defer jaeger.ShutDown(ctx)
|
defer jaeger.ShutDown(ctx)
|
||||||
|
|
||||||
|
// 设置时区为东八区
|
||||||
|
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||||
|
if err == nil {
|
||||||
|
time.Local = loc
|
||||||
|
}
|
||||||
|
// 关键:设置 PGTZ 环境变量,lib/pq 驱动在连接 pg 时会自动设置 session timezone
|
||||||
|
// 确保从数据库读取 TIMESTAMPTZ 时返回的是东八区时间,gtime.Time 序列化输出北京时间
|
||||||
|
os.Setenv("PGTZ", "Asia/Shanghai")
|
||||||
|
|
||||||
|
// 初始化易盾客户端
|
||||||
|
if err := serviceYidun.InitYidunClients(ctx); err != nil {
|
||||||
|
panic(fmt.Sprintf("初始化易盾客户端失败: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Log().Info(ctx, "易盾客户端初始化成功")
|
||||||
|
|
||||||
|
// 启动内容送检定时任务
|
||||||
|
startContentCheckService(ctx)
|
||||||
|
|
||||||
|
// 获取前端目录
|
||||||
|
frontendDir := getFrontendDir()
|
||||||
|
|
||||||
|
// 注册前端静态文件路由(在使用 http.Httpserver 之前)
|
||||||
|
registerFrontendRoutes(frontendDir)
|
||||||
|
|
||||||
|
// 注册 API 路由并启动服务器
|
||||||
http.RouteRegister([]interface{}{
|
http.RouteRegister([]interface{}{
|
||||||
controller.AdSource,
|
check.YidunController,
|
||||||
controller.CID,
|
check.YidunCallback,
|
||||||
controller.Strategy,
|
check.ContentCheck,
|
||||||
controller.Advertisement,
|
check.MaterialVerify,
|
||||||
controller.Advertiser,
|
|
||||||
controller.AdPosition,
|
|
||||||
controller.RateLimit,
|
|
||||||
controller.Application,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 打印前端访问地址
|
||||||
|
port := g.Cfg().MustGet(ctx, "server.address", ":3001").String()
|
||||||
|
g.Log().Info(ctx, "============================================")
|
||||||
|
g.Log().Infof(ctx, "🌐 前端访问地址: http://localhost%s", port)
|
||||||
|
g.Log().Info(ctx, "============================================")
|
||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getFrontendDir 获取前端目录路径
|
||||||
|
func getFrontendDir() string {
|
||||||
|
execPath, _ := os.Executable()
|
||||||
|
execDir := filepath.Dir(execPath)
|
||||||
|
frontendDir := filepath.Join(execDir, "resource", "frontend")
|
||||||
|
|
||||||
|
if _, err := os.Stat(frontendDir); os.IsNotExist(err) {
|
||||||
|
cwd, _ := os.Getwd()
|
||||||
|
frontendDir = filepath.Join(cwd, "resource", "frontend")
|
||||||
|
}
|
||||||
|
|
||||||
|
return frontendDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerFrontendRoutes 注册前端静态文件路由
|
||||||
|
func registerFrontendRoutes(frontendDir string) {
|
||||||
|
if _, err := os.Stat(frontendDir); os.IsNotExist(err) {
|
||||||
|
g.Log().Warningf(context.Background(), "前端目录不存在: %s", frontendDir)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s := http.Httpserver
|
||||||
|
|
||||||
|
// 静态资源路由
|
||||||
|
s.BindHandler("/frontend/{file}", func(r *ghttp.Request) {
|
||||||
|
file := r.Get("file").String()
|
||||||
|
filePath := filepath.Join(frontendDir, file)
|
||||||
|
if _, err := os.Stat(filePath); err == nil {
|
||||||
|
r.Response.ServeFile(filePath)
|
||||||
|
} else {
|
||||||
|
r.Response.WriteStatus(404)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 首页/主入口
|
||||||
|
s.BindHandler("/", func(r *ghttp.Request) {
|
||||||
|
indexFile := filepath.Join(frontendDir, "material-verify.html")
|
||||||
|
if _, err := os.Stat(indexFile); err == nil {
|
||||||
|
r.Response.ServeFile(indexFile)
|
||||||
|
} else {
|
||||||
|
r.Response.Write("<html><body><h1>CID Backend Service</h1><p>前端页面未找到</p></body></html>")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// startContentCheckService 启动内容送检服务
|
||||||
|
func startContentCheckService(ctx context.Context) {
|
||||||
|
// 检查是否启用定时送检任务
|
||||||
|
schedulerEnabled := g.Cfg().MustGet(ctx, "content_check.scheduler_enabled", true).Bool()
|
||||||
|
if !schedulerEnabled {
|
||||||
|
g.Log().Info(ctx, "定时送检任务已禁用(scheduler_enabled=false),仅支持API手动送检")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 配置送检服务参数
|
||||||
|
config := serviceYidun.ContentCheckConfig{
|
||||||
|
BatchSize: g.Cfg().MustGet(ctx, "content_check.batch_size", 10).Int(),
|
||||||
|
ImageEnabled: g.Cfg().MustGet(ctx, "content_check.image_enabled", true).Bool(),
|
||||||
|
VideoEnabled: g.Cfg().MustGet(ctx, "content_check.video_enabled", true).Bool(),
|
||||||
|
IntervalSeconds: g.Cfg().MustGet(ctx, "content_check.interval_seconds", 30).Int(),
|
||||||
|
PollInterval: g.Cfg().MustGet(ctx, "content_check.poll_interval", 60).Int(),
|
||||||
|
}
|
||||||
|
serviceYidun.TencentContentCheck.SetConfig(config)
|
||||||
|
|
||||||
|
// 启动服务
|
||||||
|
if err := serviceYidun.TencentContentCheck.Start(ctx); err != nil {
|
||||||
|
g.Log().Errorf(ctx, "启动内容送检服务失败: %v", err)
|
||||||
|
} else {
|
||||||
|
g.Log().Info(ctx, "内容送检服务启动成功")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,231 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/consts"
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BaseConfig 基础配置结构
|
|
||||||
type BaseConfig struct {
|
|
||||||
// 优先级和权重
|
|
||||||
Priority int `bson:"priority" json:"priority"` // 优先级
|
|
||||||
Weight float64 `bson:"weight" json:"weight"` // 权重
|
|
||||||
Order int `bson:"order" json:"order"` // 排序顺序
|
|
||||||
|
|
||||||
// 标签和分类
|
|
||||||
Tags []string `bson:"tags" json:"tags"` // 标签
|
|
||||||
Category string `bson:"category" json:"category"` // 分类
|
|
||||||
Industry string `bson:"industry" json:"industry"` // 行业
|
|
||||||
|
|
||||||
// 配置信息
|
|
||||||
Config string `bson:"config" json:"config"` // 配置信息(JSON格式)
|
|
||||||
Extra map[string]interface{} `bson:"extra" json:"extra"` // 扩展字段
|
|
||||||
Remark string `bson:"remark" json:"remark"` // 备注
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate 基础配置验证
|
|
||||||
func (c *BaseConfig) Validate() error {
|
|
||||||
if c.Priority < 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.Weight < 0 || c.Weight > 1 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BiddingConfig 竞价配置
|
|
||||||
type BiddingConfig struct {
|
|
||||||
// 竞价类型
|
|
||||||
BiddingType string `bson:"biddingType" json:"biddingType"` // 竞价类型:cpm、cpc、cpa、rtb
|
|
||||||
BiddingStrategy string `bson:"biddingStrategy" json:"biddingStrategy"` // 出价策略:manual、auto、target_cpa、target_roas等
|
|
||||||
|
|
||||||
// 出价范围
|
|
||||||
MinBidAmount int64 `bson:"minBidAmount" json:"minBidAmount"` // 最小出价(分)
|
|
||||||
MaxBidAmount int64 `bson:"maxBidAmount" json:"maxBidAmount"` // 最大出价(分)
|
|
||||||
DefaultBidAmount int64 `bson:"defaultBidAmount" json:"defaultBidAmount"` // 默认出价(分)
|
|
||||||
BidIncrement int64 `bson:"bidIncrement" json:"bidIncrement"` // 出价增量(分)
|
|
||||||
|
|
||||||
// 自动优化
|
|
||||||
AutoOptimization bool `bson:"autoOptimization" json:"autoOptimization"` // 是否自动优化
|
|
||||||
TargetCPA int64 `bson:"targetCPA" json:"targetCPA"` // 目标CPA(分)
|
|
||||||
TargetROAS float64 `bson:"targetROAS" json:"targetROAS"` // 目标ROAS
|
|
||||||
OptimizationGoal string `bson:"optimizationGoal" json:"optimizationGoal"` // 优化目标:impressions、clicks、conversions、revenue等
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate 竞价配置验证
|
|
||||||
func (c *BiddingConfig) Validate() error {
|
|
||||||
if c.MinBidAmount < 0 || c.MaxBidAmount < 0 || c.DefaultBidAmount < 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.MinBidAmount > c.MaxBidAmount {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.TargetROAS < 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BudgetConfig 预算配置
|
|
||||||
type BudgetConfig struct {
|
|
||||||
// 预算设置
|
|
||||||
TotalBudget int64 `bson:"totalBudget" json:"totalBudget"` // 总预算(分)
|
|
||||||
DailyBudget int64 `bson:"dailyBudget" json:"dailyBudget"` // 日预算(分)
|
|
||||||
|
|
||||||
// 投放节奏
|
|
||||||
PaceType string `bson:"paceType" json:"paceType"` // 投放节奏:even、accelerated、standard
|
|
||||||
IsBudgetPacing bool `bson:"isBudgetPacing" json:"isBudgetPacing"` // 是否预算匀速投放
|
|
||||||
|
|
||||||
// 时间配置
|
|
||||||
StartDate int64 `bson:"startDate" json:"startDate"` // 开始投放时间
|
|
||||||
EndDate int64 `bson:"endDate" json:"endDate"` // 结束投放时间
|
|
||||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate 预算配置验证
|
|
||||||
func (c *BudgetConfig) Validate() error {
|
|
||||||
if c.TotalBudget < 0 || c.DailyBudget < 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.StartDate > c.EndDate {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIConfig API配置
|
|
||||||
type APIConfig struct {
|
|
||||||
// 基础配置
|
|
||||||
Endpoint string `bson:"endpoint" json:"endpoint"` // API端点
|
|
||||||
Version string `bson:"version" json:"version"` // API版本
|
|
||||||
Timeout int `bson:"timeout" json:"timeout"` // 超时时间(毫秒)
|
|
||||||
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
|
|
||||||
|
|
||||||
// 认证配置
|
|
||||||
AuthType string `bson:"authType" json:"authType"` // 认证类型:api_key、oauth、basic
|
|
||||||
AuthConfig string `bson:"authConfig" json:"authConfig"` // 认证配置(JSON字符串)
|
|
||||||
|
|
||||||
// 请求配置
|
|
||||||
Headers string `bson:"headers" json:"headers"` // 请求头配置(JSON字符串)
|
|
||||||
|
|
||||||
// 限流配置
|
|
||||||
RateLimit int64 `bson:"rateLimit" json:"rateLimit"` // 速率限制
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate API配置验证
|
|
||||||
func (c *APIConfig) Validate() error {
|
|
||||||
if c.Timeout <= 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.RetryCount < 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.RateLimit <= 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreativeConfig 创意配置
|
|
||||||
type CreativeConfig struct {
|
|
||||||
// 轮播设置
|
|
||||||
CreativeRotation string `bson:"creativeRotation" json:"creativeRotation"` // 创意轮播方式:optimize、even、random
|
|
||||||
SelectedCreatives []string `bson:"selectedCreatives" json:"selectedCreatives"` // 选中的创意列表
|
|
||||||
ExcludedCreatives []string `bson:"excludedCreatives" json:"excludedCreatives"` // 排除的创意列表
|
|
||||||
|
|
||||||
// 技术要求
|
|
||||||
MaxFileSize int64 `bson:"maxFileSize" json:"maxFileSize"` // 最大文件大小(bytes)
|
|
||||||
MaxDuration int64 `bson:"maxDuration" json:"maxDuration"` // 最大时长(秒)
|
|
||||||
|
|
||||||
// 支持的格式
|
|
||||||
SupportedFormats []string `bson:"supportedFormats" json:"supportedFormats"` // 支持的格式
|
|
||||||
SupportedSizes []string `bson:"supportedSizes" json:"supportedSizes"` // 支持的尺寸
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate 创意配置验证
|
|
||||||
func (c *CreativeConfig) Validate() error {
|
|
||||||
if c.MaxFileSize <= 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.MaxDuration <= 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PaymentConfig 支付配置
|
|
||||||
type PaymentConfig struct {
|
|
||||||
// 计费模式
|
|
||||||
BillingModel string `bson:"billingModel" json:"billingModel"` // 计费模式:CPC、CPM、CPA等
|
|
||||||
CommissionRate float64 `bson:"commissionRate" json:"commissionRate"` // 佣金比例
|
|
||||||
MinimumBudget int64 `bson:"minimumBudget" json:"minimumBudget"` // 最低预算(分)
|
|
||||||
|
|
||||||
// 结算配置
|
|
||||||
SettlementCycle string `bson:"settlementCycle" json:"settlementCycle"` // 结算周期:daily、weekly、monthly
|
|
||||||
PaymentTerms string `bson:"paymentTerms" json:"paymentTerms"` // 支付条款
|
|
||||||
Currency string `bson:"currency" json:"currency"` // 货币单位
|
|
||||||
|
|
||||||
// 收入分成
|
|
||||||
RevShareRate float64 `bson:"revShareRate" json:"revShareRate"` // 收入分成比例(0-1)
|
|
||||||
MinPayment int64 `bson:"minPayment" json:"minPayment"` // 最小支付金额(分)
|
|
||||||
TaxInclusive bool `bson:"taxInclusive" json:"taxInclusive"` // 是否含税
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate 支付配置验证
|
|
||||||
func (c *PaymentConfig) Validate() error {
|
|
||||||
if c.CommissionRate < 0 || c.CommissionRate > 1 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.RevShareRate < 0 || c.RevShareRate > 1 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.MinimumBudget < 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
if c.MinPayment < 0 {
|
|
||||||
return errors.New(consts.ErrInvalidConfiguration)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FrequencyCapConfig 频次控制配置
|
|
||||||
type FrequencyCapConfig struct {
|
|
||||||
// 频次限制
|
|
||||||
Impressions int `bson:"impressions" json:"impressions"` // 展示次数
|
|
||||||
TimeWindow int `bson:"timeWindow" json:"timeWindow"` // 时间窗口(小时)
|
|
||||||
PerUser int `bson:"perUser" json:"perUser"` // 每用户频次
|
|
||||||
PerHour int `bson:"perHour" json:"perHour"` // 每小时频次
|
|
||||||
PerDay int `bson:"perDay" json:"perDay"` // 每日频次
|
|
||||||
|
|
||||||
// 频次控制规则
|
|
||||||
CapType string `bson:"capType" json:"capType"` // 频次类型:lifetime、daily、hourly
|
|
||||||
CapScope string `bson:"capScope" json:"capScope"` // 频次范围:user、device、ip
|
|
||||||
ResetRule string `bson:"resetRule" json:"resetRule"` // 重置规则:daily、weekly、monthly
|
|
||||||
}
|
|
||||||
|
|
||||||
// RestrictionConfig 限制配置
|
|
||||||
type RestrictionConfig struct {
|
|
||||||
// 年龄限制
|
|
||||||
AgeRestriction bool `bson:"ageRestriction" json:"ageRestriction"` // 年龄限制
|
|
||||||
MinAge int `bson:"minAge" json:"minAge"` // 最小年龄
|
|
||||||
MaxAge int `bson:"maxAge" json:"maxAge"` // 最大年龄
|
|
||||||
|
|
||||||
// 地域限制
|
|
||||||
GeoRestrictions []string `bson:"geoRestrictions" json:"geoRestrictions"` // 地域限制
|
|
||||||
|
|
||||||
// 设备限制
|
|
||||||
DeviceRestrictions []string `bson:"deviceRestrictions" json:"deviceRestrictions"` // 设备限制
|
|
||||||
|
|
||||||
// 分类限制
|
|
||||||
CategoryRestrictions []string `bson:"categoryRestrictions" json:"categoryRestrictions"` // 分类限制
|
|
||||||
|
|
||||||
// 内容限制
|
|
||||||
ContentRestrictions []string `bson:"contentRestrictions" json:"contentRestrictions"` // 内容限制
|
|
||||||
|
|
||||||
// 品牌安全
|
|
||||||
BrandSafety bool `bson:"brandSafety" json:"brandSafety"` // 品牌安全
|
|
||||||
BlockedCategories []string `bson:"blockedCategories" json:"blockedCategories"` // 阻止的分类
|
|
||||||
AllowedCategories []string `bson:"allowedCategories" json:"allowedCategories"` // 允许的分类
|
|
||||||
ExcludedKeywords []string `bson:"excludedKeywords" json:"excludedKeywords"` // 排除的关键词
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddAdPositionReq 添加广告位请求
|
|
||||||
type AddAdPositionReq struct {
|
|
||||||
g.Meta `path:"/add" method:"post" tags:"广告位管理" summary:"添加广告位" dc:"添加新的广告位"`
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `json:"name" v:"required"` // 广告位名称
|
|
||||||
Description string `json:"description"` // 广告位描述
|
|
||||||
PositionCode string `json:"positionCode" v:"required"` // 广告位编码,用于标识
|
|
||||||
AdFormat string `json:"adFormat" v:"required"` // 支持的广告格式
|
|
||||||
|
|
||||||
// 尺寸信息
|
|
||||||
Width int `json:"width" v:"required"` // 宽度(px)
|
|
||||||
Height int `json:"height" v:"required"` // 高度(px)
|
|
||||||
|
|
||||||
// 位置信息
|
|
||||||
Page string `json:"page" v:"required"` // 所属页面
|
|
||||||
Section string `json:"section" v:"required"` // 页面区域
|
|
||||||
Location string `json:"location" v:"required"` // 具体位置
|
|
||||||
|
|
||||||
// 展示设置
|
|
||||||
MaxAds int `json:"maxAds"` // 最大广告数量
|
|
||||||
RefreshInterval int `json:"refreshInterval"` // 刷新间隔(秒)
|
|
||||||
IsLazyLoad bool `json:"isLazyLoad"` // 是否懒加载
|
|
||||||
|
|
||||||
// 定价设置
|
|
||||||
PricingModel string `json:"pricingModel" v:"required"` // 计费模型:CPC、CPM、CPA等
|
|
||||||
BasePrice int64 `json:"basePrice" v:"required"` // 基础价格(分)
|
|
||||||
FloorPrice int64 `json:"floorPrice" v:"required"` // 底价(分)
|
|
||||||
PriceUnit string `json:"priceUnit" v:"required"` // 价格单位:千次展示、单次点击、单次转化等
|
|
||||||
|
|
||||||
// 展示规则
|
|
||||||
DisplayRules *entity.DisplayRules `json:"displayRules"` // 展示规则
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
Status string `json:"status" v:"required"` // 广告位状态:启用、禁用、测试
|
|
||||||
IsExclusive bool `json:"isExclusive"` // 是否独占广告位
|
|
||||||
}
|
|
||||||
|
|
||||||
type AddAdPositionRes struct {
|
|
||||||
Id *bson.ObjectID `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdPositionReq 更新广告位请求
|
|
||||||
type UpdateAdPositionReq struct {
|
|
||||||
g.Meta `path:"/update" method:"put" tags:"广告位管理" summary:"更新广告位" dc:"更新广告位信息"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // ID
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `json:"name"` // 广告位名称
|
|
||||||
Description string `json:"description"` // 广告位描述
|
|
||||||
PositionCode string `json:"positionCode"` // 广告位编码,用于标识
|
|
||||||
AdFormat string `json:"adFormat"` // 支持的广告格式
|
|
||||||
|
|
||||||
// 尺寸信息
|
|
||||||
Width *int `json:"width"` // 宽度(px)
|
|
||||||
Height *int `json:"height"` // 高度(px)
|
|
||||||
|
|
||||||
// 位置信息
|
|
||||||
Page string `json:"page"` // 所属页面
|
|
||||||
Section string `json:"section"` // 页面区域
|
|
||||||
Location string `json:"location"` // 具体位置
|
|
||||||
|
|
||||||
// 展示设置
|
|
||||||
MaxAds *int `json:"maxAds"` // 最大广告数量
|
|
||||||
RefreshInterval *int `json:"refreshInterval"` // 刷新间隔(秒)
|
|
||||||
IsLazyLoad *bool `json:"isLazyLoad"` // 是否懒加载
|
|
||||||
|
|
||||||
// 定价设置
|
|
||||||
PricingModel string `json:"pricingModel"` // 计费模型:CPC、CPM、CPA等
|
|
||||||
BasePrice *int64 `json:"basePrice"` // 基础价格(分)
|
|
||||||
FloorPrice *int64 `json:"floorPrice"` // 底价(分)
|
|
||||||
PriceUnit string `json:"priceUnit"` // 价格单位:千次展示、单次点击、单次转化等
|
|
||||||
|
|
||||||
// 展示规则
|
|
||||||
DisplayRules *entity.DisplayRules `json:"displayRules"` // 展示规则
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
Status *string `json:"status"` // 广告位状态:启用、禁用、测试
|
|
||||||
IsExclusive *bool `json:"isExclusive"` // 是否独占广告位
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAdPositionReq 获取广告位详情请求
|
|
||||||
type GetAdPositionReq struct {
|
|
||||||
g.Meta `path:"/one" method:"get" tags:"广告位管理" summary:"获取广告位详情" dc:"根据ID获取单个广告位详情"`
|
|
||||||
Id string `json:"id" v:"required"` // ID
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetAdPositionRes struct {
|
|
||||||
*entity.AdPosition
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListAdPositionReq 获取广告位列表请求
|
|
||||||
type ListAdPositionReq struct {
|
|
||||||
g.Meta `path:"/list" method:"get" tags:"广告位管理" summary:"获取广告位列表" dc:"分页查询广告位列表,支持多条件筛选"`
|
|
||||||
*beans.Page
|
|
||||||
|
|
||||||
Name string `json:"name"` // 广告位名称模糊查询
|
|
||||||
PositionCode string `json:"positionCode"` // 广告位编码
|
|
||||||
PageName string `json:"pageName"` // 所属页面
|
|
||||||
Section string `json:"section"` // 页面区域
|
|
||||||
Status string `json:"status"` // 广告位状态
|
|
||||||
AdFormat string `json:"adFormat"` // 广告格式
|
|
||||||
DateRange []string `json:"dateRange"` // 创建时间范围 [start, end]
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListAdPositionRes struct {
|
|
||||||
List []*entity.AdPosition `json:"list"`
|
|
||||||
Total int `json:"total"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdPositionStatusReq 更新广告位状态请求
|
|
||||||
type UpdateAdPositionStatusReq struct {
|
|
||||||
g.Meta `path:"/updateStatus" method:"patch" tags:"广告位管理" summary:"更新广告位状态" dc:"更新广告位状态"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告位ID
|
|
||||||
Status string `json:"status" v:"required"` // 广告位状态:启用、禁用、测试
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAvailableAdPositionsReq 获取可用广告位请求
|
|
||||||
type GetAvailableAdPositionsReq struct {
|
|
||||||
g.Meta `path:"/getAvailableAdPositions" method:"get" tags:"广告位管理" summary:"获取可用广告位列表" dc:"获取所有启用的广告位列表"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetAvailableAdPositionsRes struct {
|
|
||||||
List []*entity.AdPosition `json:"list"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchAdReq 匹配广告请求
|
|
||||||
type MatchAdReq struct {
|
|
||||||
g.Meta `path:"/matchAd" method:"post" tags:"广告位管理" summary:"匹配广告" dc:"根据广告位编码和用户信息匹配适合的广告"`
|
|
||||||
|
|
||||||
PositionCode string `json:"positionCode" v:"required"` // 广告位编码
|
|
||||||
UserInfo map[string]interface{} `json:"userInfo"` // 用户信息
|
|
||||||
}
|
|
||||||
|
|
||||||
type MatchAdRes struct {
|
|
||||||
*entity.Advertisement `json:"advertisement"`
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateAdSourceReq 创建广告源请求
|
|
||||||
type CreateAdSourceReq struct {
|
|
||||||
g.Meta `path:"/create" method:"post" tags:"广告源管理" summary:"创建广告源" dc:"创建新的广告源配置"`
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `json:"name" v:"required"` // 广告源名称
|
|
||||||
Code string `json:"code" v:"required"` // 广告源编码,唯一标识
|
|
||||||
Provider string `json:"provider" v:"required"` // 提供商:google、facebook、baidu、tencent、self等
|
|
||||||
Type string `json:"type" v:"required|in:self,third_party,exchange"` // 类型
|
|
||||||
Description string `json:"description"` // 描述
|
|
||||||
|
|
||||||
// 连接配置
|
|
||||||
APIEndpoint string `json:"apiEndpoint" v:"required"` // API端点
|
|
||||||
APIVersion string `json:"apiVersion"` // API版本
|
|
||||||
AuthType string `json:"authType" v:"required|in:api_key,oauth,basic"` // 认证类型
|
|
||||||
AuthConfig map[string]interface{} `json:"authConfig" v:"required"` // 认证配置
|
|
||||||
Headers map[string]string `json:"headers"` // 请求头配置
|
|
||||||
Timeout int `json:"timeout"` // 超时时间(毫秒)
|
|
||||||
RetryCount int `json:"retryCount"` // 重试次数
|
|
||||||
|
|
||||||
// 基础配置
|
|
||||||
SupportedFormats []string `json:"supportedFormats" v:"required"` // 支持的广告格式
|
|
||||||
SupportedSizes []string `json:"supportedSizes"` // 支持的尺寸
|
|
||||||
SupportedDevices []string `json:"supportedDevices"` // 支持的设备类型
|
|
||||||
SupportedOS []string `json:"supportedOS"` // 支持的操作系统
|
|
||||||
SupportedCountries []string `json:"supportedCountries"` // 支持的国家/地区
|
|
||||||
|
|
||||||
// 竞价配置
|
|
||||||
BiddingType string `json:"biddingType" v:"required|in:cpm,cpc,cpa,rtb"` // 竞价类型
|
|
||||||
MinBidAmount int64 `json:"minBidAmount"` // 最小出价(分)
|
|
||||||
MaxBidAmount int64 `json:"maxBidAmount"` // 最大出价(分)
|
|
||||||
BidIncrement int64 `json:"bidIncrement"` // 出价增量(分)
|
|
||||||
DefaultBidAmount int64 `json:"defaultBidAmount"` // 默认出价(分)
|
|
||||||
AutoOptimization bool `json:"autoOptimization"` // 是否自动优化
|
|
||||||
|
|
||||||
// 最大广告数
|
|
||||||
MaxAdsPerRequest int `json:"maxAdsPerRequest"` // 单次请求最大广告数量
|
|
||||||
|
|
||||||
// 其他配置
|
|
||||||
BrandSafety bool `json:"brandSafety"` // 品牌安全
|
|
||||||
Viewability bool `json:"viewability"` // 可见性支持
|
|
||||||
RealTimeBidding bool `json:"realTimeBidding"` // 实时竞价
|
|
||||||
HeaderBidding bool `json:"headerBidding"` // 标题竞价
|
|
||||||
|
|
||||||
// 财务设置
|
|
||||||
BillingModel string `json:"billingModel" v:"required|in:cpm,cpc,cpa,rev_share"` // 计费模式
|
|
||||||
PaymentTerms string `json:"paymentTerms" v:"in:net_30,net_60,net_90"` // 支付条款
|
|
||||||
RevShareRate float64 `json:"revShareRate" v:"between:0,1"` // 收入分成比例
|
|
||||||
MinPayment int64 `json:"minPayment"` // 最小支付金额(分)
|
|
||||||
Currency string `json:"currency"` // 货币单位
|
|
||||||
TaxInclusive bool `json:"taxInclusive"` // 是否含税
|
|
||||||
|
|
||||||
// 系统信息
|
|
||||||
Priority int `json:"priority"` // 优先级
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateAdSourceRes struct {
|
|
||||||
Id string `json:"id"` // 广告源ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAdSourceReq 获取广告源详情请求
|
|
||||||
type GetAdSourceReq struct {
|
|
||||||
g.Meta `path:"/getByID" method:"get" tags:"广告源管理" summary:"获取广告源详情" dc:"根据ID获取单个广告源详情"`
|
|
||||||
Id string `json:"id" v:"required"` // 广告源ID
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetAdSourceRes struct {
|
|
||||||
*entity.AdSource
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListAdSourceReq 获取广告源列表请求
|
|
||||||
type ListAdSourceReq struct {
|
|
||||||
g.Meta `path:"/getList" method:"get" tags:"广告源管理" summary:"获取广告源列表" dc:"分页查询广告源列表,支持多条件筛选"`
|
|
||||||
*beans.Page
|
|
||||||
|
|
||||||
Name string `json:"name"` // 广告源名称模糊查询
|
|
||||||
Code string `json:"code"` // 广告源编码
|
|
||||||
Provider string `json:"provider"` // 提供商
|
|
||||||
Type string `json:"type"` // 类型
|
|
||||||
Status string `json:"status"` // 状态
|
|
||||||
Health string `json:"health"` // 健康状态
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListAdSourceRes struct {
|
|
||||||
List []*entity.AdSource `json:"list"`
|
|
||||||
Total int `json:"total"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdSourceReq 更新广告源请求
|
|
||||||
type UpdateAdSourceReq struct {
|
|
||||||
g.Meta `path:"/update" method:"put" tags:"广告源管理" summary:"更新广告源" dc:"更新广告源信息"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告源ID
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `json:"name"` // 广告源名称
|
|
||||||
Description string `json:"description"` // 描述
|
|
||||||
|
|
||||||
// 连接配置
|
|
||||||
APIEndpoint string `json:"apiEndpoint"` // API端点
|
|
||||||
APIVersion string `json:"apiVersion"` // API版本
|
|
||||||
AuthType string `json:"authType"` // 认证类型
|
|
||||||
AuthConfig map[string]interface{} `json:"authConfig"` // 认证配置
|
|
||||||
Headers map[string]string `json:"headers"` // 请求头配置
|
|
||||||
Timeout int `json:"timeout"` // 超时时间(毫秒)
|
|
||||||
RetryCount int `json:"retryCount"` // 重试次数
|
|
||||||
|
|
||||||
// 基础配置
|
|
||||||
SupportedFormats []string `json:"supportedFormats"` // 支持的广告格式
|
|
||||||
SupportedSizes []string `json:"supportedSizes"` // 支持的尺寸
|
|
||||||
SupportedDevices []string `json:"supportedDevices"` // 支持的设备类型
|
|
||||||
SupportedOS []string `json:"supportedOS"` // 支持的操作系统
|
|
||||||
SupportedCountries []string `json:"supportedCountries"` // 支持的国家/地区
|
|
||||||
|
|
||||||
// 竞价配置
|
|
||||||
BiddingType string `json:"biddingType"` // 竞价类型
|
|
||||||
MinBidAmount int64 `json:"minBidAmount"` // 最小出价(分)
|
|
||||||
MaxBidAmount int64 `json:"maxBidAmount"` // 最大出价(分)
|
|
||||||
BidIncrement int64 `json:"bidIncrement"` // 出价增量(分)
|
|
||||||
DefaultBidAmount int64 `json:"defaultBidAmount"` // 默认出价(分)
|
|
||||||
AutoOptimization bool `json:"autoOptimization"` // 是否自动优化
|
|
||||||
|
|
||||||
// 最大广告数
|
|
||||||
MaxAdsPerRequest int `json:"maxAdsPerRequest"` // 单次请求最大广告数量
|
|
||||||
|
|
||||||
// 其他配置
|
|
||||||
BrandSafety bool `json:"brandSafety"` // 品牌安全
|
|
||||||
Viewability bool `json:"viewability"` // 可见性支持
|
|
||||||
RealTimeBidding bool `json:"realTimeBidding"` // 实时竞价
|
|
||||||
HeaderBidding bool `json:"headerBidding"` // 标题竞价
|
|
||||||
|
|
||||||
// 财务设置
|
|
||||||
BillingModel string `json:"billingModel"` // 计费模式
|
|
||||||
PaymentTerms string `json:"paymentTerms"` // 支付条款
|
|
||||||
RevShareRate float64 `json:"revShareRate"` // 收入分成比例
|
|
||||||
MinPayment int64 `json:"minPayment"` // 最小支付金额(分)
|
|
||||||
Currency string `json:"currency"` // 货币单位
|
|
||||||
TaxInclusive bool `json:"taxInclusive"` // 是否含税
|
|
||||||
|
|
||||||
// 系统信息
|
|
||||||
Priority int `json:"priority"` // 优先级
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdSourceStatusReq 更新广告源状态请求
|
|
||||||
type UpdateAdSourceStatusReq struct {
|
|
||||||
// g.Meta `path:"/adsource" method:"patch" tags:"广告源管理" summary:"更新广告源状态" dc:"更新广告源状态"` // 暂时注释,缺少对应的controller方法
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告源ID
|
|
||||||
Status string `json:"status" v:"required"` // 广告源状态:active、inactive、maintenance
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteAdSourceReq 删除广告源请求
|
|
||||||
type DeleteAdSourceReq struct {
|
|
||||||
g.Meta `path:"/delete" method:"delete" tags:"广告源管理" summary:"删除广告源" dc:"删除指定的广告源"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告源ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestAdSourceReq 测试广告源连接请求
|
|
||||||
type TestAdSourceReq struct {
|
|
||||||
// g.Meta `path:"/adsource-test" method:"post" tags:"广告源管理" summary:"测试广告源连接" dc:"测试广告源的连接性和可用性"` // 暂时注释,缺少对应的controller方法
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告源ID
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestAdSourceRes struct {
|
|
||||||
Success bool `json:"success"` // 测试是否成功
|
|
||||||
ResponseTime int64 `json:"responseTime"` // 响应时间(毫秒)
|
|
||||||
ErrorMessage string `json:"errorMessage"` // 错误信息
|
|
||||||
SupportedFormats []string `json:"supportedFormats"` // 支持的广告格式
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteAdSourceRes 删除广告源响应
|
|
||||||
type DeleteAdSourceRes struct {
|
|
||||||
Success bool `json:"success"` // 删除是否成功
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import "github.com/gogf/gf/v2/frame/g"
|
|
||||||
|
|
||||||
// GetAdSourceStatisticsReq 获取广告源统计数据请求
|
|
||||||
type GetAdSourceStatisticsReq struct {
|
|
||||||
g.Meta `path:"/adsource-statistics" method:"get" tags:"广告源管理" summary:"获取广告源统计数据" dc:"获取广告源的详细统计数据"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告源ID
|
|
||||||
StartDate int64 `json:"startDate" v:"required"` // 开始日期
|
|
||||||
EndDate int64 `json:"endDate" v:"required"` // 结束日期
|
|
||||||
Dimension string `json:"dimension"` // 统计维度:day、week、month
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetAdSourceStatisticsRes struct {
|
|
||||||
// 概览数据
|
|
||||||
Overview AdSourceOverviewStats `json:"overview"`
|
|
||||||
|
|
||||||
// 趋势数据
|
|
||||||
Trends []AdSourceTrendData `json:"trends"`
|
|
||||||
|
|
||||||
// 性能数据
|
|
||||||
Performance AdSourcePerformanceStats `json:"performance"`
|
|
||||||
|
|
||||||
// 错误统计
|
|
||||||
Errors []AdSourceErrorStats `json:"errors"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceOverviewStats 广告源概览统计
|
|
||||||
type AdSourceOverviewStats struct {
|
|
||||||
TotalRequests int64 `json:"totalRequests"` // 总请求数
|
|
||||||
SuccessfulRequests int64 `json:"successfulRequests"` // 成功请求数
|
|
||||||
FailedRequests int64 `json:"failedRequests"` // 失败请求数
|
|
||||||
TotalImpressions int64 `json:"totalImpressions"` // 总展示次数
|
|
||||||
TotalClicks int64 `json:"totalClicks"` // 总点击次数
|
|
||||||
TotalConversions int64 `json:"totalConversions"` // 总转化次数
|
|
||||||
TotalRevenue int64 `json:"totalRevenue"` // 总收入(分)
|
|
||||||
SuccessRate float64 `json:"successRate"` // 成功率
|
|
||||||
ErrorRate float64 `json:"errorRate"` // 错误率
|
|
||||||
CTR float64 `json:"ctr"` // 点击率
|
|
||||||
CVR float64 `json:"cvr"` // 转化率
|
|
||||||
FillRate float64 `json:"fillRate"` // 填充率
|
|
||||||
ECPM int64 `json:"ecpm"` // 有效千次展示成本(分)
|
|
||||||
ECPC int64 `json:"ecpc"` // 有效点击成本(分)
|
|
||||||
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
|
|
||||||
Uptime float64 `json:"uptime"` // 可用性(百分比)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceTrendData 广告源趋势数据
|
|
||||||
type AdSourceTrendData struct {
|
|
||||||
Date int64 `json:"date"` // 日期
|
|
||||||
Requests int64 `json:"requests"` // 请求数
|
|
||||||
Impressions int64 `json:"impressions"` // 展示次数
|
|
||||||
Clicks int64 `json:"clicks"` // 点击次数
|
|
||||||
Conversions int64 `json:"conversions"` // 转化次数
|
|
||||||
Revenue int64 `json:"revenue"` // 收入(分)
|
|
||||||
SuccessRate float64 `json:"successRate"` // 成功率
|
|
||||||
ErrorRate float64 `json:"errorRate"` // 错误率
|
|
||||||
CTR float64 `json:"ctr"` // 点击率
|
|
||||||
CVR float64 `json:"cvr"` // 转化率
|
|
||||||
FillRate float64 `json:"fillRate"` // 填充率
|
|
||||||
ECPM int64 `json:"ecpm"` // 有效千次展示成本(分)
|
|
||||||
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourcePerformanceStats 广告源性能统计
|
|
||||||
type AdSourcePerformanceStats struct {
|
|
||||||
// 响应时间分布
|
|
||||||
ResponseTimeDistribution map[string]int64 `json:"responseTimeDistribution"` // 响应时间分布
|
|
||||||
|
|
||||||
// 错误类型统计
|
|
||||||
ErrorTypes map[string]int64 `json:"errorTypes"` // 错误类型统计
|
|
||||||
|
|
||||||
// 地区性能
|
|
||||||
RegionalPerformance map[string]AdSourceRegionalStats `json:"regionalPerformance"` // 地区性能
|
|
||||||
|
|
||||||
// 设备性能
|
|
||||||
DevicePerformance map[string]AdSourceDeviceStats `json:"devicePerformance"` // 设备性能
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceErrorStats 广告源错误统计
|
|
||||||
type AdSourceErrorStats struct {
|
|
||||||
ErrorType string `json:"errorType"` // 错误类型
|
|
||||||
Count int64 `json:"count"` // 错误次数
|
|
||||||
Percentage float64 `json:"percentage"` // 占比
|
|
||||||
LastOccurred int64 `json:"lastOccurred"` // 最后发生时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceRegionalStats 广告源地区统计
|
|
||||||
type AdSourceRegionalStats struct {
|
|
||||||
Region string `json:"region"` // 地区
|
|
||||||
Requests int64 `json:"requests"` // 请求数
|
|
||||||
Impressions int64 `json:"impressions"` // 展示次数
|
|
||||||
Clicks int64 `json:"clicks"` // 点击次数
|
|
||||||
Revenue int64 `json:"revenue"` // 收入(分)
|
|
||||||
CTR float64 `json:"ctr"` // 点击率
|
|
||||||
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceDeviceStats 广告源设备统计
|
|
||||||
type AdSourceDeviceStats struct {
|
|
||||||
Device string `json:"device"` // 设备类型
|
|
||||||
Requests int64 `json:"requests"` // 请求数
|
|
||||||
Impressions int64 `json:"impressions"` // 展示次数
|
|
||||||
Clicks int64 `json:"clicks"` // 点击次数
|
|
||||||
Revenue int64 `json:"revenue"` // 收入(分)
|
|
||||||
CTR float64 `json:"ctr"` // 点击率
|
|
||||||
ResponseTime float64 `json:"responseTime"` // 平均响应时间(毫秒)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceTestMetrics 广告源测试质量指标
|
|
||||||
type AdSourceTestMetrics struct {
|
|
||||||
SuccessRate float64 `json:"successRate"` // 成功率
|
|
||||||
AverageResponseTime float64 `json:"averageResponseTime"` // 平均响应时间(毫秒)
|
|
||||||
FillRate float64 `json:"fillRate"` // 填充率
|
|
||||||
CTR float64 `json:"ctr"` // 点击率
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddAdvertisementReq 添加广告请求
|
|
||||||
type AddAdvertisementReq struct {
|
|
||||||
g.Meta `path:"/add" method:"post" tags:"广告管理" summary:"添加广告" dc:"添加新的广告"`
|
|
||||||
|
|
||||||
// 广告基本信息
|
|
||||||
Title string `json:"title" v:"required"` // 广告标题
|
|
||||||
Description string `json:"description"` // 广告描述
|
|
||||||
AdvertiserId string `json:"advertiserId" v:"required"` // 广告主ID
|
|
||||||
AdPositionId string `json:"adPositionId" v:"required"` // 广告位ID
|
|
||||||
AdType string `json:"adType" v:"required"` // 广告类型:图片、视频、文字等
|
|
||||||
AdFormat string `json:"adFormat" v:"required"` // 广告格式
|
|
||||||
MaterialUrl string `json:"materialUrl" v:"required"` // 广告素材URL
|
|
||||||
TargetUrl string `json:"targetUrl" v:"required"` // 目标链接
|
|
||||||
|
|
||||||
// 投放设置
|
|
||||||
StartDate int64 `json:"startDate" v:"required"` // 开始投放时间
|
|
||||||
EndDate int64 `json:"endDate" v:"required"` // 结束投放时间
|
|
||||||
Budget int64 `json:"budget" v:"required"` // 预算(分)
|
|
||||||
DailyBudget int64 `json:"dailyBudget"` // 日预算(分)
|
|
||||||
BidAmount int64 `json:"bidAmount" v:"required"` // 出价(分)
|
|
||||||
BillingType string `json:"billingType" v:"required"` // 计费类型:CPC、CPM、CPA等
|
|
||||||
|
|
||||||
// 投放条件
|
|
||||||
Targeting *entity.UnifiedTargeting `json:"targeting"` // 定向条件
|
|
||||||
}
|
|
||||||
|
|
||||||
type AddAdvertisementRes struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdvertisementReq 更新广告请求
|
|
||||||
type UpdateAdvertisementReq struct {
|
|
||||||
g.Meta `path:"/update" method:"put" tags:"广告管理" summary:"更新广告" dc:"更新广告信息"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // ID
|
|
||||||
|
|
||||||
// 广告基本信息
|
|
||||||
Title string `json:"title"` // 广告标题
|
|
||||||
Description string `json:"description"` // 广告描述
|
|
||||||
AdvertiserId string `json:"advertiserId"` // 广告主ID
|
|
||||||
AdPositionId string `json:"adPositionId"` // 广告位ID
|
|
||||||
AdType string `json:"adType"` // 广告类型:图片、视频、文字等
|
|
||||||
AdFormat string `json:"adFormat"` // 广告格式
|
|
||||||
MaterialUrl string `json:"materialUrl"` // 广告素材URL
|
|
||||||
TargetUrl string `json:"targetUrl"` // 目标链接
|
|
||||||
|
|
||||||
// 投放设置
|
|
||||||
StartDate *int64 `json:"startDate"` // 开始投放时间
|
|
||||||
EndDate *int64 `json:"endDate"` // 结束投放时间
|
|
||||||
Budget *int64 `json:"budget"` // 预算(分)
|
|
||||||
DailyBudget *int64 `json:"dailyBudget"` // 日预算(分)
|
|
||||||
BidAmount *int64 `json:"bidAmount"` // 出价(分)
|
|
||||||
BillingType string `json:"billingType"` // 计费类型:CPC、CPM、CPA等
|
|
||||||
|
|
||||||
// 投放条件
|
|
||||||
Targeting *entity.UnifiedTargeting `json:"targeting"` // 定向条件
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
Status *string `json:"status"` // 广告状态:待审核、审核中、已通过、已拒绝、投放中、已暂停、已结束
|
|
||||||
AuditStatus *string `json:"auditStatus"` // 审核状态:通过、拒绝
|
|
||||||
AuditReason *string `json:"auditReason"` // 审核不通过原因
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAdvertisementReq 获取广告详情请求
|
|
||||||
type GetAdvertisementReq struct {
|
|
||||||
g.Meta `path:"/getOne" method:"get" tags:"广告管理" summary:"获取广告详情" dc:"根据ID获取单个广告详情"`
|
|
||||||
Id string `json:"id" v:"required"` // ID
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetAdvertisementRes struct {
|
|
||||||
*entity.Advertisement
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListAdvertisementReq 获取广告列表请求
|
|
||||||
type ListAdvertisementReq struct {
|
|
||||||
g.Meta `path:"/list" method:"get" tags:"广告管理" summary:"获取广告列表" dc:"分页查询广告列表,支持多条件筛选"`
|
|
||||||
*beans.Page
|
|
||||||
|
|
||||||
AdvertiserId string `json:"advertiserId"` // 广告主ID
|
|
||||||
AdPositionId string `json:"adPositionId"` // 广告位ID
|
|
||||||
AdType string `json:"adType"` // 广告类型
|
|
||||||
Status string `json:"status"` // 广告状态
|
|
||||||
AuditStatus string `json:"auditStatus"` // 审核状态
|
|
||||||
Title string `json:"title"` // 广告标题模糊查询
|
|
||||||
DateRange []string `json:"dateRange"` // 创建时间范围 [start, end]
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListAdvertisementRes struct {
|
|
||||||
List []*entity.Advertisement `json:"list"`
|
|
||||||
Total int `json:"total"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuditAdvertisementReq 审核广告请求
|
|
||||||
type AuditAdvertisementReq struct {
|
|
||||||
g.Meta `path:"/audit" method:"post" tags:"广告管理" summary:"审核广告" dc:"审核广告,通过或拒绝"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告ID
|
|
||||||
AuditStatus string `json:"auditStatus" v:"required"` // 审核状态:通过、拒绝
|
|
||||||
AuditReason string `json:"auditReason"` // 审核不通过原因
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdStatusReq 更新广告状态请求
|
|
||||||
type UpdateAdStatusReq struct {
|
|
||||||
g.Meta `path:"/updateStatus" method:"patch" tags:"广告管理" summary:"更新广告状态" dc:"更新广告状态"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告ID
|
|
||||||
Status string `json:"status" v:"required"` // 广告状态:启用、禁用
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/entity"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddAdvertiserReq 添加广告主请求
|
|
||||||
type AddAdvertiserReq struct {
|
|
||||||
g.Meta `path:"/add" method:"post" tags:"广告主管理" summary:"添加广告主" dc:"添加新的广告主"`
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `json:"name" v:"required"` // 广告主名称
|
|
||||||
ContactName string `json:"contactName" v:"required"` // 联系人姓名
|
|
||||||
ContactPhone string `json:"contactPhone" v:"required"` // 联系电话
|
|
||||||
ContactEmail string `json:"contactEmail" v:"required"` // 联系邮箱
|
|
||||||
Company string `json:"company" v:"required"` // 公司名称
|
|
||||||
Industry string `json:"industry" v:"required"` // 所属行业
|
|
||||||
Scale string `json:"scale"` // 公司规模
|
|
||||||
|
|
||||||
// 证件信息
|
|
||||||
BusinessLicenseUrl string `json:"businessLicenseUrl" v:"required"` // 营业执照URL
|
|
||||||
ICPLicenseUrl string `json:"icpLicenseUrl"` // ICP备案截图URL
|
|
||||||
OtherLicenseUrls []string `json:"otherLicenseUrls"` // 其他证件URL
|
|
||||||
|
|
||||||
// 财务信息
|
|
||||||
BankName string `json:"bankName" v:"required"` // 开户银行
|
|
||||||
BankAccount string `json:"bankAccount" v:"required"` // 银行账号
|
|
||||||
AccountName string `json:"accountName" v:"required"` // 账户名称
|
|
||||||
|
|
||||||
// 合同信息
|
|
||||||
ContractId string `json:"contractId"` // 合同编号
|
|
||||||
ContractType string `json:"contractType"` // 合同类型
|
|
||||||
ContractUrl string `json:"contractUrl"` // 合同文件URL
|
|
||||||
SignDate int64 `json:"signDate"` // 签约日期
|
|
||||||
ExpireDate int64 `json:"expireDate"` // 到期日期
|
|
||||||
|
|
||||||
// 系统信息
|
|
||||||
AccountBalance int64 `json:"accountBalance"` // 账户余额(分)
|
|
||||||
CreditLimit int64 `json:"creditLimit"` // 授信额度(分)
|
|
||||||
Remark string `json:"remark"` // 备注
|
|
||||||
}
|
|
||||||
|
|
||||||
type AddAdvertiserRes struct {
|
|
||||||
Id string `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdvertiserReq 更新广告主请求
|
|
||||||
type UpdateAdvertiserReq struct {
|
|
||||||
g.Meta `path:"/update" method:"put" tags:"广告主管理" summary:"更新广告主" dc:"更新广告主信息"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // ID
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `json:"name"` // 广告主名称
|
|
||||||
ContactName string `json:"contactName"` // 联系人姓名
|
|
||||||
ContactPhone string `json:"contactPhone"` // 联系电话
|
|
||||||
ContactEmail string `json:"contactEmail"` // 联系邮箱
|
|
||||||
Company string `json:"company"` // 公司名称
|
|
||||||
Industry string `json:"industry"` // 所属行业
|
|
||||||
Scale string `json:"scale"` // 公司规模
|
|
||||||
|
|
||||||
// 证件信息
|
|
||||||
BusinessLicenseUrl string `json:"businessLicenseUrl"` // 营业执照URL
|
|
||||||
ICPLicenseUrl string `json:"icpLicenseUrl"` // ICP备案截图URL
|
|
||||||
OtherLicenseUrls []string `json:"otherLicenseUrls"` // 其他证件URL
|
|
||||||
|
|
||||||
// 财务信息
|
|
||||||
BankName string `json:"bankName"` // 开户银行
|
|
||||||
BankAccount string `json:"bankAccount"` // 银行账号
|
|
||||||
AccountName string `json:"accountName"` // 账户名称
|
|
||||||
|
|
||||||
// 合同信息
|
|
||||||
ContractId string `json:"contractId"` // 合同编号
|
|
||||||
ContractType string `json:"contractType"` // 合同类型
|
|
||||||
ContractUrl string `json:"contractUrl"` // 合同文件URL
|
|
||||||
SignDate *int64 `json:"signDate"` // 签约日期
|
|
||||||
ExpireDate *int64 `json:"expireDate"` // 到期日期
|
|
||||||
|
|
||||||
// 系统信息
|
|
||||||
AccountBalance *int64 `json:"accountBalance"` // 账户余额(分)
|
|
||||||
CreditLimit *int64 `json:"creditLimit"` // 授信额度(分)
|
|
||||||
Remark string `json:"remark"` // 备注
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
Status *string `json:"status"` // 广告主状态:待审核、已审核、已拒绝、已冻结
|
|
||||||
AuditStatus *string `json:"auditStatus"` // 审核状态
|
|
||||||
AuditReason *string `json:"auditReason"` // 审核不通过原因
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAdvertiserReq 获取广告主详情请求
|
|
||||||
type GetAdvertiserReq struct {
|
|
||||||
g.Meta `path:"/getOne" method:"get" tags:"广告主管理" summary:"获取广告主详情" dc:"根据ID获取单个广告主详情"`
|
|
||||||
Id string `json:"id" v:"required"` // ID
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetAdvertiserRes struct {
|
|
||||||
*entity.Advertiser
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListAdvertiserReq 获取广告主列表请求
|
|
||||||
type ListAdvertiserReq struct {
|
|
||||||
g.Meta `path:"/list" method:"get" tags:"广告主管理" summary:"获取广告主列表" dc:"分页查询广告主列表,支持多条件筛选"`
|
|
||||||
*beans.Page
|
|
||||||
|
|
||||||
Name string `json:"name"` // 广告主名称模糊查询
|
|
||||||
ContactName string `json:"contactName"` // 联系人模糊查询
|
|
||||||
Company string `json:"company"` // 公司名称模糊查询
|
|
||||||
Industry string `json:"industry"` // 所属行业
|
|
||||||
Status string `json:"status"` // 广告主状态
|
|
||||||
AuditStatus string `json:"auditStatus"` // 审核状态
|
|
||||||
DateRange []string `json:"dateRange"` // 创建时间范围 [start, end]
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListAdvertiserRes struct {
|
|
||||||
List []*entity.Advertiser `json:"list"`
|
|
||||||
Total int `json:"total"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuditAdvertiserReq 审核广告主请求
|
|
||||||
type AuditAdvertiserReq struct {
|
|
||||||
g.Meta `path:"/audit" method:"post" tags:"广告主管理" summary:"审核广告主" dc:"审核广告主,通过或拒绝"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告主ID
|
|
||||||
AuditStatus string `json:"auditStatus" v:"required"` // 审核状态:通过、拒绝
|
|
||||||
AuditReason string `json:"auditReason"` // 审核不通过原因
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdvertiserStatusReq 更新广告主状态请求
|
|
||||||
type UpdateAdvertiserStatusReq struct {
|
|
||||||
g.Meta `path:"/updateStatus" method:"patch" tags:"广告主管理" summary:"更新广告主状态" dc:"更新广告主状态"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告主ID
|
|
||||||
Status string `json:"status" v:"required"` // 广告主状态:启用、禁用、冻结
|
|
||||||
}
|
|
||||||
|
|
||||||
// RechargeAdvertiserReq 广告主充值请求
|
|
||||||
type RechargeAdvertiserReq struct {
|
|
||||||
g.Meta `path:"/recharge" method:"post" tags:"广告主管理" summary:"广告主充值" dc:"为广告主账户充值"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告主ID
|
|
||||||
Amount int64 `json:"amount" v:"required"` // 充值金额(分)
|
|
||||||
Remark string `json:"remark"` // 充值备注
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateCreditLimitReq 更新授信额度请求
|
|
||||||
type UpdateCreditLimitReq struct {
|
|
||||||
g.Meta `path:"/updateCreditLimit" method:"post" tags:"广告主管理" summary:"更新授信额度" dc:"更新广告主的授信额度"`
|
|
||||||
|
|
||||||
Id string `json:"id" v:"required"` // 广告主ID
|
|
||||||
CreditLimit int64 `json:"creditLimit" v:"required"` // 授信额度(分)
|
|
||||||
Remark string `json:"remark"` // 备注说明
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAdvertiserBalanceReq 获取广告主余额请求
|
|
||||||
type GetAdvertiserBalanceReq struct {
|
|
||||||
g.Meta `path:"/getBalance" method:"get" tags:"广告主管理" summary:"获取广告主余额" dc:"根据ID获取广告主账户余额和授信额度"`
|
|
||||||
Id string `json:"id" v:"required"` // 广告主ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAdvertiserBalanceRes 获取广告主余额响应
|
|
||||||
type GetAdvertiserBalanceRes struct {
|
|
||||||
Balance int64 `json:"balance"` // 账户余额(分)
|
|
||||||
CreditLimit int64 `json:"creditLimit"` // 授信额度(分)
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateApplicationReq 创建应用请求
|
|
||||||
type CreateApplicationReq struct {
|
|
||||||
g.Meta `path:"/createApplication" method:"post" summary:"创建应用"`
|
|
||||||
|
|
||||||
TenantID interface{} `json:"tenantId" v:"required#租户ID不能为空"`
|
|
||||||
Name string `json:"name" v:"required#应用名称不能为空"`
|
|
||||||
Code string `json:"code" v:"required#应用编码不能为空"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Platform string `json:"platform" v:"required#平台不能为空|in:web,h5,android,ios#平台类型错误"`
|
|
||||||
PackageName string `json:"packageName"`
|
|
||||||
AppStoreURL string `json:"appStoreUrl"`
|
|
||||||
Categories []string `json:"categories"`
|
|
||||||
Tags []string `json:"tags"`
|
|
||||||
AdTypes []string `json:"adTypes"`
|
|
||||||
CallbackURL string `json:"callbackUrl"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateApplicationRes 创建应用响应
|
|
||||||
type CreateApplicationRes struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
AppKey string `json:"appKey"`
|
|
||||||
AppSecret string `json:"appSecret"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateApplicationReq 更新应用请求
|
|
||||||
type UpdateApplicationReq struct {
|
|
||||||
g.Meta `path:"/updateApplication" method:"put" summary:"更新应用"`
|
|
||||||
|
|
||||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Platform string `json:"platform" v:"in:web,h5,android,ios#平台类型错误"`
|
|
||||||
PackageName string `json:"packageName"`
|
|
||||||
AppStoreURL string `json:"appStoreUrl"`
|
|
||||||
Categories []string `json:"categories"`
|
|
||||||
Tags []string `json:"tags"`
|
|
||||||
AdTypes []string `json:"adTypes"`
|
|
||||||
CallbackURL string `json:"callbackUrl"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateApplicationRes 更新应用响应
|
|
||||||
type UpdateApplicationRes struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetApplicationReq 获取应用请求
|
|
||||||
type GetApplicationReq struct {
|
|
||||||
g.Meta `path:"/getApplication" method:"get" summary:"获取应用信息"`
|
|
||||||
|
|
||||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetApplicationRes 获取应用响应
|
|
||||||
type GetApplicationRes struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
TenantID interface{} `json:"tenantId"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Platform string `json:"platform"`
|
|
||||||
PackageName string `json:"packageName"`
|
|
||||||
AppStoreURL string `json:"appStoreUrl"`
|
|
||||||
Categories []string `json:"categories"`
|
|
||||||
Tags []string `json:"tags"`
|
|
||||||
AdTypes []string `json:"adTypes"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
AppKey string `json:"appKey"`
|
|
||||||
CallbackURL string `json:"callbackUrl"`
|
|
||||||
CreatedAt int64 `json:"createdAt"`
|
|
||||||
UpdatedAt int64 `json:"updatedAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListApplicationsReq 获取应用列表请求
|
|
||||||
type ListApplicationsReq struct {
|
|
||||||
g.Meta `path:"/listApplications" method:"get" summary:"获取应用列表"`
|
|
||||||
|
|
||||||
TenantID int64 `json:"tenantId" v:"required#租户ID不能为空"`
|
|
||||||
Platform string `json:"platform"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Page int `json:"page" d:"1"`
|
|
||||||
Size int `json:"size" d:"20"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListApplicationsRes 获取应用列表响应
|
|
||||||
type ListApplicationsRes struct {
|
|
||||||
List []ApplicationItem `json:"list"`
|
|
||||||
Total int64 `json:"total"`
|
|
||||||
Page int `json:"page"`
|
|
||||||
Size int `json:"size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplicationItem 应用列表项
|
|
||||||
type ApplicationItem struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Code string `json:"code"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Platform string `json:"platform"`
|
|
||||||
PackageName string `json:"packageName"`
|
|
||||||
Categories []string `json:"categories"`
|
|
||||||
Tags []string `json:"tags"`
|
|
||||||
AdTypes []string `json:"adTypes"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
DailyRequests int64 `json:"dailyRequests"`
|
|
||||||
MonthlyRequests int64 `json:"monthlyRequests"`
|
|
||||||
CreatedAt int64 `json:"createdAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetAPIKeysReq 重置API密钥请求
|
|
||||||
type ResetAPIKeysReq struct {
|
|
||||||
g.Meta `path:"/resetAPIKeys" method:"post" summary:"重置API密钥"`
|
|
||||||
|
|
||||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetAPIKeysRes 重置API密钥响应
|
|
||||||
type ResetAPIKeysRes struct {
|
|
||||||
AppKey string `json:"appKey"`
|
|
||||||
AppSecret string `json:"appSecret"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateApplicationReq 验证应用请求
|
|
||||||
type ValidateApplicationReq struct {
|
|
||||||
g.Meta `path:"/validateApplication" method:"post" summary:"验证应用权限"`
|
|
||||||
|
|
||||||
AppKey string `json:"appKey" v:"required#应用密钥不能为空"`
|
|
||||||
AppSecret string `json:"appSecret" v:"required#应用密钥不能为空"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateApplicationRes 验证应用响应
|
|
||||||
type ValidateApplicationRes struct {
|
|
||||||
Valid bool `json:"valid"`
|
|
||||||
AppID int64 `json:"appId"`
|
|
||||||
AppName string `json:"appName"`
|
|
||||||
TenantID int64 `json:"tenantId"`
|
|
||||||
TenantName string `json:"tenantName"`
|
|
||||||
Platform string `json:"platform"`
|
|
||||||
AdTypes []string `json:"adTypes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteApplicationReq 删除应用请求
|
|
||||||
type DeleteApplicationReq struct {
|
|
||||||
g.Meta `path:"/deleteApplication" method:"delete" summary:"删除应用"`
|
|
||||||
|
|
||||||
ID int64 `json:"id" v:"required#应用ID不能为空"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteApplicationRes 删除应用响应
|
|
||||||
type DeleteApplicationRes struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
// ContentCheckConfig 送检配置
|
||||||
|
type ContentCheckConfig struct {
|
||||||
|
BatchSize int `json:"batch_size"`
|
||||||
|
ImageEnabled bool `json:"image_enabled"`
|
||||||
|
VideoEnabled bool `json:"video_enabled"`
|
||||||
|
IntervalSeconds int `json:"interval_seconds"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartCheckReq 启动送检服务请求
|
||||||
|
type StartCheckReq struct {
|
||||||
|
BatchSize int `json:"batch_size"`
|
||||||
|
IntervalSeconds int `json:"interval_seconds"`
|
||||||
|
ImageEnabled bool `json:"image_enabled"`
|
||||||
|
VideoEnabled bool `json:"video_enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyReq 空请求
|
||||||
|
type EmptyReq struct{}
|
||||||
|
|
||||||
|
// ProcessImageCallbackReq 处理图片回调请求
|
||||||
|
type ProcessImageCallbackReq struct {
|
||||||
|
CallbackData string `json:"callbackData"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessVideoCallbackReq 处理视频回调请求
|
||||||
|
type ProcessVideoCallbackReq struct {
|
||||||
|
CallbackData string `json:"callbackData"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessImageResultReq 查询图片检测结果请求
|
||||||
|
type ProcessImageResultReq struct {
|
||||||
|
TaskID string `json:"taskId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessVideoResultReq 查询视频检测结果请求
|
||||||
|
type ProcessVideoResultReq struct {
|
||||||
|
TaskID string `json:"taskId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualSubmitImageByIDReq 手动提交图片送检请求
|
||||||
|
type ManualSubmitImageByIDReq struct {
|
||||||
|
ImageID string `json:"image_id" v:"required#图片ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualSubmitVideoByIDReq 手动提交视频送检请求
|
||||||
|
type ManualSubmitVideoByIDReq struct {
|
||||||
|
VideoID string `json:"video_id" v:"required#视频ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ManualSubmitRes 手动提交响应
|
||||||
|
type ManualSubmitRes struct {
|
||||||
|
TaskID string `json:"taskId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetImageCheckLogsReq 获取图片送检日志请求
|
||||||
|
type GetImageCheckLogsReq struct {
|
||||||
|
ImageID string `json:"image_id" v:"required#图片ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVideoCheckLogsReq 获取视频送检日志请求
|
||||||
|
type GetVideoCheckLogsReq struct {
|
||||||
|
VideoID string `json:"video_id" v:"required#视频ID不能为空"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCheckLogsRes 获取送检日志响应
|
||||||
|
type GetCheckLogsRes struct {
|
||||||
|
List interface{} `json:"list"`
|
||||||
|
}
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GenerateCIDReq 生成CID请求
|
|
||||||
type GenerateCIDReq struct {
|
|
||||||
g.Meta `path:"/generateCID" method:"post" tags:"CID服务" summary:"生成CID广告" dc:"为当前用户生成CID广告"`
|
|
||||||
UserId int64 `json:"user_id"` // 用户ID(可选,如果不提供则从token获取)
|
|
||||||
RequestType string `json:"request_type"` // 请求类型
|
|
||||||
Parameters map[string]interface{} `json:"parameters"` // 请求参数
|
|
||||||
Position string `json:"position"` // 广告位置
|
|
||||||
Count int `json:"count"` // 广告数量
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdInfo 广告信息
|
|
||||||
type AdInfo struct {
|
|
||||||
Id int64 `json:"id"` // 广告ID
|
|
||||||
Title string `json:"title"` // 广告标题
|
|
||||||
Description string `json:"description"` // 广告描述
|
|
||||||
ImageUrl string `json:"image_url"` // 广告图片URL
|
|
||||||
TargetUrl string `json:"target_url"` // 目标链接
|
|
||||||
ConversionRate float64 `json:"conversion_rate"` // 转化率
|
|
||||||
Source string `json:"source"` // 广告源
|
|
||||||
Bid int `json:"bid"` // 出价(分)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateCIDRes 生成CID响应
|
|
||||||
type GenerateCIDRes struct {
|
|
||||||
CID string `json:"cid"` // 唯一CID
|
|
||||||
Ads []*AdInfo `json:"ads"` // 广告列表
|
|
||||||
TotalAds int `json:"total_ads"` // 总广告数
|
|
||||||
TenantId interface{} `json:"tenant_id"` // 租户ID
|
|
||||||
TenantName string `json:"tenant_name"` // 租户名称
|
|
||||||
GeneratedAt string `json:"generated_at"` // 生成时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// CIDRequestHistory CID请求历史记录
|
|
||||||
type CIDRequestHistory struct {
|
|
||||||
Id int64 `json:"id"` // 记录ID
|
|
||||||
TenantId interface{} `json:"tenant_id"` // 租户ID
|
|
||||||
UserId int64 `json:"user_id"` // 用户ID
|
|
||||||
RequestType string `json:"request_type"` // 请求类型
|
|
||||||
Status string `json:"status"` // 状态
|
|
||||||
ProcessTime int `json:"process_time"` // 处理时间(ms)
|
|
||||||
CreatedAt string `json:"created_at"` // 创建时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCIDHistoryReq 获取CID历史请求
|
|
||||||
type GetCIDHistoryReq struct {
|
|
||||||
g.Meta `path:"/getCidHistory" method:"get" tags:"CID服务" summary:"获取CID历史记录" dc:"分页获取用户的CID请求历史"`
|
|
||||||
Page int `json:"page" v:"required|min:1"` // 页码
|
|
||||||
Size int `json:"size" v:"required|min:1|max:100"` // 每页数量
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCIDHistoryRes 获取CID历史响应
|
|
||||||
type GetCIDHistoryRes struct {
|
|
||||||
List []*CIDRequestHistory `json:"list"` // 历史记录列表
|
|
||||||
Total int64 `json:"total"` // 总数
|
|
||||||
Page int `json:"page"` // 当前页
|
|
||||||
Size int `json:"size"` // 每页数量
|
|
||||||
}
|
|
||||||
|
|
||||||
// TenantInfo 租户信息
|
|
||||||
type TenantInfo struct {
|
|
||||||
Id string `json:"id"` // 租户ID
|
|
||||||
Name string `json:"name"` // 租户名称
|
|
||||||
Level string `json:"level"` // 租户级别
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetTenantRateLimitReq 设置租户限流配置请求
|
|
||||||
type SetTenantRateLimitReq struct {
|
|
||||||
g.Meta `path:"/setTenantRateLimit" method:"post" tags:"租户限流" summary:"设置租户限流配置" dc:"设置指定租户的请求次数限制配置(实际使用全局配置)"`
|
|
||||||
|
|
||||||
TenantID int64 `json:"tenant_id" v:"required"` // 租户ID(仅用于记录,实际使用全局配置)
|
|
||||||
RequestsPerSecond float64 `json:"requests_per_second" v:"required"` // 每秒请求数
|
|
||||||
Burst int `json:"burst" v:"required"` // 突发请求数
|
|
||||||
WindowSeconds int `json:"window_seconds" v:"required"` // 时间窗口(秒)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTenantRateLimitRes 设置租户限流配置响应
|
|
||||||
type SetTenantRateLimitRes struct {
|
|
||||||
Success bool `json:"success"` // 是否成功
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTenantRateLimitUsageReq 获取租户限流使用情况请求
|
|
||||||
type GetTenantRateLimitUsageReq struct {
|
|
||||||
g.Meta `path:"/getTenantRateLimitUsage" method:"get" tags:"租户限流" summary:"获取租户限流使用情况" dc:"获取指定租户的请求次数使用情况"`
|
|
||||||
|
|
||||||
TenantID int64 `json:"tenant_id" v:"required"` // 租户ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTenantRateLimitUsageRes 获取租户限流使用情况响应
|
|
||||||
type GetTenantRateLimitUsageRes struct {
|
|
||||||
TenantID int64 `json:"tenant_id"` // 租户ID
|
|
||||||
CurrentUsed int64 `json:"current_used"` // 当前已使用请求数
|
|
||||||
MaxAllowed int64 `json:"max_allowed"` // 最大允许请求数(基于全局配置)
|
|
||||||
UsagePercent float64 `json:"usage_percent"` // 使用率百分比
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package dto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateStrategyReq 创建策略请求
|
|
||||||
type CreateStrategyReq struct {
|
|
||||||
g.Meta `path:"/create" method:"post" tags:"策略管理" summary:"创建匹配策略" dc:"创建新的广告匹配策略"`
|
|
||||||
Name string `json:"name" v:"required|length:3,50"` // 策略名称
|
|
||||||
Description string `json:"description" v:"max:500"` // 描述
|
|
||||||
TenantLevel string `json:"tenant_level" v:"required|in:basic,standard,premium"` // 租户级别
|
|
||||||
MinConversion float64 `json:"min_conversion" v:"required|min:0|max:1"` // 最低转化率
|
|
||||||
MaxConversion float64 `json:"max_conversion" v:"required|min:0|max:1"` // 最高转化率
|
|
||||||
SourceWeights map[string]int `json:"source_weights" v:"required"` // 广告源权重
|
|
||||||
MaxAdsPerReq int `json:"max_ads_per_req" v:"required|min:1|max:50"` // 每次请求最大广告数
|
|
||||||
MaxReqPerHour int `json:"max_req_per_hour" v:"required|min:1"` // 每小时最大请求次数
|
|
||||||
Priority int `json:"priority" v:"required|min:0|max:100"` // 优先级
|
|
||||||
Status string `json:"status" v:"required|in:active,inactive"` // 状态
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStrategyReq 更新策略请求
|
|
||||||
type UpdateStrategyReq struct {
|
|
||||||
g.Meta `path:"/update" method:"put" tags:"策略管理" summary:"更新匹配策略" dc:"更新现有的广告匹配策略"`
|
|
||||||
Id int64 `json:"id" v:"required"` // 策略ID
|
|
||||||
Name string `json:"name" v:"required|length:3,50"` // 策略名称
|
|
||||||
Description string `json:"description" v:"max:500"` // 描述
|
|
||||||
TenantLevel string `json:"tenant_level" v:"required|in:basic,standard,premium"` // 租户级别
|
|
||||||
MinConversion float64 `json:"min_conversion" v:"required|min:0|max:1"` // 最低转化率
|
|
||||||
MaxConversion float64 `json:"max_conversion" v:"required|min:0|max:1"` // 最高转化率
|
|
||||||
SourceWeights map[string]int `json:"source_weights" v:"required"` // 广告源权重
|
|
||||||
MaxAdsPerReq int `json:"max_ads_per_req" v:"required|min:1|max:50"` // 每次请求最大广告数
|
|
||||||
MaxReqPerHour int `json:"max_req_per_hour" v:"required|min:1"` // 每小时最大请求次数
|
|
||||||
Priority int `json:"priority" v:"required|min:0|max:100"` // 优先级
|
|
||||||
Status string `json:"status" v:"required|in:active,inactive"` // 状态
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteStrategyReq 删除策略请求
|
|
||||||
type DeleteStrategyReq struct {
|
|
||||||
g.Meta `path:"/delete" method:"delete" tags:"策略管理" summary:"删除匹配策略" dc:"删除指定的广告匹配策略"`
|
|
||||||
Id int64 `json:"id" v:"required"` // 策略ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStrategyReq 获取策略请求
|
|
||||||
type GetStrategyReq struct {
|
|
||||||
g.Meta `path:"/getByID" method:"get" tags:"策略管理" summary:"获取策略详情" dc:"获取指定策略的详细信息"`
|
|
||||||
Id int64 `json:"id" v:"required"` // 策略ID
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStrategyListReq 获取策略列表请求
|
|
||||||
type GetStrategyListReq struct {
|
|
||||||
g.Meta `path:"/getList" method:"get" tags:"策略管理" summary:"获取策略列表" dc:"分页获取策略列表"`
|
|
||||||
Page int `json:"page" v:"required|min:1"` // 页码
|
|
||||||
Size int `json:"size" v:"required|min:1|max:100"` // 每页数量
|
|
||||||
TenantLevel string `json:"tenant_level"` // 租户级别筛选
|
|
||||||
Status string `json:"status"` // 状态筛选
|
|
||||||
}
|
|
||||||
|
|
||||||
// StrategyRes 策略响应
|
|
||||||
type StrategyRes struct {
|
|
||||||
Id int64 `json:"id"` // ID
|
|
||||||
Name string `json:"name"` // 策略名称
|
|
||||||
Description string `json:"description"` // 描述
|
|
||||||
TenantLevel string `json:"tenant_level"` // 租户级别
|
|
||||||
MinConversion float64 `json:"min_conversion"` // 最低转化率
|
|
||||||
MaxConversion float64 `json:"max_conversion"` // 最高转化率
|
|
||||||
SourceWeights map[string]int `json:"source_weights"` // 广告源权重
|
|
||||||
MaxAdsPerReq int `json:"max_ads_per_req"` // 每次请求最大广告数
|
|
||||||
MaxReqPerHour int `json:"max_req_per_hour"` // 每小时最大请求次数
|
|
||||||
Priority int `json:"priority"` // 优先级
|
|
||||||
Status string `json:"status"` // 状态
|
|
||||||
CreatedAt string `json:"created_at"` // 创建时间
|
|
||||||
UpdatedAt string `json:"updated_at"` // 更新时间
|
|
||||||
CreatedBy int64 `json:"created_by"` // 创建人
|
|
||||||
UpdatedBy int64 `json:"updated_by"` // 更新人
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStrategyListRes 获取策略列表响应
|
|
||||||
type GetStrategyListRes struct {
|
|
||||||
List []*StrategyRes `json:"list"` // 策略列表
|
|
||||||
Total int64 `json:"total"` // 总数
|
|
||||||
Page int `json:"page"` // 当前页
|
|
||||||
Size int `json:"size"` // 每页数量
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteStrategyRes 删除策略响应
|
|
||||||
type DeleteStrategyRes struct {
|
|
||||||
Success bool `json:"success"` // 是否成功
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/config"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdCreativeCollection = "ad_creative"
|
|
||||||
|
|
||||||
// AdCreative 广告创意素材实体
|
|
||||||
type AdCreative struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
AdvertiserId string `bson:"advertiserId" json:"advertiserId"` // 广告主ID
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 创意名称
|
|
||||||
Title string `bson:"title" json:"title"` // 广告标题
|
|
||||||
Description string `bson:"description" json:"description"` // 广告描述
|
|
||||||
AdType string `bson:"adType" json:"adType"` // 广告类型:image、video、native、interstitial等
|
|
||||||
Format string `bson:"format" json:"format"` // 创意格式:jpg、png、mp4、html等
|
|
||||||
|
|
||||||
// 素材信息
|
|
||||||
MaterialURL string `bson:"materialUrl" json:"materialUrl"` // 素材URL
|
|
||||||
ThumbnailURL string `bson:"thumbnailUrl" json:"thumbnailUrl"` // 缩略图URL
|
|
||||||
LandingPageURL string `bson:"landingPageUrl" json:"landingPageUrl"` // 落地页URL
|
|
||||||
DisplayURL string `bson:"displayUrl" json:"displayUrl"` // 显示URL
|
|
||||||
|
|
||||||
// 尺寸和文件信息
|
|
||||||
Width int64 `bson:"width" json:"width"` // 宽度(px)
|
|
||||||
Height int64 `bson:"height" json:"height"` // 高度(px)
|
|
||||||
Size int64 `bson:"size" json:"size"` // 文件大小(bytes)
|
|
||||||
Duration int64 `bson:"duration" json:"duration"` // 时长(秒)
|
|
||||||
HasAudio bool `bson:"hasAudio" json:"hasAudio"` // 是否有音频
|
|
||||||
AspectRatio string `bson:"aspectRatio" json:"aspectRatio"` // 宽高比
|
|
||||||
|
|
||||||
// 技术信息
|
|
||||||
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
|
|
||||||
Source string `bson:"source" json:"source"` // 来源:upload、sync、generate
|
|
||||||
BackupURL string `bson:"backupUrl" json:"backupUrl"` // 备份URL
|
|
||||||
CDNURL string `bson:"cdnUrl" json:"cdnUrl"` // CDN加速URL
|
|
||||||
CompressInfo string `bson:"compressInfo" json:"compressInfo"` // 压缩信息(JSON格式)
|
|
||||||
|
|
||||||
// 平台兼容性
|
|
||||||
SupportedPlatforms []string `bson:"supportedPlatforms" json:"supportedPlatforms"` // 支持的平台
|
|
||||||
PlatformSpecific string `bson:"platformSpecific" json:"platformSpecific"` // 平台特定配置(JSON格式)
|
|
||||||
|
|
||||||
// 外部平台信息
|
|
||||||
ExternalCreativeId string `bson:"externalCreativeId" json:"externalCreativeId"` // 外部创意ID
|
|
||||||
PlatformId string `bson:"platformId" json:"platformId"` // 平台ID
|
|
||||||
SyncStatus string `bson:"syncStatus" json:"syncStatus"` // 同步状态
|
|
||||||
LastSyncTime int64 `bson:"lastSyncTime" json:"lastSyncTime"` // 最后同步时间
|
|
||||||
|
|
||||||
// 基础配置
|
|
||||||
config.BaseConfig `bson:",inline" json:",inline"` // 内联基础配置
|
|
||||||
|
|
||||||
// 限制配置
|
|
||||||
config.RestrictionConfig `bson:",inline" json:",inline"` // 内联限制配置
|
|
||||||
|
|
||||||
// 其他信息
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、archived
|
|
||||||
ExpireTime int64 `bson:"expireTime" json:"expireTime"` // 过期时间
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *AdCreative) GetCollectionName() string {
|
|
||||||
return AdCreativeCollection
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/config"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdPlatformCollection = "ad_platform"
|
|
||||||
|
|
||||||
// AdPlatform 广告平台实体
|
|
||||||
type AdPlatform struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 平台基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 平台名称:小红书、抖音、快手、京东、淘宝、百度等
|
|
||||||
Code string `bson:"code" json:"code"` // 平台编码,唯一标识
|
|
||||||
DisplayName string `bson:"displayName" json:"displayName"` // 显示名称
|
|
||||||
Logo string `bson:"logo" json:"logo"` // 平台Logo
|
|
||||||
Description string `bson:"description" json:"description"` // 平台描述
|
|
||||||
Category string `bson:"category" json:"category"` // 平台分类:social、ecommerce、search、short_video等
|
|
||||||
|
|
||||||
// 支持的广告类型
|
|
||||||
SupportedAdTypes []string `bson:"supportedAdTypes" json:"supportedAdTypes"` // 支持的广告类型
|
|
||||||
SupportedFormats []string `bson:"supportedFormats" json:"supportedFormats"` // 支持的广告格式
|
|
||||||
|
|
||||||
// 技术能力
|
|
||||||
RealTimeBidding bool `bson:"realTimeBidding" json:"realTimeBidding"` // 是否支持实时竞价
|
|
||||||
ProgrammaticGuaranteed bool `bson:"programmaticGuaranteed" json:"programmaticGuaranteed"` // 是否支持程序化保障
|
|
||||||
HeaderBidding bool `bson:"headerBidding" json:"headerBidding"` // 是否支持Header Bidding
|
|
||||||
|
|
||||||
// API配置
|
|
||||||
config.APIConfig `bson:",inline" json:",inline"` // 内联API配置
|
|
||||||
|
|
||||||
// 竞价配置
|
|
||||||
config.BiddingConfig `bson:",inline" json:",inline"` // 内联竞价配置
|
|
||||||
|
|
||||||
// 支付配置
|
|
||||||
config.PaymentConfig `bson:",inline" json:",inline"` // 内联支付配置
|
|
||||||
|
|
||||||
// 限流配置
|
|
||||||
RateLimit int64 `bson:"rateLimit" json:"rateLimit"` // 速率限制
|
|
||||||
MaxBudgetPerDay int64 `bson:"maxBudgetPerDay" json:"maxBudgetPerDay"` // 每日最大预算
|
|
||||||
|
|
||||||
LastSyncTime int64 `bson:"lastSyncTime" json:"lastSyncTime"` // 最后同步时间
|
|
||||||
|
|
||||||
// 联系信息
|
|
||||||
SupportContact string `bson:"supportContact" json:"supportContact"` // 技术支持联系方式
|
|
||||||
AccountManager string `bson:"accountManager" json:"accountManager"` // 客户经理
|
|
||||||
TechDocumentation string `bson:"techDocumentation" json:"techDocumentation"` // 技术文档链接
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *AdPlatform) GetCollectionName() string {
|
|
||||||
return AdPlatformCollection
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/config"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdPositionCollection = "ad_position"
|
|
||||||
|
|
||||||
// AdPosition 广告位实体
|
|
||||||
type AdPosition struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 广告位名称
|
|
||||||
Description string `bson:"description" json:"description"` // 广告位描述
|
|
||||||
PositionCode string `bson:"positionCode" json:"positionCode"` // 广告位编码,用于标识
|
|
||||||
AdFormat string `bson:"adFormat" json:"adFormat"` // 支持的广告格式
|
|
||||||
|
|
||||||
// 尺寸信息
|
|
||||||
Width int64 `bson:"width" json:"width"` // 宽度(px)
|
|
||||||
Height int64 `bson:"height" json:"height"` // 高度(px)
|
|
||||||
|
|
||||||
// 位置信息
|
|
||||||
Page string `bson:"page" json:"page"` // 所属页面
|
|
||||||
Section string `bson:"section" json:"section"` // 页面区域
|
|
||||||
Location string `bson:"location" json:"location"` // 具体位置
|
|
||||||
|
|
||||||
// 展示设置
|
|
||||||
MaxAds int `bson:"maxAds" json:"maxAds"` // 最大广告数量
|
|
||||||
RefreshInterval int `bson:"refreshInterval" json:"refreshInterval"` // 刷新间隔(秒)
|
|
||||||
IsLazyLoad bool `bson:"isLazyLoad" json:"isLazyLoad"` // 是否懒加载
|
|
||||||
|
|
||||||
// 定价设置
|
|
||||||
PricingModel string `bson:"pricingModel" json:"pricingModel"` // 计费模型:CPC、CPM、CPA等
|
|
||||||
BasePrice int64 `bson:"basePrice" json:"basePrice"` // 基础价格(分)
|
|
||||||
FloorPrice int64 `bson:"floorPrice" json:"floorPrice"` // 底价(分)
|
|
||||||
PriceUnit string `bson:"priceUnit" json:"priceUnit"` // 价格单位:千次展示、单次点击、单次转化等
|
|
||||||
|
|
||||||
// 展示规则
|
|
||||||
DisplayRules *DisplayRules `bson:"displayRules" json:"displayRules"` // 展示规则
|
|
||||||
|
|
||||||
// 限制配置
|
|
||||||
config.RestrictionConfig `bson:",inline" json:",inline"` // 内联限制配置
|
|
||||||
|
|
||||||
// 其他状态
|
|
||||||
IsExclusive bool `bson:"isExclusive" json:"isExclusive"` // 是否独占广告位
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisplayRules 广告位展示规则
|
|
||||||
type DisplayRules struct {
|
|
||||||
// 频次控制
|
|
||||||
FrequencyCap *FrequencyCap `bson:"frequencyCap" json:"frequencyCap"` // 频次控制
|
|
||||||
|
|
||||||
// 展示条件
|
|
||||||
DisplayConditions []DisplayCondition `bson:"displayConditions" json:"displayConditions"` // 展示条件
|
|
||||||
|
|
||||||
// 排除条件
|
|
||||||
ExcludeConditions []ExcludeCondition `bson:"excludeConditions" json:"excludeConditions"` // 排除条件
|
|
||||||
}
|
|
||||||
|
|
||||||
// FrequencyCap 频次控制
|
|
||||||
type FrequencyCap struct {
|
|
||||||
Impressions int `bson:"impressions" json:"impressions"` // 展示次数
|
|
||||||
TimeWindow int `bson:"timeWindow" json:"timeWindow"` // 时间窗口(小时)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisplayCondition 展示条件
|
|
||||||
type DisplayCondition struct {
|
|
||||||
Type string `bson:"type" json:"type"` // 条件类型
|
|
||||||
Value interface{} `bson:"value" json:"value"` // 条件值
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExcludeCondition 排除条件
|
|
||||||
type ExcludeCondition struct {
|
|
||||||
Type string `bson:"type" json:"type"` // 条件类型
|
|
||||||
Value interface{} `bson:"value" json:"value"` // 条件值
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *AdPosition) GetCollectionName() string {
|
|
||||||
return AdPositionCollection
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/config"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdSourceCollection = "ad_source"
|
|
||||||
|
|
||||||
// AdSource 广告源实体
|
|
||||||
type AdSource struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 广告源名称
|
|
||||||
Code string `bson:"code" json:"code"` // 广告源编码,唯一标识
|
|
||||||
Provider string `bson:"provider" json:"provider"` // 提供商:self(自营)、chuanshanjia(穿山甲)、gdt(腾讯广点通)、baidu(百度)、byteance(字节跳动)等
|
|
||||||
Type string `bson:"type" json:"type"` // 类型:self(自营)、third_party(第三方)、exchange(广告交易平台)、platform_ad_source(平台广告源)
|
|
||||||
Category string `bson:"category" json:"category"` // 分类:network、ssp、dsp、rtb等
|
|
||||||
|
|
||||||
// 连接配置
|
|
||||||
Config string `bson:"config" json:"config"` // 广告源配置(JSON字符串)
|
|
||||||
|
|
||||||
// API配置
|
|
||||||
config.APIConfig `bson:",inline" json:",inline"` // 内联API配置
|
|
||||||
|
|
||||||
// 创意配置
|
|
||||||
config.CreativeConfig `bson:",inline" json:",inline"` // 内联创意配置
|
|
||||||
|
|
||||||
// 广告源能力
|
|
||||||
Capabilities *AdSourceCapabilities `bson:"capabilities" json:"capabilities"` // 广告源能力
|
|
||||||
|
|
||||||
// 支付配置
|
|
||||||
config.PaymentConfig `bson:",inline" json:",inline"` // 内联支付配置
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceCapabilities 广告源能力
|
|
||||||
type AdSourceCapabilities struct {
|
|
||||||
// 广告格式
|
|
||||||
SupportedFormats []AdFormat `bson:"supportedFormats" json:"supportedFormats"` // 支持的广告格式
|
|
||||||
|
|
||||||
// 功能特性
|
|
||||||
RealTimeBidding bool `bson:"realTimeBidding" json:"realTimeBidding"` // 实时竞价
|
|
||||||
HeaderBidding bool `bson:"headerBidding" json:"headerBidding"` // 标题竞价
|
|
||||||
ProgrammaticDirect bool `bson:"programmaticDirect" json:"programmaticDirect"` // 程序化直购
|
|
||||||
PrivateMarketplace bool `bson:"privateMarketplace" json:"privateMarketplace"` // 私有交易市场
|
|
||||||
|
|
||||||
// 质量控制
|
|
||||||
FraudDetection bool `bson:"fraudDetection" json:"fraudDetection"` // 反欺诈检测
|
|
||||||
BrandSafety bool `bson:"brandSafety" json:"brandSafety"` // 品牌安全
|
|
||||||
Viewability bool `bson:"viewability" json:"viewability"` // 可见度验证
|
|
||||||
CreativeApproval bool `bson:"creativeApproval" json:"creativeApproval"` // 创意审核
|
|
||||||
|
|
||||||
// 数据能力
|
|
||||||
AudienceTargeting bool `bson:"audienceTargeting" json:"audienceTargeting"` // 受众定向
|
|
||||||
ContextualTargeting bool `bson:"contextualTargeting" json:"contextualTargeting"` // 上下文定向
|
|
||||||
CrossDeviceTargeting bool `bson:"crossDeviceTargeting" json:"crossDeviceTargeting"` // 跨设备定向
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdFormat 广告格式
|
|
||||||
type AdFormat struct {
|
|
||||||
Type string `bson:"type" json:"type"` // 格式类型:banner、video、native、interstitial等
|
|
||||||
Name string `bson:"name" json:"name"` // 格式名称
|
|
||||||
Width int `bson:"width" json:"width"` // 宽度
|
|
||||||
Height int `bson:"height" json:"height"` // 高度
|
|
||||||
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *AdSource) GetCollectionName() string {
|
|
||||||
return AdSourceCollection
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdTypeCollection = "ad_type"
|
|
||||||
|
|
||||||
// AdType 广告类型实体
|
|
||||||
type AdType struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline"`
|
|
||||||
|
|
||||||
// 广告类型信息
|
|
||||||
Name string `bson:"name" json:"name"` // 广告类型名称
|
|
||||||
Code string `bson:"code" json:"code"` // 广告类型编码
|
|
||||||
Description string `bson:"description" json:"description"` // 广告类型描述
|
|
||||||
Icon string `bson:"icon" json:"icon"` // 广告类型图标
|
|
||||||
|
|
||||||
// 类型配置
|
|
||||||
Category string `bson:"category" json:"category"` // 分类:display, video, native, interstitial
|
|
||||||
Platforms []string `bson:"platforms" json:"platforms"` // 支持的平台
|
|
||||||
Formats []string `bson:"formats" json:"formats"` // 支持格式
|
|
||||||
Dimensions []string `bson:"dimensions" json:"dimensions"` // 尺寸规格
|
|
||||||
|
|
||||||
// 技术要求
|
|
||||||
MaxFileSize int64 `bson:"maxFileSize" json:"maxFileSize"` // 最大文件大小(bytes)
|
|
||||||
MaxDuration int64 `bson:"maxDuration" json:"maxDuration"` // 最大时长(秒)
|
|
||||||
SupportedMimeTypes []string `bson:"supportedMimeTypes" json:"supportedMimeTypes"` // 支持的MIME类型
|
|
||||||
|
|
||||||
// 业务配置
|
|
||||||
BidType string `bson:"bidType" json:"bidType"` // 竞价类型:CPM, CPC, CPA
|
|
||||||
MinBidPrice int64 `bson:"minBidPrice" json:"minBidPrice"` // 最低出价(分)
|
|
||||||
MaxBidPrice int64 `bson:"maxBidPrice" json:"maxBidPrice"` // 最高出价(分)
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active, inactive
|
|
||||||
SortOrder int `bson:"sortOrder" json:"sortOrder"` // 排序顺序
|
|
||||||
|
|
||||||
// 统计信息
|
|
||||||
DailyImpression int64 `bson:"dailyImpression" json:"dailyImpression"` // 日展示量
|
|
||||||
DailyClick int64 `bson:"dailyClick" json:"dailyClick"` // 日点击量
|
|
||||||
|
|
||||||
Remark string `bson:"remark" json:"remark"` // 备注
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/config"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdvertisementCollection = "advertisement"
|
|
||||||
|
|
||||||
// Advertisement 广告实体
|
|
||||||
type Advertisement struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
AdvertiserId string `bson:"advertiserId" json:"advertiserId"` // 广告主ID
|
|
||||||
|
|
||||||
// 广告基本信息
|
|
||||||
Title string `bson:"title" json:"title"` // 广告标题
|
|
||||||
Description string `bson:"description" json:"description"` // 广告描述
|
|
||||||
AdPositionId string `bson:"adPositionId" json:"adPositionId"` // 广告位ID
|
|
||||||
AdType string `bson:"adType" json:"adType"` // 广告类型:图片、视频、文字等
|
|
||||||
AdFormat string `bson:"adFormat" json:"adFormat"` // 广告格式
|
|
||||||
MaterialUrl string `bson:"materialUrl" json:"materialUrl"` // 广告素材URL
|
|
||||||
TargetUrl string `bson:"targetUrl" json:"targetUrl"` // 目标链接(点击跳转或落地页)
|
|
||||||
|
|
||||||
// 平台和广告源信息
|
|
||||||
AdSourceId string `bson:"adSourceId" json:"adSourceId"` // 广告源ID
|
|
||||||
AdPlatformId string `bson:"adPlatformId" json:"adPlatformId"` // 广告平台ID(当广告来自第三方平台时)
|
|
||||||
ExternalAdId string `bson:"externalAdId" json:"externalAdId"` // 外部广告ID(第三方平台的广告ID)
|
|
||||||
AdProvider string `bson:"adProvider" json:"adProvider"` // 广告提供者:self、chuanshanjia、xiaohongshu、douyin等
|
|
||||||
|
|
||||||
// 投放配置
|
|
||||||
config.BudgetConfig `bson:",inline" json:",inline"` // 内联预算配置
|
|
||||||
BidAmount int64 `bson:"bidAmount" json:"bidAmount"` // 出价(分)
|
|
||||||
BillingType string `bson:"billingType" json:"billingType"` // 计费类型:CPC、CPM、CPA等
|
|
||||||
|
|
||||||
// 定向条件
|
|
||||||
Targeting *UnifiedTargeting `bson:"targeting" json:"targeting"` // 统一定向条件
|
|
||||||
|
|
||||||
// 审核状态
|
|
||||||
AuditStatus string `bson:"auditStatus" json:"auditStatus"` // 广告状态:待审核、审核中、已通过、已拒绝、投放中、已暂停、已结束
|
|
||||||
AuditReason string `bson:"auditReason" json:"auditReason"` // 审核不通过原因
|
|
||||||
AuditTime int64 `bson:"auditTime" json:"auditTime"` // 审核时间
|
|
||||||
AuditBy string `bson:"auditBy" json:"auditBy"` // 审核人
|
|
||||||
|
|
||||||
// 限制配置
|
|
||||||
config.RestrictionConfig `bson:",inline" json:",inline"` // 内联限制配置
|
|
||||||
|
|
||||||
// 其他状态信息
|
|
||||||
Status string `bson:"status" json:"status"` // 业务状态:active、inactive、archived
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *Advertisement) GetCollectionName() string {
|
|
||||||
return AdvertisementCollection
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AdvertiserCollection = "advertiser"
|
|
||||||
|
|
||||||
// Advertiser 广告主实体
|
|
||||||
type Advertiser struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 广告主名称
|
|
||||||
ContactName string `bson:"contactName" json:"contactName"` // 联系人姓名
|
|
||||||
ContactPhone string `bson:"contactPhone" json:"contactPhone"` // 联系电话
|
|
||||||
ContactEmail string `bson:"contactEmail" json:"contactEmail"` // 联系邮箱
|
|
||||||
Company string `bson:"company" json:"company"` // 公司名称
|
|
||||||
Scale string `bson:"scale" json:"scale"` // 公司规模
|
|
||||||
|
|
||||||
// 证件信息
|
|
||||||
BusinessLicenseUrl string `bson:"businessLicenseUrl" json:"businessLicenseUrl"` // 营业执照URL
|
|
||||||
ICPLicenseUrl string `bson:"icpLicenseUrl" json:"icpLicenseUrl"` // ICP备案截图URL
|
|
||||||
OtherLicenseUrls []string `bson:"otherLicenseUrls" json:"otherLicenseUrls"` // 其他证件URL
|
|
||||||
|
|
||||||
// 财务信息
|
|
||||||
BankName string `bson:"bankName" json:"bankName"` // 开户银行
|
|
||||||
BankAccount string `bson:"bankAccount" json:"bankAccount"` // 银行账号
|
|
||||||
AccountName string `bson:"accountName" json:"accountName"` // 账户名称
|
|
||||||
|
|
||||||
// 合同信息
|
|
||||||
ContractId string `bson:"contractId" json:"contractId"` // 合同编号
|
|
||||||
ContractType string `bson:"contractType" json:"contractType"` // 合同类型
|
|
||||||
ContractUrl string `bson:"contractUrl" json:"contractUrl"` // 合同文件URL
|
|
||||||
SignDate int64 `bson:"signDate" json:"signDate"` // 签约日期
|
|
||||||
ExpireDate int64 `bson:"expireDate" json:"expireDate"` // 到期日期
|
|
||||||
|
|
||||||
// 审核状态
|
|
||||||
AuditStatus string `bson:"auditStatus" json:"auditStatus"` // 广告主状态:待审核、审核中、已通过、已拒绝、已冻结
|
|
||||||
AuditReason string `bson:"auditReason" json:"auditReason"` // 审核不通过原因
|
|
||||||
AuditTime int64 `bson:"auditTime" json:"auditTime"` // 审核时间
|
|
||||||
AuditBy string `bson:"auditBy" json:"auditBy"` // 审核人
|
|
||||||
|
|
||||||
// 系统信息
|
|
||||||
AccountBalance int64 `bson:"accountBalance" json:"accountBalance"` // 账户余额(分)
|
|
||||||
CreditLimit int64 `bson:"creditLimit" json:"creditLimit"` // 授信额度(分)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *Advertiser) GetCollectionName() string {
|
|
||||||
return AdvertiserCollection
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const AppPlatformConfigCollection = "app_platform_config"
|
|
||||||
|
|
||||||
// AppPlatformConfig 应用平台配置实体
|
|
||||||
type AppPlatformConfig struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 关联信息
|
|
||||||
AppID string `bson:"appId" json:"appId"` // 应用ID
|
|
||||||
PlatformID string `bson:"platformId" json:"platformId"` // 平台ID
|
|
||||||
|
|
||||||
// 配置信息
|
|
||||||
Config string `bson:"config" json:"config"` // 配置信息(JSON字符串)
|
|
||||||
MaxAdsPerReq int `bson:"maxAdsPerReq" json:"maxAdsPerReq"` // 每次请求最大广告数
|
|
||||||
|
|
||||||
// 定向配置
|
|
||||||
TargetingRules string `bson:"targetingRules" json:"targetingRules"` // 定向规则(JSON字符串)
|
|
||||||
|
|
||||||
// 过滤配置
|
|
||||||
FilterRules string `bson:"filterRules" json:"filterRules"` // 过滤规则(JSON字符串)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *AppPlatformConfig) GetCollectionName() string {
|
|
||||||
return AppPlatformConfigCollection
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const ApplicationCollection = "application"
|
|
||||||
|
|
||||||
// Application 应用实体
|
|
||||||
type Application struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 应用基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 应用名称
|
|
||||||
Code string `bson:"code" json:"code"` // 应用编码
|
|
||||||
Description string `bson:"description" json:"description"` // 应用描述
|
|
||||||
AppKey string `bson:"appKey" json:"appKey"` // 应用密钥
|
|
||||||
AppSecret string `bson:"appSecret" json:"appSecret"` // 应用秘钥
|
|
||||||
Platform string `bson:"platform" json:"platform"` // 平台:web、ios、android、h5
|
|
||||||
Version string `bson:"version" json:"version"` // 版本号
|
|
||||||
PackageName string `bson:"packageName" json:"packageName"` // 包名(移动应用)
|
|
||||||
BundleID string `bson:"bundleId" json:"bundleId"` // Bundle ID(iOS应用)
|
|
||||||
AppStoreURL string `bson:"appStoreUrl" json:"appStoreUrl"` // 应用商店URL
|
|
||||||
|
|
||||||
// 应用配置
|
|
||||||
Config string `bson:"config" json:"config"` // 应用配置(JSON字符串)
|
|
||||||
Permissions string `bson:"permissions" json:"permissions"` // 权限配置(JSON字符串)
|
|
||||||
|
|
||||||
// 应用分类和标签
|
|
||||||
Categories []string `bson:"categories" json:"categories"` // 应用分类
|
|
||||||
Tags []string `bson:"tags" json:"tags"` // 标签
|
|
||||||
AdTypes []string `bson:"adTypes" json:"adTypes"` // 支持的广告类型
|
|
||||||
|
|
||||||
// 回调配置
|
|
||||||
CallbackURL string `bson:"callbackUrl" json:"callbackUrl"` // 回调URL
|
|
||||||
|
|
||||||
// 应用特定统计
|
|
||||||
DailyActiveUsers int64 `bson:"dailyActiveUsers" json:"dailyActiveUsers"` // 日活用户数
|
|
||||||
MonthlyActiveUsers int64 `bson:"monthlyActiveUsers" json:"monthlyActiveUsers"` // 月活用户数
|
|
||||||
TotalRequests int64 `bson:"totalRequests" json:"totalRequests"` // 总请求数
|
|
||||||
DailyRequests int64 `bson:"dailyRequests" json:"dailyRequests"` // 日请求数
|
|
||||||
MonthlyRequests int64 `bson:"monthlyRequests" json:"monthlyRequests"` // 月请求数
|
|
||||||
|
|
||||||
// 联系信息
|
|
||||||
ContactName string `bson:"contactName" json:"contactName"` // 联系人姓名
|
|
||||||
ContactEmail string `bson:"contactEmail" json:"contactEmail"` // 联系邮箱
|
|
||||||
ContactPhone string `bson:"contactPhone" json:"contactPhone"` // 联系电话
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (a *Application) GetCollectionName() string {
|
|
||||||
return ApplicationCollection
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package attribution
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClickLog 点击日志实体(CID核心表,按 day 分区)
|
||||||
|
type ClickLog struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
ClickID string `orm:"click_id" json:"clickId" description:"对外CID"`
|
||||||
|
RequestID string `orm:"request_id" json:"requestId" description:"广告平台请求号(去重键)"`
|
||||||
|
Channel string `orm:"channel" json:"channel" description:"投放通道 external外投/self_dsp自有"`
|
||||||
|
AdPlatform string `orm:"ad_platform" json:"adPlatform" description:"广告平台 douyin/xiaohongshu/kuaishou/self_dsp"`
|
||||||
|
AccountID string `orm:"account_id" json:"accountId" description:"广告账户ID"`
|
||||||
|
CampaignID string `orm:"campaign_id" json:"campaignId" description:"平台侧计划ID(透传)"`
|
||||||
|
LocalCampaignID int64 `orm:"local_campaign_id" json:"localCampaignId" description:"本地计划ID(回传路由)"`
|
||||||
|
LocalAdID int64 `orm:"local_ad_id" json:"localAdId" description:"本地广告ID(DSP必填,外投按映射回填)"`
|
||||||
|
LocalCreativeID int64 `orm:"local_creative_id" json:"localCreativeId" description:"本地创意ID(DSP必填,外投按映射回填)"`
|
||||||
|
SlotID int64 `orm:"slot_id" json:"slotId" description:"自有DSP广告位ID"`
|
||||||
|
AdGroupID string `orm:"ad_group_id" json:"adGroupId" description:"广告组ID"`
|
||||||
|
AdID string `orm:"ad_id" json:"adId" description:"广告ID"`
|
||||||
|
CreativeID string `orm:"creative_id" json:"creativeId" description:"创意ID"`
|
||||||
|
DeviceID string `orm:"device_id" json:"deviceId" description:"设备ID oaid/imei/idfa"`
|
||||||
|
IP string `orm:"ip" json:"ip" description:"点击IP"`
|
||||||
|
UA string `orm:"ua" json:"ua" description:"用户代理"`
|
||||||
|
LandingURL string `orm:"landing_url" json:"landingUrl" description:"原始落地页URL"`
|
||||||
|
RedirectURL string `orm:"redirect_url" json:"redirectUrl" description:"跳转下游URL(带click_id)"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"平台透传参数(JSON)"`
|
||||||
|
Day *gtime.Time `orm:"day" json:"day" description:"分区日期"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClickLogCol 点击日志表字段定义
|
||||||
|
type ClickLogCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
ClickID string
|
||||||
|
RequestID string
|
||||||
|
Channel string
|
||||||
|
AdPlatform string
|
||||||
|
AccountID string
|
||||||
|
CampaignID string
|
||||||
|
LocalCampaignID string
|
||||||
|
LocalAdID string
|
||||||
|
LocalCreativeID string
|
||||||
|
SlotID string
|
||||||
|
AdGroupID string
|
||||||
|
AdID string
|
||||||
|
CreativeID string
|
||||||
|
DeviceID string
|
||||||
|
IP string
|
||||||
|
UA string
|
||||||
|
LandingURL string
|
||||||
|
RedirectURL string
|
||||||
|
Extra string
|
||||||
|
Day string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClickLogCols 点击日志表字段常量
|
||||||
|
var ClickLogCols = ClickLogCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
ClickID: "click_id",
|
||||||
|
RequestID: "request_id",
|
||||||
|
Channel: "channel",
|
||||||
|
AdPlatform: "ad_platform",
|
||||||
|
AccountID: "account_id",
|
||||||
|
CampaignID: "campaign_id",
|
||||||
|
LocalCampaignID: "local_campaign_id",
|
||||||
|
LocalAdID: "local_ad_id",
|
||||||
|
LocalCreativeID: "local_creative_id",
|
||||||
|
SlotID: "slot_id",
|
||||||
|
AdGroupID: "ad_group_id",
|
||||||
|
AdID: "ad_id",
|
||||||
|
CreativeID: "creative_id",
|
||||||
|
DeviceID: "device_id",
|
||||||
|
IP: "ip",
|
||||||
|
UA: "ua",
|
||||||
|
LandingURL: "landing_url",
|
||||||
|
RedirectURL: "redirect_url",
|
||||||
|
Extra: "extra",
|
||||||
|
Day: "day",
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package attribution
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConversionOrder 转化订单实体(电商平台回传的订单/转化)
|
||||||
|
type ConversionOrder struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
ConversionID string `orm:"conversion_id" json:"conversionId" description:"转化事件ID(幂等键)"`
|
||||||
|
OrderID string `orm:"order_id" json:"orderId" description:"电商平台订单号"`
|
||||||
|
CommercePlatform string `orm:"commerce_platform" json:"commercePlatform" description:"电商平台 jd/taobao"`
|
||||||
|
ClickID string `orm:"click_id" json:"clickId" description:"关联点击CID"`
|
||||||
|
LocalCampaignID int64 `orm:"local_campaign_id" json:"localCampaignId" description:"本地计划ID(回传路由)"`
|
||||||
|
AdAccountID int64 `orm:"ad_account_id" json:"adAccountId" description:"广告账户ID(回传凭据)"`
|
||||||
|
DeviceID string `orm:"device_id" json:"deviceId" description:"设备ID(无click_id时兜底归因)"`
|
||||||
|
ItemID string `orm:"item_id" json:"itemId" description:"商品ID"`
|
||||||
|
ItemName string `orm:"item_name" json:"itemName" description:"商品名称"`
|
||||||
|
SkuID string `orm:"sku_id" json:"skuId" description:"SKU ID"`
|
||||||
|
ConversionType string `orm:"conversion_type" json:"conversionType" description:"转化类型 order/pay/refund/cart"`
|
||||||
|
OrderAmount int64 `orm:"order_amount" json:"orderAmount" description:"订单金额(分)"`
|
||||||
|
PayAmount int64 `orm:"pay_amount" json:"payAmount" description:"实付金额(分)"`
|
||||||
|
Quantity int `orm:"quantity" json:"quantity" description:"商品数量"`
|
||||||
|
OrderStatus string `orm:"order_status" json:"orderStatus" description:"订单状态 paid/refunded/canceled"`
|
||||||
|
AttributedBy string `orm:"attributed_by" json:"attributedBy" description:"归因方式 click_id/device/manual"`
|
||||||
|
ReportStatus int `orm:"report_status" json:"reportStatus" description:"回传状态 0待回传 1已回传 2失败"`
|
||||||
|
ReportCount int `orm:"report_count" json:"reportCount" description:"回传次数"`
|
||||||
|
FirstClickTime int64 `orm:"first_click_time" json:"firstClickTime" description:"首次点击时间戳"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConversionOrderCol 转化订单表字段定义
|
||||||
|
type ConversionOrderCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
ConversionID string
|
||||||
|
OrderID string
|
||||||
|
CommercePlatform string
|
||||||
|
ClickID string
|
||||||
|
LocalCampaignID string
|
||||||
|
AdAccountID string
|
||||||
|
DeviceID string
|
||||||
|
ItemID string
|
||||||
|
ItemName string
|
||||||
|
SkuID string
|
||||||
|
ConversionType string
|
||||||
|
OrderAmount string
|
||||||
|
PayAmount string
|
||||||
|
Quantity string
|
||||||
|
OrderStatus string
|
||||||
|
AttributedBy string
|
||||||
|
ReportStatus string
|
||||||
|
ReportCount string
|
||||||
|
FirstClickTime string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConversionOrderCols 转化订单表字段常量
|
||||||
|
var ConversionOrderCols = ConversionOrderCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
ConversionID: "conversion_id",
|
||||||
|
OrderID: "order_id",
|
||||||
|
CommercePlatform: "commerce_platform",
|
||||||
|
ClickID: "click_id",
|
||||||
|
LocalCampaignID: "local_campaign_id",
|
||||||
|
AdAccountID: "ad_account_id",
|
||||||
|
DeviceID: "device_id",
|
||||||
|
ItemID: "item_id",
|
||||||
|
ItemName: "item_name",
|
||||||
|
SkuID: "sku_id",
|
||||||
|
ConversionType: "conversion_type",
|
||||||
|
OrderAmount: "order_amount",
|
||||||
|
PayAmount: "pay_amount",
|
||||||
|
Quantity: "quantity",
|
||||||
|
OrderStatus: "order_status",
|
||||||
|
AttributedBy: "attributed_by",
|
||||||
|
ReportStatus: "report_status",
|
||||||
|
ReportCount: "report_count",
|
||||||
|
FirstClickTime: "first_click_time",
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package attribution
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReportTask 转化回传任务实体(回传广告平台的任务队列,失败退避重试)
|
||||||
|
type ReportTask struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
ConversionID string `orm:"conversion_id" json:"conversionId" description:"关联转化事件ID"`
|
||||||
|
ClickID string `orm:"click_id" json:"clickId" description:"点击CID"`
|
||||||
|
AdPlatform string `orm:"ad_platform" json:"adPlatform" description:"回传目标广告平台"`
|
||||||
|
AdAccountID int64 `orm:"ad_account_id" json:"adAccountId" description:"广告账户ID(回传凭据)"`
|
||||||
|
CampaignID int64 `orm:"campaign_id" json:"campaignId" description:"回传目标本地计划ID"`
|
||||||
|
TaskType string `orm:"task_type" json:"taskType" description:"回传类型 conversion/refund"`
|
||||||
|
Status int `orm:"status" json:"status" description:"状态 0待回传 1回传中 2成功 3失败"`
|
||||||
|
RetryCount int `orm:"retry_count" json:"retryCount" description:"重试次数"`
|
||||||
|
NextRetryAt int64 `orm:"next_retry_at" json:"nextRetryAt" description:"下次重试时间戳"`
|
||||||
|
RequestBody string `orm:"request_body" json:"requestBody" description:"回传请求体(JSON)"`
|
||||||
|
ResponseBody string `orm:"response_body" json:"responseBody" description:"回传响应体(JSON)"`
|
||||||
|
TraceID string `orm:"trace_id" json:"traceId" description:"链路追踪ID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportTaskCol 回传任务表字段定义
|
||||||
|
type ReportTaskCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
ConversionID string
|
||||||
|
ClickID string
|
||||||
|
AdPlatform string
|
||||||
|
AdAccountID string
|
||||||
|
CampaignID string
|
||||||
|
TaskType string
|
||||||
|
Status string
|
||||||
|
RetryCount string
|
||||||
|
NextRetryAt string
|
||||||
|
RequestBody string
|
||||||
|
ResponseBody string
|
||||||
|
TraceID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReportTaskCols 回传任务表字段常量
|
||||||
|
var ReportTaskCols = ReportTaskCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
ConversionID: "conversion_id",
|
||||||
|
ClickID: "click_id",
|
||||||
|
AdPlatform: "ad_platform",
|
||||||
|
AdAccountID: "ad_account_id",
|
||||||
|
CampaignID: "campaign_id",
|
||||||
|
TaskType: "task_type",
|
||||||
|
Status: "status",
|
||||||
|
RetryCount: "retry_count",
|
||||||
|
NextRetryAt: "next_retry_at",
|
||||||
|
RequestBody: "request_body",
|
||||||
|
ResponseBody: "response_body",
|
||||||
|
TraceID: "trace_id",
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaterialVerifyLog 素材校验日志实体
|
||||||
|
type MaterialVerifyLog struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
TenantID int64 `orm:"tenant_id" json:"tenantId" description:"租户ID"`
|
||||||
|
MaterialType string `orm:"material_type" json:"materialType" description:"素材类型 IMAGE/VIDEO"`
|
||||||
|
MaterialID string `orm:"material_id" json:"materialId" description:"素材ID"`
|
||||||
|
SourceTable string `orm:"source_table" json:"sourceTable" description:"来源表"`
|
||||||
|
SourceID int64 `orm:"source_id" json:"sourceId" description:"原表主键ID"`
|
||||||
|
AccountID int64 `orm:"account_id" json:"accountId" description:"账户ID"`
|
||||||
|
TaskID string `orm:"task_id" json:"taskId" description:"易盾任务ID"`
|
||||||
|
RequestParams string `orm:"request_params" json:"requestParams" description:"请求入参"`
|
||||||
|
ResponseResult string `orm:"response_result" json:"responseResult" description:"响应出参"`
|
||||||
|
VerifyStatus string `orm:"verify_status" json:"verifyStatus" description:"校验状态"`
|
||||||
|
Suggestion int `orm:"suggestion" json:"suggestion" description:"处置建议"`
|
||||||
|
Label int `orm:"label" json:"label" description:"垃圾类型"`
|
||||||
|
ResultType int `orm:"result_type" json:"resultType" description:"结果类型"`
|
||||||
|
ErrorMsg string `orm:"error_msg" json:"errorMsg" description:"错误信息"`
|
||||||
|
CheckTime int64 `orm:"check_time" json:"checkTime" description:"审核时间戳"`
|
||||||
|
DurationMs int64 `orm:"duration_ms" json:"durationMs" description:"处理耗时(毫秒)"`
|
||||||
|
RiskDescription string `orm:"risk_description" json:"riskDescription" description:"风险描述(易盾返回)"`
|
||||||
|
|
||||||
|
// 扩展字段(用于展示)
|
||||||
|
PreviewURL string `orm:"-" json:"previewUrl" description:"预览URL"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaterialVerifyLogCol 日志表字段定义
|
||||||
|
type MaterialVerifyLogCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
TenantID string
|
||||||
|
MaterialType string
|
||||||
|
MaterialID string
|
||||||
|
SourceTable string
|
||||||
|
SourceID string
|
||||||
|
AccountID string
|
||||||
|
TaskID string
|
||||||
|
RequestParams string
|
||||||
|
ResponseResult string
|
||||||
|
VerifyStatus string
|
||||||
|
Suggestion string
|
||||||
|
Label string
|
||||||
|
ResultType string
|
||||||
|
ErrorMsg string
|
||||||
|
CheckTime string
|
||||||
|
DurationMs string
|
||||||
|
RiskDescription string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaterialVerifyLogCols 日志表字段常量
|
||||||
|
var MaterialVerifyLogCols = MaterialVerifyLogCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
TenantID: "tenant_id",
|
||||||
|
MaterialType: "material_type",
|
||||||
|
MaterialID: "material_id",
|
||||||
|
SourceTable: "source_table",
|
||||||
|
SourceID: "source_id",
|
||||||
|
AccountID: "account_id",
|
||||||
|
TaskID: "task_id",
|
||||||
|
RequestParams: "request_params",
|
||||||
|
ResponseResult: "response_result",
|
||||||
|
VerifyStatus: "verify_status",
|
||||||
|
Suggestion: "suggestion",
|
||||||
|
Label: "label",
|
||||||
|
ResultType: "result_type",
|
||||||
|
ErrorMsg: "error_msg",
|
||||||
|
CheckTime: "check_time",
|
||||||
|
DurationMs: "duration_ms",
|
||||||
|
RiskDescription: "risk_description",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 素材类型常量
|
||||||
|
const (
|
||||||
|
MaterialTypeImage = "IMAGE"
|
||||||
|
MaterialTypeVideo = "VIDEO"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 校验状态常量
|
||||||
|
const (
|
||||||
|
VerifyStatusPending = "PENDING" // 待校验
|
||||||
|
VerifyStatusReview = "REVIEW" // 嫌疑,需人工复核
|
||||||
|
VerifyStatusVerified = "VERIFIED" // 校验通过
|
||||||
|
VerifyStatusRejected = "REJECTED" // 校验不通过
|
||||||
|
)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentAccountRelation 腾讯广告账户关系实体(来源:data-engine.tencent_account_relation)
|
||||||
|
type TencentAccountRelation struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
AccountID int64 `orm:"account_id" json:"accountId" description:"账户ID"`
|
||||||
|
CorporationName string `orm:"corporation_name" json:"corporationName" description:"公司名称"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentAccountRelationCol 账户关系表字段定义
|
||||||
|
type TencentAccountRelationCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
AccountID string
|
||||||
|
CorporationName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentAccountRelationCols 账户关系表字段常量
|
||||||
|
var TencentAccountRelationCols = TencentAccountRelationCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
AccountID: "account_id",
|
||||||
|
CorporationName: "corporation_name",
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentContentCheckLog 送检日志实体(来源:data-engine.tencent_content_check_log)
|
||||||
|
type TencentContentCheckLog struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 来源标识
|
||||||
|
SourceTable string `orm:"source_table" json:"sourceTable" description:"来源表标识:tencent_image/tencent_video"`
|
||||||
|
SourceID int64 `orm:"source_id" json:"sourceId" description:"原数据ID(关联业务表数据)"`
|
||||||
|
// 送检信息
|
||||||
|
RequestURL string `orm:"request_url" json:"requestUrl" description:"送检请求路径(接口地址)"`
|
||||||
|
RequestParam string `orm:"request_param" json:"requestParam" description:"送检入参(完整请求参数,JSON格式)"`
|
||||||
|
ResponseData string `orm:"response_data" json:"responseData" description:"送检出参(完整接口返回结果,JSON格式)"`
|
||||||
|
Status string `orm:"status" json:"status" description:"送检状态:pending-待送检, submitting-送检中, success-送检成功, failed-送检失败"`
|
||||||
|
CheckTime int64 `orm:"check_time" json:"checkTime" description:"送检时间(时间戳,毫秒)"`
|
||||||
|
FailReason string `orm:"fail_reason" json:"failReason" description:"失败原因(可选,记录接口报错信息)"`
|
||||||
|
TaskID string `orm:"task_id" json:"taskId" description:"易盾返回的任务ID"`
|
||||||
|
// 检测结果
|
||||||
|
Suggestion int `orm:"suggestion" json:"suggestion" description:"检测结果建议:0-通过,1-嫌疑,2-不通过"`
|
||||||
|
Label int `orm:"label" json:"label" description:"检测标签"`
|
||||||
|
ResultType int `orm:"result_type" json:"resultType" description:"结果类型:1-机器结果,2-人审结果"`
|
||||||
|
Duration int64 `orm:"duration" json:"duration" description:"送检耗时(毫秒)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentContentCheckLogCol 送检日志表字段定义
|
||||||
|
type TencentContentCheckLogCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
SourceTable string
|
||||||
|
SourceID string
|
||||||
|
RequestURL string
|
||||||
|
RequestParam string
|
||||||
|
ResponseData string
|
||||||
|
Status string
|
||||||
|
CheckTime string
|
||||||
|
FailReason string
|
||||||
|
TaskID string
|
||||||
|
Suggestion string
|
||||||
|
Label string
|
||||||
|
ResultType string
|
||||||
|
Duration string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentContentCheckLogCols 送检日志表字段常量
|
||||||
|
var TencentContentCheckLogCols = TencentContentCheckLogCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
SourceTable: "source_table",
|
||||||
|
SourceID: "source_id",
|
||||||
|
RequestURL: "request_url",
|
||||||
|
RequestParam: "request_param",
|
||||||
|
ResponseData: "response_data",
|
||||||
|
Status: "status",
|
||||||
|
CheckTime: "check_time",
|
||||||
|
FailReason: "fail_reason",
|
||||||
|
TaskID: "task_id",
|
||||||
|
Suggestion: "suggestion",
|
||||||
|
Label: "label",
|
||||||
|
ResultType: "result_type",
|
||||||
|
Duration: "duration",
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentImage 图片素材实体(来源:data-engine.tencent_image)
|
||||||
|
type TencentImage struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段 - 匹配现有表结构
|
||||||
|
ImageID string `orm:"image_id" json:"imageId" description:"图片ID"`
|
||||||
|
AccountID int64 `orm:"account_id" json:"accountId" description:"账户ID"`
|
||||||
|
Width int `orm:"width" json:"width" description:"宽度"`
|
||||||
|
Height int `orm:"height" json:"height" description:"高度"`
|
||||||
|
FileSize int64 `orm:"file_size" json:"fileSize" description:"文件大小"`
|
||||||
|
Type string `orm:"type" json:"type" description:"图片类型"`
|
||||||
|
Signature string `orm:"signature" json:"signature" description:"签名"`
|
||||||
|
Description string `orm:"description" json:"description" description:"描述"`
|
||||||
|
SourceSignature string `orm:"source_signature" json:"sourceSignature" description:"源签名"`
|
||||||
|
PreviewURL string `orm:"preview_url" json:"previewUrl" description:"预览URL"`
|
||||||
|
ThumbPreviewURL string `orm:"thumb_preview_url" json:"thumbPreviewUrl" description:"缩略图URL"`
|
||||||
|
SourceType string `orm:"source_type" json:"sourceType" description:"来源类型"`
|
||||||
|
ImageUsage string `orm:"image_usage" json:"imageUsage" description:"图片用途"`
|
||||||
|
CreatedTime int64 `orm:"created_time" json:"createdTime" description:"创建时间戳"`
|
||||||
|
LastModifiedTime int64 `orm:"last_modified_time" json:"lastModifiedTime" description:"最后修改时间戳"`
|
||||||
|
ProductCatalogID int64 `orm:"product_catalog_id" json:"productCatalogId" description:"产品目录ID"`
|
||||||
|
ProductOuterID string `orm:"product_outer_id" json:"productOuterId" description:"产品外部ID"`
|
||||||
|
SourceReferenceID string `orm:"source_reference_id" json:"sourceReferenceId" description:"源引用ID"`
|
||||||
|
OwnerAccountID string `orm:"owner_account_id" json:"ownerAccountId" description:"所有者账户ID"`
|
||||||
|
VerifyStatus string `orm:"verify_status" json:"verifyStatus" description:"审核状态"`
|
||||||
|
SampleAspectRatio string `orm:"sample_aspect_ratio" json:"sampleAspectRatio" description:"示例宽高比"`
|
||||||
|
SourceMaterialID string `orm:"source_material_id" json:"sourceMaterialId" description:"源素材ID"`
|
||||||
|
NewSourceType string `orm:"new_source_type" json:"newSourceType" description:"新来源类型"`
|
||||||
|
FirstPublicationStatus string `orm:"first_publication_status" json:"firstPublicationStatus" description:"首次发布状态"`
|
||||||
|
QualityStatus string `orm:"quality_status" json:"qualityStatus" description:"质量状态"`
|
||||||
|
SimilarityStatus string `orm:"similarity_status" json:"similarityStatus" description:"相似度状态"`
|
||||||
|
UserAigcStatus string `orm:"user_aigc_status" json:"userAigcStatus" description:"用户AIGC状态"`
|
||||||
|
SystemAigcStatus string `orm:"system_aigc_status" json:"systemAigcStatus" description:"系统AIGC状态"`
|
||||||
|
AigcSource string `orm:"aigc_source" json:"aigcSource" description:"AIGC来源"`
|
||||||
|
AigcFlag string `orm:"aigc_flag" json:"aigcFlag" description:"AIGC标志"`
|
||||||
|
MuseAigcVersion int `orm:"muse_aigc_version" json:"museAigcVersion" description:"Muse AIGC版本"`
|
||||||
|
AigcType int `orm:"aigc_type" json:"aigcType" description:"AIGC类型"`
|
||||||
|
|
||||||
|
// 内容检测相关字段(扩展字段,用于存储检测结果)
|
||||||
|
// 注意:如果表中没有这些字段,需要通过 content_check_log 表来存储检测结果
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentImageCol 图片素材表字段定义
|
||||||
|
type TencentImageCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
ImageID string
|
||||||
|
AccountID string
|
||||||
|
Width string
|
||||||
|
Height string
|
||||||
|
FileSize string
|
||||||
|
Type string
|
||||||
|
Signature string
|
||||||
|
Description string
|
||||||
|
SourceSignature string
|
||||||
|
PreviewURL string
|
||||||
|
ThumbPreviewURL string
|
||||||
|
SourceType string
|
||||||
|
ImageUsage string
|
||||||
|
CreatedTime string
|
||||||
|
LastModifiedTime string
|
||||||
|
ProductCatalogID string
|
||||||
|
ProductOuterID string
|
||||||
|
SourceReferenceID string
|
||||||
|
OwnerAccountID string
|
||||||
|
VerifyStatus string
|
||||||
|
SampleAspectRatio string
|
||||||
|
SourceMaterialID string
|
||||||
|
NewSourceType string
|
||||||
|
FirstPublicationStatus string
|
||||||
|
QualityStatus string
|
||||||
|
SimilarityStatus string
|
||||||
|
UserAigcStatus string
|
||||||
|
SystemAigcStatus string
|
||||||
|
AigcSource string
|
||||||
|
AigcFlag string
|
||||||
|
MuseAigcVersion string
|
||||||
|
AigcType string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentImageCols 图片素材表字段常量
|
||||||
|
var TencentImageCols = TencentImageCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
ImageID: "image_id",
|
||||||
|
AccountID: "account_id",
|
||||||
|
Width: "width",
|
||||||
|
Height: "height",
|
||||||
|
FileSize: "file_size",
|
||||||
|
Type: "type",
|
||||||
|
Signature: "signature",
|
||||||
|
Description: "description",
|
||||||
|
SourceSignature: "source_signature",
|
||||||
|
PreviewURL: "preview_url",
|
||||||
|
ThumbPreviewURL: "thumb_preview_url",
|
||||||
|
SourceType: "source_type",
|
||||||
|
ImageUsage: "image_usage",
|
||||||
|
CreatedTime: "created_time",
|
||||||
|
LastModifiedTime: "last_modified_time",
|
||||||
|
ProductCatalogID: "product_catalog_id",
|
||||||
|
ProductOuterID: "product_outer_id",
|
||||||
|
SourceReferenceID: "source_reference_id",
|
||||||
|
OwnerAccountID: "owner_account_id",
|
||||||
|
VerifyStatus: "verify_status",
|
||||||
|
SampleAspectRatio: "sample_aspect_ratio",
|
||||||
|
SourceMaterialID: "source_material_id",
|
||||||
|
NewSourceType: "new_source_type",
|
||||||
|
FirstPublicationStatus: "first_publication_status",
|
||||||
|
QualityStatus: "quality_status",
|
||||||
|
SimilarityStatus: "similarity_status",
|
||||||
|
UserAigcStatus: "user_aigc_status",
|
||||||
|
SystemAigcStatus: "system_aigc_status",
|
||||||
|
AigcSource: "aigc_source",
|
||||||
|
AigcFlag: "aigc_flag",
|
||||||
|
MuseAigcVersion: "muse_aigc_version",
|
||||||
|
AigcType: "aigc_type",
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TencentVideo 视频素材实体(来源:data-engine.tencent_video)
|
||||||
|
type TencentVideo struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段 - 匹配现有表结构
|
||||||
|
VideoID string `orm:"video_id" json:"videoId" description:"视频ID"`
|
||||||
|
AccountID int64 `orm:"account_id" json:"accountId" description:"账户ID"`
|
||||||
|
Width int `orm:"width" json:"width" description:"宽度"`
|
||||||
|
Height int `orm:"height" json:"height" description:"高度"`
|
||||||
|
VideoFrames int `orm:"video_frames" json:"videoFrames" description:"视频帧数"`
|
||||||
|
VideoFps int `orm:"video_fps" json:"videoFps" description:"帧率"`
|
||||||
|
VideoCodec string `orm:"video_codec" json:"videoCodec" description:"视频编码"`
|
||||||
|
VideoBitRate int64 `orm:"video_bit_rate" json:"videoBitRate" description:"视频码率"`
|
||||||
|
AudioCodec string `orm:"audio_codec" json:"audioCodec" description:"音频编码"`
|
||||||
|
AudioBitRate int64 `orm:"audio_bit_rate" json:"audioBitRate" description:"音频码率"`
|
||||||
|
FileSize int64 `orm:"file_size" json:"fileSize" description:"文件大小"`
|
||||||
|
Type string `orm:"type" json:"type" description:"媒体类型"`
|
||||||
|
Signature string `orm:"signature" json:"signature" description:"签名"`
|
||||||
|
SystemStatus string `orm:"system_status" json:"systemStatus" description:"系统状态"`
|
||||||
|
Description string `orm:"description" json:"description" description:"描述"`
|
||||||
|
PreviewURL string `orm:"preview_url" json:"previewUrl" description:"预览URL"`
|
||||||
|
KeyFrameImageURL string `orm:"key_frame_image_url" json:"keyFrameImageUrl" description:"关键帧图片URL"`
|
||||||
|
CreatedTime int64 `orm:"created_time" json:"createdTime" description:"创建时间戳"`
|
||||||
|
LastModifiedTime int64 `orm:"last_modified_time" json:"lastModifiedTime" description:"最后修改时间戳"`
|
||||||
|
VideoProfileName string `orm:"video_profile_name" json:"videoProfileName" description:"视频配置名称"`
|
||||||
|
AudioSampleRate int `orm:"audio_sample_rate" json:"audioSampleRate" description:"音频采样率"`
|
||||||
|
MaxKeyframeInterval int `orm:"max_keyframe_interval" json:"maxKeyframeInterval" description:"最大关键帧间隔"`
|
||||||
|
MinKeyframeInterval int `orm:"min_keyframe_interval" json:"minKeyframeInterval" description:"最小关键帧间隔"`
|
||||||
|
SampleAspectRatio string `orm:"sample_aspect_ratio" json:"sampleAspectRatio" description:"示例宽高比"`
|
||||||
|
AudioProfileName string `orm:"audio_profile_name" json:"audioProfileName" description:"音频配置名称"`
|
||||||
|
ScanType string `orm:"scan_type" json:"scanType" description:"扫描类型"`
|
||||||
|
ImageDurationMs int64 `orm:"image_duration_millisecond" json:"imageDurationMs" description:"图片时长(毫秒)"`
|
||||||
|
AudioDurationMs int64 `orm:"audio_duration_millisecond" json:"audioDurationMs" description:"音频时长(毫秒)"`
|
||||||
|
SourceType string `orm:"source_type" json:"sourceType" description:"来源类型"`
|
||||||
|
ProductCatalogID string `orm:"product_catalog_id" json:"productCatalogId" description:"产品目录ID"`
|
||||||
|
ProductOuterID string `orm:"product_outer_id" json:"productOuterId" description:"产品外部ID"`
|
||||||
|
SourceReferenceID string `orm:"source_reference_id" json:"sourceReferenceId" description:"源引用ID"`
|
||||||
|
OwnerAccountID string `orm:"owner_account_id" json:"ownerAccountId" description:"所有者账户ID"`
|
||||||
|
VerifyStatus string `orm:"verify_status" json:"verifyStatus" description:"审核状态"`
|
||||||
|
SourceMaterialID string `orm:"source_material_id" json:"sourceMaterialId" description:"源素材ID"`
|
||||||
|
NewSourceType string `orm:"new_source_type" json:"newSourceType" description:"新来源类型"`
|
||||||
|
AigcType int `orm:"aigc_type" json:"aigcType" description:"AIGC类型"`
|
||||||
|
FirstPublicationStatus string `orm:"first_publication_status" json:"firstPublicationStatus" description:"首次发布状态"`
|
||||||
|
QualityStatus string `orm:"quality_status" json:"qualityStatus" description:"质量状态"`
|
||||||
|
CoverID string `orm:"cover_id" json:"coverId" description:"封面ID"`
|
||||||
|
SimilarityStatus string `orm:"similarity_status" json:"similarityStatus" description:"相似度状态"`
|
||||||
|
UserAigcStatus string `orm:"user_aigc_status" json:"userAigcStatus" description:"用户AIGC状态"`
|
||||||
|
SystemAigcStatus string `orm:"system_aigc_status" json:"systemAigcStatus" description:"系统AIGC状态"`
|
||||||
|
AigcSource string `orm:"aigc_source" json:"aigcSource" description:"AIGC来源"`
|
||||||
|
AigcFlag string `orm:"aigc_flag" json:"aigcFlag" description:"AIGC标志"`
|
||||||
|
MuseAigcVersion int `orm:"muse_aigc_version" json:"museAigcVersion" description:"Muse AIGC版本"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentVideoCol 视频素材表字段定义
|
||||||
|
type TencentVideoCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
VideoID string
|
||||||
|
AccountID string
|
||||||
|
Width string
|
||||||
|
Height string
|
||||||
|
VideoFrames string
|
||||||
|
VideoFps string
|
||||||
|
VideoCodec string
|
||||||
|
VideoBitRate string
|
||||||
|
AudioCodec string
|
||||||
|
AudioBitRate string
|
||||||
|
FileSize string
|
||||||
|
Type string
|
||||||
|
Signature string
|
||||||
|
SystemStatus string
|
||||||
|
Description string
|
||||||
|
PreviewURL string
|
||||||
|
KeyFrameImageURL string
|
||||||
|
CreatedTime string
|
||||||
|
LastModifiedTime string
|
||||||
|
VideoProfileName string
|
||||||
|
AudioSampleRate string
|
||||||
|
MaxKeyframeInterval string
|
||||||
|
MinKeyframeInterval string
|
||||||
|
SampleAspectRatio string
|
||||||
|
AudioProfileName string
|
||||||
|
ScanType string
|
||||||
|
ImageDurationMs string
|
||||||
|
AudioDurationMs string
|
||||||
|
SourceType string
|
||||||
|
ProductCatalogID string
|
||||||
|
ProductOuterID string
|
||||||
|
SourceReferenceID string
|
||||||
|
OwnerAccountID string
|
||||||
|
VerifyStatus string
|
||||||
|
SourceMaterialID string
|
||||||
|
NewSourceType string
|
||||||
|
AigcType string
|
||||||
|
FirstPublicationStatus string
|
||||||
|
QualityStatus string
|
||||||
|
CoverID string
|
||||||
|
SimilarityStatus string
|
||||||
|
UserAigcStatus string
|
||||||
|
SystemAigcStatus string
|
||||||
|
AigcSource string
|
||||||
|
AigcFlag string
|
||||||
|
MuseAigcVersion string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TencentVideoCols 视频素材表字段常量
|
||||||
|
var TencentVideoCols = TencentVideoCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
VideoID: "video_id",
|
||||||
|
AccountID: "account_id",
|
||||||
|
Width: "width",
|
||||||
|
Height: "height",
|
||||||
|
VideoFrames: "video_frames",
|
||||||
|
VideoFps: "video_fps",
|
||||||
|
VideoCodec: "video_codec",
|
||||||
|
VideoBitRate: "video_bit_rate",
|
||||||
|
AudioCodec: "audio_codec",
|
||||||
|
AudioBitRate: "audio_bit_rate",
|
||||||
|
FileSize: "file_size",
|
||||||
|
Type: "type",
|
||||||
|
Signature: "signature",
|
||||||
|
SystemStatus: "system_status",
|
||||||
|
Description: "description",
|
||||||
|
PreviewURL: "preview_url",
|
||||||
|
KeyFrameImageURL: "key_frame_image_url",
|
||||||
|
CreatedTime: "created_time",
|
||||||
|
LastModifiedTime: "last_modified_time",
|
||||||
|
VideoProfileName: "video_profile_name",
|
||||||
|
AudioSampleRate: "audio_sample_rate",
|
||||||
|
MaxKeyframeInterval: "max_keyframe_interval",
|
||||||
|
MinKeyframeInterval: "min_keyframe_interval",
|
||||||
|
SampleAspectRatio: "sample_aspect_ratio",
|
||||||
|
AudioProfileName: "audio_profile_name",
|
||||||
|
ScanType: "scan_type",
|
||||||
|
ImageDurationMs: "image_duration_millisecond",
|
||||||
|
AudioDurationMs: "audio_duration_millisecond",
|
||||||
|
SourceType: "source_type",
|
||||||
|
ProductCatalogID: "product_catalog_id",
|
||||||
|
ProductOuterID: "product_outer_id",
|
||||||
|
SourceReferenceID: "source_reference_id",
|
||||||
|
OwnerAccountID: "owner_account_id",
|
||||||
|
VerifyStatus: "verify_status",
|
||||||
|
SourceMaterialID: "source_material_id",
|
||||||
|
NewSourceType: "new_source_type",
|
||||||
|
AigcType: "aigc_type",
|
||||||
|
FirstPublicationStatus: "first_publication_status",
|
||||||
|
QualityStatus: "quality_status",
|
||||||
|
CoverID: "cover_id",
|
||||||
|
SimilarityStatus: "similarity_status",
|
||||||
|
UserAigcStatus: "user_aigc_status",
|
||||||
|
SystemAigcStatus: "system_aigc_status",
|
||||||
|
AigcSource: "aigc_source",
|
||||||
|
AigcFlag: "aigc_flag",
|
||||||
|
MuseAigcVersion: "muse_aigc_version",
|
||||||
|
}
|
||||||
@@ -1,251 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const CidRequestCollection = "cid_request"
|
|
||||||
|
|
||||||
// CidRequest CID请求实体(合并后的统一版本)
|
|
||||||
type CidRequest struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"` // 嵌入基础字段:Id, Creator, CreatedAt, Updater, UpdatedAt, IsDeleted
|
|
||||||
|
|
||||||
// 请求基础信息
|
|
||||||
RequestID string `bson:"requestId" json:"requestId"` // 请求唯一ID
|
|
||||||
SessionID string `bson:"sessionId" json:"sessionId"` // 会话ID
|
|
||||||
UserID string `bson:"userId" json:"userId"` // 用户ID
|
|
||||||
|
|
||||||
// 网络信息
|
|
||||||
IPAddress string `bson:"ipAddress" json:"ipAddress"` // IP地址
|
|
||||||
UserAgent string `bson:"userAgent" json:"userAgent"` // 用户代理
|
|
||||||
Referer string `bson:"referer" json:"referer"` // 来源页面
|
|
||||||
|
|
||||||
// 广告位信息(使用内联结构)
|
|
||||||
PositionCode string `bson:"positionCode" json:"positionCode"` // 广告位编码
|
|
||||||
PositionSize string `bson:"positionSize" json:"positionSize"` // 广告位尺寸
|
|
||||||
PositionFormat string `bson:"positionFormat" json:"positionFormat"` // 广告位格式
|
|
||||||
PositionType string `bson:"positionType" json:"positionType"` // 广告位类型
|
|
||||||
|
|
||||||
// 页面信息
|
|
||||||
PageURL string `bson:"pageUrl" json:"pageUrl"` // 页面URL
|
|
||||||
PageTitle string `bson:"pageTitle" json:"pageTitle"` // 页面标题
|
|
||||||
PageCategory string `bson:"pageCategory" json:"pageCategory"` // 页面分类
|
|
||||||
PageKeywords []string `bson:"pageKeywords" json:"pageKeywords"` // 页面关键词
|
|
||||||
PageTags map[string]string `bson:"pageTags" json:"pageTags"` // 页面标签
|
|
||||||
|
|
||||||
// 用户上下文信息(使用统一版本)
|
|
||||||
UserContext *UnifiedUserContext `bson:"userContext" json:"userContext"` // 用户上下文
|
|
||||||
DeviceInfo *DeviceInfo `bson:"deviceInfo" json:"deviceInfo"` // 设备信息
|
|
||||||
LocationInfo *UnifiedLocationInfo `bson:"locationInfo" json:"locationInfo"` // 位置信息
|
|
||||||
TemporalInfo *UnifiedTemporalInfo `bson:"temporalInfo" json:"temporalInfo"` // 时间信息
|
|
||||||
|
|
||||||
// 请求参数(使用合并版本)
|
|
||||||
RequestParams *RequestParams `bson:"requestParams" json:"requestParams"` // 请求参数
|
|
||||||
|
|
||||||
// 定向规则(使用统一的定向结构)
|
|
||||||
TargetingRules *UnifiedTargeting `bson:"targetingRules" json:"targetingRules"` // 定向规则
|
|
||||||
|
|
||||||
// 策略配置
|
|
||||||
StrategyConfig *StrategyConfig `bson:"strategyConfig" json:"strategyConfig"` // 策略配置
|
|
||||||
|
|
||||||
// 响应信息
|
|
||||||
Response *CidResponse `bson:"response" json:"response"` // 响应结果
|
|
||||||
ProcessingTime int64 `bson:"processingTime" json:"processingTime"` // 处理时间(毫秒)
|
|
||||||
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
|
|
||||||
|
|
||||||
// 状态信息
|
|
||||||
Status string `bson:"status" json:"status"` // 请求状态:pending、processing、completed、failed、timeout
|
|
||||||
ErrorMessage string `bson:"errorMessage" json:"errorMessage"` // 错误信息
|
|
||||||
ErrorCode string `bson:"errorCode" json:"errorCode"` // 错误代码
|
|
||||||
|
|
||||||
// 广告源信息
|
|
||||||
RequestedAdSources []string `bson:"requestedAdSources" json:"requestedAdSources"` // 请求的广告源列表
|
|
||||||
RespondedAdSources []string `bson:"respondedAdSources" json:"respondedAdSources"` // 响应的广告源列表
|
|
||||||
AdSourceResponses map[string]*AdSourceResponse `bson:"adSourceResponses" json:"adSourceResponses"` // 各广告源响应
|
|
||||||
|
|
||||||
// 统计信息
|
|
||||||
TotalAdsReturned int `bson:"totalAdsReturned" json:"totalAdsReturned"` // 返回的广告总数
|
|
||||||
ValidAdsReturned int `bson:"validAdsReturned" json:"validAdsReturned"` // 有效广告数
|
|
||||||
FilteredAds int `bson:"filteredAds" json:"filteredAds"` // 过滤的广告数
|
|
||||||
DuplicateAds int `bson:"duplicateAds" json:"duplicateAds"` // 重复广告数
|
|
||||||
|
|
||||||
// 系统信息
|
|
||||||
ServerInstance string `bson:"serverInstance" json:"serverInstance"` // 服务实例ID
|
|
||||||
Region string `bson:"region" json:"region"` // 服务区域
|
|
||||||
Version string `bson:"version" json:"version"` // 系统版本
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (c *CidRequest) GetCollectionName() string {
|
|
||||||
return CidRequestCollection
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnifiedUserContext 统一的用户上下文
|
|
||||||
type UnifiedUserContext struct {
|
|
||||||
UserID string `bson:"userId" json:"userId"` // 用户ID
|
|
||||||
SessionID string `bson:"sessionId" json:"sessionId"` // 会话ID
|
|
||||||
CookieID string `bson:"cookieId" json:"cookieId"` // Cookie ID
|
|
||||||
IP string `bson:"ip" json:"ip"` // IP地址
|
|
||||||
UserAgent string `bson:"userAgent" json:"userAgent"` // 用户代理
|
|
||||||
Language string `bson:"language" json:"language"` // 语言
|
|
||||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
|
||||||
CustomData map[string]interface{} `bson:"customData" json:"customData"` // 自定义数据
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnifiedLocationInfo 统一的位置信息
|
|
||||||
type UnifiedLocationInfo struct {
|
|
||||||
Country string `bson:"country" json:"country"` // 国家
|
|
||||||
Region string `bson:"region" json:"region"` // 地区/省份
|
|
||||||
City string `bson:"city" json:"city"` // 城市
|
|
||||||
PostalCode string `bson:"postalCode" json:"postalCode"` // 邮政编码
|
|
||||||
Latitude float64 `bson:"latitude" json:"latitude"` // 纬度
|
|
||||||
Longitude float64 `bson:"longitude" json:"longitude"` // 经度
|
|
||||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
|
||||||
Metro string `bson:"metro" json:"metro"` // 都市区
|
|
||||||
Area string `bson:"area" json:"area"` // 区域
|
|
||||||
Network string `bson:"network" json:"network"` // 网络运营商
|
|
||||||
ConnectionType string `bson:"connectionType" json:"connectionType"` // 连接类型
|
|
||||||
ISP string `bson:"isp" json:"isp"` // 互联网服务提供商
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnifiedTemporalInfo 统一的时间信息
|
|
||||||
type UnifiedTemporalInfo struct {
|
|
||||||
Timestamp int64 `bson:"timestamp" json:"timestamp"` // 时间戳(秒)
|
|
||||||
Milliseconds int64 `bson:"milliseconds" json:"milliseconds"` // 毫秒数
|
|
||||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
|
||||||
DayOfWeek int `bson:"dayOfWeek" json:"dayOfWeek"` // 星期几(0-6)
|
|
||||||
HourOfDay int `bson:"hourOfDay" json:"hourOfDay"` // 小时(0-23)
|
|
||||||
DayOfMonth int `bson:"dayOfMonth" json:"dayOfMonth"` // 月份中的天数
|
|
||||||
Month int `bson:"month" json:"month"` // 月份(1-12)
|
|
||||||
Year int `bson:"year" json:"year"` // 年份
|
|
||||||
IsWeekend bool `bson:"isWeekend" json:"isWeekend"` // 是否周末
|
|
||||||
IsBusinessHours bool `bson:"isBusinessHours" json:"isBusinessHours"` // 是否营业时间
|
|
||||||
Season string `bson:"season" json:"season"` // 季节
|
|
||||||
Holiday string `bson:"holiday" json:"holiday"` // 节假日
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeviceInfo 设备信息
|
|
||||||
type DeviceInfo struct {
|
|
||||||
Type string `bson:"type" json:"type"` // 设备类型:desktop、mobile、tablet
|
|
||||||
Brand string `bson:"brand" json:"brand"` // 设备品牌
|
|
||||||
Model string `bson:"model" json:"model"` // 设备型号
|
|
||||||
OS string `bson:"os" json:"os"` // 操作系统
|
|
||||||
OSVersion string `bson:"osVersion" json:"osVersion"` // 操作系统版本
|
|
||||||
Browser string `bson:"browser" json:"browser"` // 浏览器
|
|
||||||
BrowserVersion string `bson:"browserVersion" json:"browserVersion"` // 浏览器版本
|
|
||||||
ScreenWidth int `bson:"screenWidth" json:"screenWidth"` // 屏幕宽度
|
|
||||||
ScreenHeight int `bson:"screenHeight" json:"screenHeight"` // 屏幕高度
|
|
||||||
ViewportWidth int `bson:"viewportWidth" json:"viewportWidth"` // 视口宽度
|
|
||||||
ViewportHeight int `bson:"viewportHeight" json:"viewportHeight"` // 视口高度
|
|
||||||
DPI int `bson:"dpi" json:"dpi"` // 设备DPI
|
|
||||||
IsJavaScript bool `bson:"isJavaScript" json:"isJavaScript"` // 是否支持JavaScript
|
|
||||||
IsCookie bool `bson:"isCookie" json:"isCookie"` // 是否支持Cookie
|
|
||||||
IsFlash bool `bson:"isFlash" json:"isFlash"` // 是否支持Flash
|
|
||||||
IsHTTPS bool `bson:"isHTTPS" json:"isHTTPS"` // 是否HTTPS连接
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestParams 请求参数(合并版本)
|
|
||||||
type RequestParams struct {
|
|
||||||
AdCount int `bson:"adCount" json:"adCount"` // 请求的广告数量
|
|
||||||
AdTypes []string `bson:"adTypes" json:"adTypes"` // 广告类型
|
|
||||||
AdSizes []string `bson:"adSizes" json:"adSizes"` // 广告尺寸
|
|
||||||
ExcludedAdSources []string `bson:"excludedAdSources" json:"excludedAdSources"` // 排除的广告源
|
|
||||||
RequiredAdSources []string `bson:"requiredAdSources" json:"requiredAdSources"` // 必需的广告源
|
|
||||||
MinBidAmount int64 `bson:"minBidAmount" json:"minBidAmount"` // 最小出价(分)
|
|
||||||
MaxBidAmount int64 `bson:"maxBidAmount" json:"maxBidAmount"` // 最大出价(分)
|
|
||||||
AllowDuplicates bool `bson:"allowDuplicates" json:"allowDuplicates"` // 是否允许重复广告
|
|
||||||
FloorPrice int64 `bson:"floorPrice" json:"floorPrice"` // 底价(分)
|
|
||||||
CeilingPrice int64 `bson:"ceilingPrice" json:"ceilingPrice"` // 封顶价(分)
|
|
||||||
CustomParams map[string]interface{} `bson:"customParams" json:"customParams"` // 自定义参数
|
|
||||||
}
|
|
||||||
|
|
||||||
// StrategyConfig 策略配置(合并版本)
|
|
||||||
type StrategyConfig struct {
|
|
||||||
StrategyType string `bson:"strategyType" json:"strategyType"` // 策略类型
|
|
||||||
Priority int `bson:"priority" json:"priority"` // 优先级
|
|
||||||
Weight float64 `bson:"weight" json:"weight"` // 权重
|
|
||||||
MinAds int `bson:"minAds" json:"minAds"` // 最小广告数
|
|
||||||
MaxAds int `bson:"maxAds" json:"maxAds"` // 最大广告数
|
|
||||||
AllowDuplicates bool `bson:"allowDuplicates" json:"allowDuplicates"` // 是否允许重复
|
|
||||||
Timeout int64 `bson:"timeout" json:"timeout"` // 超时时间(毫秒)
|
|
||||||
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
|
|
||||||
CustomSettings map[string]interface{} `bson:"customSettings" json:"customSettings"` // 自定义设置
|
|
||||||
}
|
|
||||||
|
|
||||||
// CidResponse CID响应(合并版本)
|
|
||||||
type CidResponse struct {
|
|
||||||
Ads []Ad `bson:"ads" json:"ads"` // 广告列表
|
|
||||||
TrackingInfo *TrackingInfo `bson:"trackingInfo" json:"trackingInfo"` // 跟踪信息
|
|
||||||
Metadata *ResponseMetadata `bson:"metadata" json:"metadata"` // 响应元数据
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ad 广告结构(合并版本)
|
|
||||||
type Ad struct {
|
|
||||||
ID string `bson:"id" json:"id"` // 广告ID
|
|
||||||
AdSource string `bson:"adSource" json:"adSource"` // 广告源
|
|
||||||
Advertiser string `bson:"advertiser" json:"advertiser"` // 广告主
|
|
||||||
Title string `bson:"title" json:"title"` // 广告标题
|
|
||||||
Description string `bson:"description" json:"description"` // 广告描述
|
|
||||||
CreativeURL string `bson:"creativeUrl" json:"creativeUrl"` // 创意URL
|
|
||||||
LandingURL string `bson:"landingUrl" json:"landingUrl"` // 落地页URL
|
|
||||||
DisplayURL string `bson:"displayUrl" json:"displayUrl"` // 显示URL
|
|
||||||
AdType string `bson:"adType" json:"adType"` // 广告类型
|
|
||||||
Format string `bson:"format" json:"format"` // 广告格式
|
|
||||||
Width int `bson:"width" json:"width"` // 宽度
|
|
||||||
Height int `bson:"height" json:"height"` // 高度
|
|
||||||
MimeType string `bson:"mimeType" json:"mimeType"` // MIME类型
|
|
||||||
BidAmount int64 `bson:"bidAmount" json:"bidAmount"` // 出价(分)
|
|
||||||
Revenue int64 `bson:"revenue" json:"revenue"` // 预估收入(分)
|
|
||||||
CTR float64 `bson:"ctr" json:"ctr"` // 点击率
|
|
||||||
CVR float64 `bson:"cvr" json:"cvr"` // 转化率
|
|
||||||
Targeting map[string]interface{} `bson:"targeting" json:"targeting"` // 定向条件
|
|
||||||
Restrictions map[string]interface{} `bson:"restrictions" json:"restrictions"` // 限制条件
|
|
||||||
TrackingPixels []string `bson:"trackingPixels" json:"trackingPixels"` // 跟踪像素
|
|
||||||
CustomData map[string]interface{} `bson:"customData" json:"customData"` // 自定义数据
|
|
||||||
ExpiresAt int64 `bson:"expiresAt" json:"expiresAt"` // 过期时间
|
|
||||||
Priority int `bson:"priority" json:"priority"` // 优先级
|
|
||||||
Score float64 `bson:"score" json:"score"` // 评分
|
|
||||||
}
|
|
||||||
|
|
||||||
// TrackingInfo 跟踪信息(合并版本)
|
|
||||||
type TrackingInfo struct {
|
|
||||||
ImpressionURLs []string `bson:"impressionUrls" json:"impressionUrls"` // 展示跟踪URL
|
|
||||||
ClickURLs []string `bson:"clickUrls" json:"clickUrls"` // 点击跟踪URL
|
|
||||||
ConversionURLs []string `bson:"conversionUrls" json:"conversionUrls"` // 转化跟踪URL
|
|
||||||
ViewThroughURLs []string `bson:"viewThroughUrls" json:"viewThroughUrls"` // 查看跟踪URL
|
|
||||||
EventURLs map[string][]string `bson:"eventUrls" json:"eventUrls"` // 事件跟踪URL
|
|
||||||
BeaconURLs []string `bson:"beaconUrls" json:"beaconUrls"` // 信标URL
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResponseMetadata 响应元数据(合并版本)
|
|
||||||
type ResponseMetadata struct {
|
|
||||||
TotalAvailableAds int `bson:"totalAvailableAds" json:"totalAvailableAds"` // 总可用广告数
|
|
||||||
SelectedAds int `bson:"selectedAds" json:"selectedAds"` // 选择的广告数
|
|
||||||
FilteredAds int `bson:"filteredAds" json:"filteredAds"` // 过滤的广告数
|
|
||||||
DuplicateAds int `bson:"duplicateAds" json:"duplicateAds"` // 重复的广告数
|
|
||||||
AverageBidAmount int64 `bson:"averageBidAmount" json:"averageBidAmount"` // 平均出价
|
|
||||||
HighestBidAmount int64 `bson:"highestBidAmount" json:"highestBidAmount"` // 最高出价
|
|
||||||
LowestBidAmount int64 `bson:"lowestBidAmount" json:"lowestBidAmount"` // 最低出价
|
|
||||||
AverageCTR float64 `bson:"averageCTR" json:"averageCTR"` // 平均点击率
|
|
||||||
AverageCVR float64 `bson:"averageCVR" json:"averageCVR"` // 平均转化率
|
|
||||||
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
|
|
||||||
CacheHit bool `bson:"cacheHit" json:"cacheHit"` // 是否命中缓存
|
|
||||||
StrategyUsed string `bson:"strategyUsed" json:"strategyUsed"` // 使用的策略
|
|
||||||
AdSourcesUsed []string `bson:"adSourcesUsed" json:"adSourcesUsed"` // 使用的广告源
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdSourceResponse 广告源响应(合并版本)
|
|
||||||
type AdSourceResponse struct {
|
|
||||||
AdSource string `bson:"adSource" json:"adSource"` // 广告源名称
|
|
||||||
Status string `bson:"status" json:"status"` // 响应状态:success、timeout、error
|
|
||||||
ResponseTime int64 `bson:"responseTime" json:"responseTime"` // 响应时间(毫秒)
|
|
||||||
AdsReturned int `bson:"adsReturned" json:"adsReturned"` // 返回的广告数
|
|
||||||
AdsAccepted int `bson:"adsAccepted" json:"adsAccepted"` // 接受的广告数
|
|
||||||
AdsFiltered int `bson:"adsFiltered" json:"adsFiltered"` // 过滤的广告数
|
|
||||||
ErrorMessage string `bson:"errorMessage" json:"errorMessage"` // 错误信息
|
|
||||||
ErrorCode string `bson:"errorCode" json:"errorCode"` // 错误代码
|
|
||||||
RetryCount int `bson:"retryCount" json:"retryCount"` // 重试次数
|
|
||||||
CacheHit bool `bson:"cacheHit" json:"cacheHit"` // 是否命中缓存
|
|
||||||
TotalRevenue int64 `bson:"totalRevenue" json:"totalRevenue"` // 总收入(分)
|
|
||||||
AverageBidAmount int64 `bson:"averageBidAmount" json:"averageBidAmount"` // 平均出价(分)
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package delivery
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ad 广告实体(计划树第三层)
|
||||||
|
type Ad struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
AdGroupID int64 `orm:"ad_group_id" json:"adGroupId" description:"所属单元ID"`
|
||||||
|
Name string `orm:"name" json:"name" description:"广告名称"`
|
||||||
|
PlatformAdID string `orm:"platform_ad_id" json:"platformAdId" description:"平台侧广告ID"`
|
||||||
|
Status string `orm:"status" json:"status" description:"本地状态 draft/active/paused/ended/rejected"`
|
||||||
|
PlatformStatus string `orm:"platform_status" json:"platformStatus" description:"平台侧状态快照"`
|
||||||
|
SyncStatus string `orm:"sync_status" json:"syncStatus" description:"同步状态 none/pending/synced/failed"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"平台特有扩展(JSON)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdCol 广告表字段定义
|
||||||
|
type AdCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
AdGroupID string
|
||||||
|
Name string
|
||||||
|
PlatformAdID string
|
||||||
|
Status string
|
||||||
|
PlatformStatus string
|
||||||
|
SyncStatus string
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdCols 广告表字段常量
|
||||||
|
var AdCols = AdCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
AdGroupID: "ad_group_id",
|
||||||
|
Name: "name",
|
||||||
|
PlatformAdID: "platform_ad_id",
|
||||||
|
Status: "status",
|
||||||
|
PlatformStatus: "platform_status",
|
||||||
|
SyncStatus: "sync_status",
|
||||||
|
Extra: "extra",
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package delivery
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AdGroup 广告单元实体(计划树第二层,定向+出价)
|
||||||
|
type AdGroup struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
CampaignID int64 `orm:"campaign_id" json:"campaignId" description:"所属计划ID"`
|
||||||
|
Name string `orm:"name" json:"name" description:"单元名称"`
|
||||||
|
PlatformAdGroupID string `orm:"platform_ad_group_id" json:"platformAdGroupId" description:"平台侧单元ID"`
|
||||||
|
Targeting string `orm:"targeting" json:"targeting" description:"定向(JSON) 地域/人群/时段"`
|
||||||
|
BidType string `orm:"bid_type" json:"bidType" description:"出价方式 cpm/ocpm/cpc/ocpc"`
|
||||||
|
BidAmount int64 `orm:"bid_amount" json:"bidAmount" description:"出价(分,cpm按千次展示)"`
|
||||||
|
Status string `orm:"status" json:"status" description:"本地状态 draft/active/paused/ended/rejected"`
|
||||||
|
PlatformStatus string `orm:"platform_status" json:"platformStatus" description:"平台侧状态快照"`
|
||||||
|
SyncStatus string `orm:"sync_status" json:"syncStatus" description:"同步状态 none/pending/synced/failed"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"平台特有扩展(JSON)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdGroupCol 广告单元表字段定义
|
||||||
|
type AdGroupCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
CampaignID string
|
||||||
|
Name string
|
||||||
|
PlatformAdGroupID string
|
||||||
|
Targeting string
|
||||||
|
BidType string
|
||||||
|
BidAmount string
|
||||||
|
Status string
|
||||||
|
PlatformStatus string
|
||||||
|
SyncStatus string
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdGroupCols 广告单元表字段常量
|
||||||
|
var AdGroupCols = AdGroupCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
CampaignID: "campaign_id",
|
||||||
|
Name: "name",
|
||||||
|
PlatformAdGroupID: "platform_ad_group_id",
|
||||||
|
Targeting: "targeting",
|
||||||
|
BidType: "bid_type",
|
||||||
|
BidAmount: "bid_amount",
|
||||||
|
Status: "status",
|
||||||
|
PlatformStatus: "platform_status",
|
||||||
|
SyncStatus: "sync_status",
|
||||||
|
Extra: "extra",
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package delivery
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Campaign 广告计划实体(计划树第一层,外投/自有DSP共用,预算在计划层)
|
||||||
|
type Campaign struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
AdAccountID int64 `orm:"ad_account_id" json:"adAccountId" description:"本地广告账户ID"`
|
||||||
|
Name string `orm:"name" json:"name" description:"计划名称"`
|
||||||
|
Channel string `orm:"channel" json:"channel" description:"投放通道 external外投/self_dsp自有"`
|
||||||
|
Platform string `orm:"platform" json:"platform" description:"广告平台 douyin/xiaohongshu/kuaishou"`
|
||||||
|
PlatformCampaignID string `orm:"platform_campaign_id" json:"platformCampaignId" description:"平台侧计划ID"`
|
||||||
|
Status string `orm:"status" json:"status" description:"本地状态 draft/active/paused/ended/rejected"`
|
||||||
|
PlatformStatus string `orm:"platform_status" json:"platformStatus" description:"平台侧状态快照"`
|
||||||
|
SyncStatus string `orm:"sync_status" json:"syncStatus" description:"同步状态 none/pending/synced/failed"`
|
||||||
|
BudgetMode string `orm:"budget_mode" json:"budgetMode" description:"预算方式 free不限/daily日预算"`
|
||||||
|
DailyBudget *int64 `orm:"daily_budget" json:"dailyBudget" description:"日预算(分),budget_mode=daily时必填,否则NULL"`
|
||||||
|
TotalBudget *int64 `orm:"total_budget" json:"totalBudget" description:"总预算(分),NULL=不限"`
|
||||||
|
OptimizeGoal string `orm:"optimize_goal" json:"optimizeGoal" description:"优化目标 conversion/click/exposure"`
|
||||||
|
StartTime *gtime.Time `orm:"start_time" json:"startTime" description:"投放开始时间"`
|
||||||
|
EndTime *gtime.Time `orm:"end_time" json:"endTime" description:"投放结束时间"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"平台特有扩展(JSON)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CampaignCol 广告计划表字段定义
|
||||||
|
type CampaignCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
AdAccountID string
|
||||||
|
Name string
|
||||||
|
Channel string
|
||||||
|
Platform string
|
||||||
|
PlatformCampaignID string
|
||||||
|
Status string
|
||||||
|
PlatformStatus string
|
||||||
|
SyncStatus string
|
||||||
|
BudgetMode string
|
||||||
|
DailyBudget string
|
||||||
|
TotalBudget string
|
||||||
|
OptimizeGoal string
|
||||||
|
StartTime string
|
||||||
|
EndTime string
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CampaignCols 广告计划表字段常量
|
||||||
|
var CampaignCols = CampaignCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
AdAccountID: "ad_account_id",
|
||||||
|
Name: "name",
|
||||||
|
Channel: "channel",
|
||||||
|
Platform: "platform",
|
||||||
|
PlatformCampaignID: "platform_campaign_id",
|
||||||
|
Status: "status",
|
||||||
|
PlatformStatus: "platform_status",
|
||||||
|
SyncStatus: "sync_status",
|
||||||
|
BudgetMode: "budget_mode",
|
||||||
|
DailyBudget: "daily_budget",
|
||||||
|
TotalBudget: "total_budget",
|
||||||
|
OptimizeGoal: "optimize_goal",
|
||||||
|
StartTime: "start_time",
|
||||||
|
EndTime: "end_time",
|
||||||
|
Extra: "extra",
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package delivery
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Creative 创意实体(计划树第四层,引用素材库,落地页带click_id模板)
|
||||||
|
type Creative struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
AdID int64 `orm:"ad_id" json:"adId" description:"所属广告ID(部分平台创意先于广告,可空)"`
|
||||||
|
CampaignID int64 `orm:"campaign_id" json:"campaignId" description:"所属计划ID(冗余,ad_id为空时链路不断)"`
|
||||||
|
Name string `orm:"name" json:"name" description:"创意名称"`
|
||||||
|
MaterialID int64 `orm:"material_id" json:"materialId" description:"素材ID(material.id)"`
|
||||||
|
Title string `orm:"title" json:"title" description:"标题"`
|
||||||
|
Description string `orm:"description" json:"description" description:"描述"`
|
||||||
|
ClickURL string `orm:"click_url" json:"clickUrl" description:"落地页URL(含click_id模板)"`
|
||||||
|
PlatformCreativeID string `orm:"platform_creative_id" json:"platformCreativeId" description:"平台侧创意ID"`
|
||||||
|
PlatformMaterialID string `orm:"platform_material_id" json:"platformMaterialId" description:"平台侧素材ID"`
|
||||||
|
AuditStatus string `orm:"audit_status" json:"auditStatus" description:"审核状态 pending/pass/reject"`
|
||||||
|
Status string `orm:"status" json:"status" description:"本地状态 draft/active/paused/ended/rejected"`
|
||||||
|
PlatformStatus string `orm:"platform_status" json:"platformStatus" description:"平台侧状态快照"`
|
||||||
|
SyncStatus string `orm:"sync_status" json:"syncStatus" description:"同步状态 none/pending/synced/failed"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"平台特有扩展(JSON)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreativeCol 创意表字段定义
|
||||||
|
type CreativeCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
AdID string
|
||||||
|
CampaignID string
|
||||||
|
Name string
|
||||||
|
MaterialID string
|
||||||
|
Title string
|
||||||
|
Description string
|
||||||
|
ClickURL string
|
||||||
|
PlatformCreativeID string
|
||||||
|
PlatformMaterialID string
|
||||||
|
AuditStatus string
|
||||||
|
Status string
|
||||||
|
PlatformStatus string
|
||||||
|
SyncStatus string
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreativeCols 创意表字段常量
|
||||||
|
var CreativeCols = CreativeCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
AdID: "ad_id",
|
||||||
|
CampaignID: "campaign_id",
|
||||||
|
Name: "name",
|
||||||
|
MaterialID: "material_id",
|
||||||
|
Title: "title",
|
||||||
|
Description: "description",
|
||||||
|
ClickURL: "click_url",
|
||||||
|
PlatformCreativeID: "platform_creative_id",
|
||||||
|
PlatformMaterialID: "platform_material_id",
|
||||||
|
AuditStatus: "audit_status",
|
||||||
|
Status: "status",
|
||||||
|
PlatformStatus: "platform_status",
|
||||||
|
SyncStatus: "sync_status",
|
||||||
|
Extra: "extra",
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package dsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AdSlot 广告位实体(自有媒体广告位,售卖给计划)
|
||||||
|
type AdSlot struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
MediaID int64 `orm:"media_id" json:"mediaId" description:"媒体ID"`
|
||||||
|
Name string `orm:"name" json:"name" description:"广告位名称"`
|
||||||
|
SlotType string `orm:"slot_type" json:"slotType" description:"广告位类型 banner/feed/video/interstitial/reward"`
|
||||||
|
Size string `orm:"size" json:"size" description:"尺寸"`
|
||||||
|
Unit string `orm:"unit" json:"unit" description:"计费方式 cpm/cpc/cpa"`
|
||||||
|
BasePrice int64 `orm:"base_price" json:"basePrice" description:"底价(分,cpm按千次)"`
|
||||||
|
Status int `orm:"status" json:"status" description:"状态 1可售 0停售"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"扩展(JSON) 定向能力声明等"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdSlotCol 广告位表字段定义
|
||||||
|
type AdSlotCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
MediaID string
|
||||||
|
Name string
|
||||||
|
SlotType string
|
||||||
|
Size string
|
||||||
|
Unit string
|
||||||
|
BasePrice string
|
||||||
|
Status string
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdSlotCols 广告位表字段常量
|
||||||
|
var AdSlotCols = AdSlotCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
MediaID: "media_id",
|
||||||
|
Name: "name",
|
||||||
|
SlotType: "slot_type",
|
||||||
|
Size: "size",
|
||||||
|
Unit: "unit",
|
||||||
|
BasePrice: "base_price",
|
||||||
|
Status: "status",
|
||||||
|
Extra: "extra",
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package dsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuctionLog 展示计费日志实体(PD与RTB统一入口,按day分区)
|
||||||
|
type AuctionLog struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
RequestID string `orm:"request_id" json:"requestId" description:"请求ID(RTB)/流水号(PD)"`
|
||||||
|
CampaignID int64 `orm:"campaign_id" json:"campaignId" description:"本地计划ID"`
|
||||||
|
AdID int64 `orm:"ad_id" json:"adId" description:"广告ID"`
|
||||||
|
SlotID int64 `orm:"slot_id" json:"slotId" description:"广告位ID"`
|
||||||
|
Event string `orm:"event" json:"event" description:"事件 show/click"`
|
||||||
|
Price int64 `orm:"price" json:"price" description:"成交价(分,cpm按千次)"`
|
||||||
|
Cost int64 `orm:"cost" json:"cost" description:"本次事件应计费用(分,写入时算好)"`
|
||||||
|
DeviceID string `orm:"device_id" json:"deviceId" description:"设备ID"`
|
||||||
|
IP string `orm:"ip" json:"ip" description:"请求IP"`
|
||||||
|
Day *gtime.Time `orm:"day" json:"day" description:"分区日期"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuctionLogCol 展示计费日志表字段定义
|
||||||
|
type AuctionLogCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
RequestID string
|
||||||
|
CampaignID string
|
||||||
|
AdID string
|
||||||
|
SlotID string
|
||||||
|
Event string
|
||||||
|
Price string
|
||||||
|
Cost string
|
||||||
|
DeviceID string
|
||||||
|
IP string
|
||||||
|
Day string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuctionLogCols 展示计费日志表字段常量
|
||||||
|
var AuctionLogCols = AuctionLogCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
RequestID: "request_id",
|
||||||
|
CampaignID: "campaign_id",
|
||||||
|
AdID: "ad_id",
|
||||||
|
SlotID: "slot_id",
|
||||||
|
Event: "event",
|
||||||
|
Price: "price",
|
||||||
|
Cost: "cost",
|
||||||
|
DeviceID: "device_id",
|
||||||
|
IP: "ip",
|
||||||
|
Day: "day",
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package dsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BidRequestLog RTB请求日志实体(高并发,按day分区,可裁剪)
|
||||||
|
type BidRequestLog struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
RequestID string `orm:"request_id" json:"requestId" description:"请求ID(去重键)"`
|
||||||
|
SlotID int64 `orm:"slot_id" json:"slotId" description:"广告位ID"`
|
||||||
|
DeviceID string `orm:"device_id" json:"deviceId" description:"设备ID"`
|
||||||
|
IP string `orm:"ip" json:"ip" description:"请求IP"`
|
||||||
|
UA string `orm:"ua" json:"ua" description:"用户代理"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"上下文/定向特征(JSON)"`
|
||||||
|
Day *gtime.Time `orm:"day" json:"day" description:"分区日期"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BidRequestLogCol RTB请求日志表字段定义
|
||||||
|
type BidRequestLogCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
RequestID string
|
||||||
|
SlotID string
|
||||||
|
DeviceID string
|
||||||
|
IP string
|
||||||
|
UA string
|
||||||
|
Extra string
|
||||||
|
Day string
|
||||||
|
}
|
||||||
|
|
||||||
|
// BidRequestLogCols RTB请求日志表字段常量
|
||||||
|
var BidRequestLogCols = BidRequestLogCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
RequestID: "request_id",
|
||||||
|
SlotID: "slot_id",
|
||||||
|
DeviceID: "device_id",
|
||||||
|
IP: "ip",
|
||||||
|
UA: "ua",
|
||||||
|
Extra: "extra",
|
||||||
|
Day: "day",
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package dsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Media 媒体实体(自有媒体,公司流量侧)
|
||||||
|
type Media struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
Name string `orm:"name" json:"name" description:"媒体名称"`
|
||||||
|
Type string `orm:"type" json:"type" description:"媒体类型 app/web"`
|
||||||
|
Domain string `orm:"domain" json:"domain" description:"域名"`
|
||||||
|
Status int `orm:"status" json:"status" description:"状态 1启用 0停用"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MediaCol 媒体表字段定义
|
||||||
|
type MediaCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Domain string
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MediaCols 媒体表字段常量
|
||||||
|
var MediaCols = MediaCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
Name: "name",
|
||||||
|
Type: "type",
|
||||||
|
Domain: "domain",
|
||||||
|
Status: "status",
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package dsp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Placement 预订单实体(PD直投/程序化直购:计划×广告位预订)
|
||||||
|
type Placement struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
AdSlotID int64 `orm:"ad_slot_id" json:"adSlotId" description:"广告位ID"`
|
||||||
|
CampaignID int64 `orm:"campaign_id" json:"campaignId" description:"本地计划ID"`
|
||||||
|
Quota int `orm:"quota" json:"quota" description:"预订量(展示次数)"`
|
||||||
|
Price int64 `orm:"price" json:"price" description:"协议价(分,按unit口径)"`
|
||||||
|
BookStart *gtime.Time `orm:"book_start" json:"bookStart" description:"预订开始时间"`
|
||||||
|
BookEnd *gtime.Time `orm:"book_end" json:"bookEnd" description:"预订结束时间"`
|
||||||
|
Status string `orm:"status" json:"status" description:"状态 pending/running/finished/ended"`
|
||||||
|
DeliveredCount int `orm:"delivered_count" json:"deliveredCount" description:"已投展示数"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlacementCol 预订单表字段定义
|
||||||
|
type PlacementCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
AdSlotID string
|
||||||
|
CampaignID string
|
||||||
|
Quota string
|
||||||
|
Price string
|
||||||
|
BookStart string
|
||||||
|
BookEnd string
|
||||||
|
Status string
|
||||||
|
DeliveredCount string
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlacementCols 预订单表字段常量
|
||||||
|
var PlacementCols = PlacementCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
AdSlotID: "ad_slot_id",
|
||||||
|
CampaignID: "campaign_id",
|
||||||
|
Quota: "quota",
|
||||||
|
Price: "price",
|
||||||
|
BookStart: "book_start",
|
||||||
|
BookEnd: "book_end",
|
||||||
|
Status: "status",
|
||||||
|
DeliveredCount: "delivered_count",
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package material
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Material 素材实体(素材文件库,md5去重)
|
||||||
|
type Material struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
Type string `orm:"type" json:"type" description:"素材类型 image/video/text"`
|
||||||
|
Title string `orm:"title" json:"title" description:"素材标题"`
|
||||||
|
FilePath string `orm:"file_path" json:"filePath" description:"本地存储路径"`
|
||||||
|
FileSize int64 `orm:"file_size" json:"fileSize" description:"文件大小(字节)"`
|
||||||
|
MD5 string `orm:"md5" json:"md5" description:"文件MD5(去重键)"`
|
||||||
|
Width int `orm:"width" json:"width" description:"宽度(像素)"`
|
||||||
|
Height int `orm:"height" json:"height" description:"高度(像素)"`
|
||||||
|
Duration int `orm:"duration" json:"duration" description:"视频时长(秒)"`
|
||||||
|
Format string `orm:"format" json:"format" description:"文件格式"`
|
||||||
|
AuditStatus string `orm:"audit_status" json:"auditStatus" description:"审核状态 pending/auditing/pass/reject/disabled"`
|
||||||
|
Status int `orm:"status" json:"status" description:"状态 1可用 0禁用"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"扩展(JSON) 如平台素材ID映射"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaterialCol 素材表字段定义
|
||||||
|
type MaterialCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
Type string
|
||||||
|
Title string
|
||||||
|
FilePath string
|
||||||
|
FileSize string
|
||||||
|
MD5 string
|
||||||
|
Width string
|
||||||
|
Height string
|
||||||
|
Duration string
|
||||||
|
Format string
|
||||||
|
AuditStatus string
|
||||||
|
Status string
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaterialCols 素材表字段常量
|
||||||
|
var MaterialCols = MaterialCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
Type: "type",
|
||||||
|
Title: "title",
|
||||||
|
FilePath: "file_path",
|
||||||
|
FileSize: "file_size",
|
||||||
|
MD5: "md5",
|
||||||
|
Width: "width",
|
||||||
|
Height: "height",
|
||||||
|
Duration: "duration",
|
||||||
|
Format: "format",
|
||||||
|
AuditStatus: "audit_status",
|
||||||
|
Status: "status",
|
||||||
|
Extra: "extra",
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package material
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaterialAudit 素材审核记录实体(审核状态机全量日志,多通道)
|
||||||
|
type MaterialAudit struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
MaterialID int64 `orm:"material_id" json:"materialId" description:"素材ID"`
|
||||||
|
AuditChannel string `orm:"audit_channel" json:"auditChannel" description:"审核通道 yidun/platform/manual"`
|
||||||
|
AuditAction string `orm:"audit_action" json:"auditAction" description:"审核动作 submit/pass/reject/revoke"`
|
||||||
|
AuditStatus string `orm:"audit_status" json:"auditStatus" description:"审核状态"`
|
||||||
|
Result string `orm:"result" json:"result" description:"平台返回详情(JSON) 原因/违规项"`
|
||||||
|
Operator string `orm:"operator" json:"operator" description:"操作人"`
|
||||||
|
AuditTime *gtime.Time `orm:"audit_time" json:"auditTime" description:"审核时间"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaterialAuditCol 素材审核记录表字段定义
|
||||||
|
type MaterialAuditCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
MaterialID string
|
||||||
|
AuditChannel string
|
||||||
|
AuditAction string
|
||||||
|
AuditStatus string
|
||||||
|
Result string
|
||||||
|
Operator string
|
||||||
|
AuditTime string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaterialAuditCols 素材审核记录表字段常量
|
||||||
|
var MaterialAuditCols = MaterialAuditCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
MaterialID: "material_id",
|
||||||
|
AuditChannel: "audit_channel",
|
||||||
|
AuditAction: "audit_action",
|
||||||
|
AuditStatus: "audit_status",
|
||||||
|
Result: "result",
|
||||||
|
Operator: "operator",
|
||||||
|
AuditTime: "audit_time",
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AdAccount 广告账户实体(平台凭据 + 多级层级 + API能力标识)
|
||||||
|
type AdAccount struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
Name string `orm:"name" json:"name" description:"账户显示名"`
|
||||||
|
Platform string `orm:"platform" json:"platform" description:"广告平台 douyin/xiaohongshu/kuaishou"`
|
||||||
|
AccountID string `orm:"account_id" json:"accountId" description:"平台侧账户ID"`
|
||||||
|
ParentAccountID int64 `orm:"parent_account_id" json:"parentAccountId" description:"上级账户ID(多级代理层级,自引用)"`
|
||||||
|
AccountRole string `orm:"account_role" json:"accountRole" description:"账户角色 agent/owner/sub"`
|
||||||
|
Capabilities string `orm:"capabilities" json:"capabilities" description:"API能力(JSON) attribution/delivery/report"`
|
||||||
|
AppID string `orm:"app_id" json:"appId" description:"应用ID"`
|
||||||
|
AppSecret string `orm:"app_secret" json:"appSecret" description:"应用密钥"`
|
||||||
|
AccessToken string `orm:"access_token" json:"accessToken" description:"访问令牌"`
|
||||||
|
TokenExpireAt int64 `orm:"token_expire_at" json:"tokenExpireAt" description:"令牌过期时间戳"`
|
||||||
|
Config string `orm:"config" json:"config" description:"平台特定配置(JSON) 含回传事件映射等"`
|
||||||
|
Enabled bool `orm:"enabled" json:"enabled" description:"是否启用"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdAccountCol 广告账户表字段定义
|
||||||
|
type AdAccountCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
Name string
|
||||||
|
Platform string
|
||||||
|
AccountID string
|
||||||
|
ParentAccountID string
|
||||||
|
AccountRole string
|
||||||
|
Capabilities string
|
||||||
|
AppID string
|
||||||
|
AppSecret string
|
||||||
|
AccessToken string
|
||||||
|
TokenExpireAt string
|
||||||
|
Config string
|
||||||
|
Enabled string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdAccountCols 广告账户表字段常量
|
||||||
|
var AdAccountCols = AdAccountCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
Name: "name",
|
||||||
|
Platform: "platform",
|
||||||
|
AccountID: "account_id",
|
||||||
|
ParentAccountID: "parent_account_id",
|
||||||
|
AccountRole: "account_role",
|
||||||
|
Capabilities: "capabilities",
|
||||||
|
AppID: "app_id",
|
||||||
|
AppSecret: "app_secret",
|
||||||
|
AccessToken: "access_token",
|
||||||
|
TokenExpireAt: "token_expire_at",
|
||||||
|
Config: "config",
|
||||||
|
Enabled: "enabled",
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommercePlatformConfig 电商平台配置实体(下游商品平台对接配置)
|
||||||
|
type CommercePlatformConfig struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
Name string `orm:"name" json:"name" description:"配置显示名"`
|
||||||
|
Platform string `orm:"platform" json:"platform" description:"电商平台 jd/taobao"`
|
||||||
|
AppKey string `orm:"app_key" json:"appKey" description:"应用Key"`
|
||||||
|
AppSecret string `orm:"app_secret" json:"appSecret" description:"应用密钥"`
|
||||||
|
CallbackURL string `orm:"callback_url" json:"callbackUrl" description:"订单回调接收URL"`
|
||||||
|
Config string `orm:"config" json:"config" description:"平台特定配置(JSON)"`
|
||||||
|
Enabled bool `orm:"enabled" json:"enabled" description:"是否启用"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommercePlatformConfigCol 电商平台配置表字段定义
|
||||||
|
type CommercePlatformConfigCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
Name string
|
||||||
|
Platform string
|
||||||
|
AppKey string
|
||||||
|
AppSecret string
|
||||||
|
CallbackURL string
|
||||||
|
Config string
|
||||||
|
Enabled string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommercePlatformConfigCols 电商平台配置表字段常量
|
||||||
|
var CommercePlatformConfigCols = CommercePlatformConfigCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
Name: "name",
|
||||||
|
Platform: "platform",
|
||||||
|
AppKey: "app_key",
|
||||||
|
AppSecret: "app_secret",
|
||||||
|
CallbackURL: "callback_url",
|
||||||
|
Config: "config",
|
||||||
|
Enabled: "enabled",
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package platform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ItemMapping 广告商品与电商商品映射实体
|
||||||
|
type ItemMapping struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
AdPlatform string `orm:"ad_platform" json:"adPlatform" description:"广告平台"`
|
||||||
|
AdItemID string `orm:"ad_item_id" json:"adItemId" description:"广告平台侧商品ID"`
|
||||||
|
CommercePlatform string `orm:"commerce_platform" json:"commercePlatform" description:"电商平台"`
|
||||||
|
CommerceItemID string `orm:"commerce_item_id" json:"commerceItemId" description:"电商平台侧商品ID"`
|
||||||
|
SkuID string `orm:"sku_id" json:"skuId" description:"SKU ID"`
|
||||||
|
Config string `orm:"config" json:"config" description:"映射扩展配置(JSON)"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ItemMappingCol 商品映射表字段定义
|
||||||
|
type ItemMappingCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
AdPlatform string
|
||||||
|
AdItemID string
|
||||||
|
CommercePlatform string
|
||||||
|
CommerceItemID string
|
||||||
|
SkuID string
|
||||||
|
Config string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ItemMappingCols 商品映射表字段常量
|
||||||
|
var ItemMappingCols = ItemMappingCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
AdPlatform: "ad_platform",
|
||||||
|
AdItemID: "ad_item_id",
|
||||||
|
CommercePlatform: "commerce_platform",
|
||||||
|
CommerceItemID: "commerce_item_id",
|
||||||
|
SkuID: "sku_id",
|
||||||
|
Config: "config",
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/model/config"
|
|
||||||
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const PlatformDeliveryRuleCollection = "platform_delivery_rule"
|
|
||||||
|
|
||||||
// PlatformDeliveryRule 平台投放规则实体
|
|
||||||
type PlatformDeliveryRule struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 关联信息
|
|
||||||
AppID string `bson:"appId" json:"appId"` // 应用ID
|
|
||||||
PlatformID string `bson:"platformId" json:"platformId"` // 平台ID
|
|
||||||
|
|
||||||
// 规则基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 规则名称
|
|
||||||
Description string `bson:"description" json:"description"` // 规则描述
|
|
||||||
RuleType string `bson:"ruleType" json:"ruleType"` // 规则类型:budget、targeting、bidding、frequency等
|
|
||||||
|
|
||||||
// 预算配置
|
|
||||||
config.BudgetConfig `bson:",inline" json:",inline"` // 内联预算配置
|
|
||||||
|
|
||||||
// 出价配置
|
|
||||||
config.BiddingConfig `bson:",inline" json:",inline"` // 内联竞价配置
|
|
||||||
|
|
||||||
// 定向配置
|
|
||||||
TargetingConfig string `bson:"targetingConfig" json:"targetingConfig"` // 定向配置(JSON格式)
|
|
||||||
IncludeAudience []string `bson:"includeAudience" json:"includeAudience"` // 包含受众
|
|
||||||
ExcludeAudience []string `bson:"excludeAudience" json:"excludeAudience"` // 排除受众
|
|
||||||
|
|
||||||
// 频次控制配置
|
|
||||||
config.FrequencyCapConfig `bson:",inline" json:",inline"` // 内联频次控制配置
|
|
||||||
|
|
||||||
// 创意配置
|
|
||||||
CreativeRotation string `bson:"creativeRotation" json:"creativeRotation"` // 创意轮播方式:optimize、even、random
|
|
||||||
SelectedCreatives []string `bson:"selectedCreatives" json:"selectedCreatives"` // 选中的创意列表
|
|
||||||
ExcludedCreatives []string `bson:"excludedCreatives" json:"excludedCreatives"` // 排除的创意列表
|
|
||||||
|
|
||||||
// 平台特定配置
|
|
||||||
PlatformSpecific string `bson:"platformSpecific" json:"platformSpecific"` // 平台特定配置(JSON格式)
|
|
||||||
|
|
||||||
// 监控和告警
|
|
||||||
PerformanceThresholds string `bson:"performanceThresholds" json:"performanceThresholds"` // 性能阈值(JSON格式)
|
|
||||||
|
|
||||||
// 自动优化配置
|
|
||||||
IsAutoOptimize bool `bson:"isAutoOptimize" json:"isAutoOptimize"` // 是否自动优化
|
|
||||||
LastOptimizeTime int64 `bson:"lastOptimizeTime" json:"lastOptimizeTime"` // 最后优化时间
|
|
||||||
AutoOptimizeConfig string `bson:"autoOptimizeConfig" json:"autoOptimizeConfig"` // 自动优化配置(JSON格式)
|
|
||||||
|
|
||||||
// 执行统计
|
|
||||||
ExecutionCount int64 `bson:"executionCount" json:"executionCount"` // 执行次数
|
|
||||||
SuccessCount int64 `bson:"successCount" json:"successCount"` // 成功次数
|
|
||||||
FailureCount int64 `bson:"failureCount" json:"failureCount"` // 失败次数
|
|
||||||
LastExecutionTime int64 `bson:"lastExecutionTime" json:"lastExecutionTime"` // 最后执行时间
|
|
||||||
NextExecutionTime int64 `bson:"nextExecutionTime" json:"nextExecutionTime"` // 下次执行时间
|
|
||||||
|
|
||||||
// 执行信息
|
|
||||||
CreatedBy string `bson:"createdBy" json:"createdBy"` // 创建人
|
|
||||||
LastModifiedBy string `bson:"lastModifiedBy" json:"lastModifiedBy"` // 最后修改人
|
|
||||||
ModifiedReason string `bson:"modifiedReason" json:"modifiedReason"` // 修改原因
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (p *PlatformDeliveryRule) GetCollectionName() string {
|
|
||||||
return PlatformDeliveryRuleCollection
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package report
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gogf/gf/v2/os/gtime"
|
||||||
|
|
||||||
|
"gitea.redpowerfuture.com/red-future/common/beans"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DailyReport 日报表实体(统一消耗/效果汇总:外投拉平台报表,DSP聚合auction_log)
|
||||||
|
type DailyReport struct {
|
||||||
|
beans.SQLBaseDO `orm:",inherit"`
|
||||||
|
// 业务字段
|
||||||
|
ReportDate *gtime.Time `orm:"report_date" json:"reportDate" description:"报表日期"`
|
||||||
|
Channel string `orm:"channel" json:"channel" description:"投放通道 external外投/self_dsp自有"`
|
||||||
|
AdAccountID int64 `orm:"ad_account_id" json:"adAccountId" description:"广告账户ID"`
|
||||||
|
CampaignID int64 `orm:"campaign_id" json:"campaignId" description:"本地计划ID"`
|
||||||
|
Platform string `orm:"platform" json:"platform" description:"广告平台 douyin/xiaohongshu/kuaishou"`
|
||||||
|
Impressions int64 `orm:"impressions" json:"impressions" description:"展示数"`
|
||||||
|
Clicks int64 `orm:"clicks" json:"clicks" description:"点击数"`
|
||||||
|
Cost int64 `orm:"cost" json:"cost" description:"消耗(分)"`
|
||||||
|
Conversions int64 `orm:"conversions" json:"conversions" description:"转化数"`
|
||||||
|
Extra string `orm:"extra" json:"extra" description:"平台报表原始快照(JSON),对账用"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyReportCol 日报表字段定义
|
||||||
|
type DailyReportCol struct {
|
||||||
|
beans.SQLBaseCol
|
||||||
|
ReportDate string
|
||||||
|
Channel string
|
||||||
|
AdAccountID string
|
||||||
|
CampaignID string
|
||||||
|
Platform string
|
||||||
|
Impressions string
|
||||||
|
Clicks string
|
||||||
|
Cost string
|
||||||
|
Conversions string
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyReportCols 日报表字段常量
|
||||||
|
var DailyReportCols = DailyReportCol{
|
||||||
|
SQLBaseCol: beans.DefSQLBaseCol,
|
||||||
|
ReportDate: "report_date",
|
||||||
|
Channel: "channel",
|
||||||
|
AdAccountID: "ad_account_id",
|
||||||
|
CampaignID: "campaign_id",
|
||||||
|
Platform: "platform",
|
||||||
|
Impressions: "impressions",
|
||||||
|
Clicks: "clicks",
|
||||||
|
Cost: "cost",
|
||||||
|
Conversions: "conversions",
|
||||||
|
Extra: "extra",
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitea.com/red-future/common/beans"
|
|
||||||
)
|
|
||||||
|
|
||||||
const StrategyCollection = "strategy"
|
|
||||||
|
|
||||||
// Strategy 匹配策略表
|
|
||||||
type Strategy struct {
|
|
||||||
beans.MongoBaseDO `bson:",inline" json:",inline"`
|
|
||||||
Status string `bson:"status" json:"status"` // 状态:active、inactive、maintenance等
|
|
||||||
|
|
||||||
// 策略基本信息
|
|
||||||
Name string `bson:"name" json:"name"` // 策略名称
|
|
||||||
Description string `bson:"description" json:"description"` // 描述
|
|
||||||
MinConversion float64 `bson:"minConversion" json:"minConversion"` // 最低转化率
|
|
||||||
MaxConversion float64 `bson:"maxConversion" json:"maxConversion"` // 最高转化率
|
|
||||||
SourceWeights string `bson:"sourceWeights" json:"sourceWeights"` // 广告源权重 (JSON格式)
|
|
||||||
MaxAdsPerReq int `bson:"maxAdsPerReq" json:"maxAdsPerReq"` // 每次请求最大广告数
|
|
||||||
MaxReqPerHour int `bson:"maxReqPerHour" json:"maxReqPerHour"` // 每小时最大请求次数
|
|
||||||
Priority int `bson:"priority" json:"priority"` // 优先级(用于策略排序)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCollectionName 获取集合名称
|
|
||||||
func (s *Strategy) GetCollectionName() string {
|
|
||||||
return StrategyCollection
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
// UnifiedTargeting 统一的定向条件
|
|
||||||
type UnifiedTargeting struct {
|
|
||||||
// 地理定向
|
|
||||||
Countries []string `bson:"countries" json:"countries"` // 国家列表
|
|
||||||
Regions []string `bson:"regions" json:"regions"` // 地区列表
|
|
||||||
Cities []string `bson:"cities" json:"cities"` // 城市列表
|
|
||||||
PostalCodes []string `bson:"postalCodes" json:"postalCodes"` // 邮政编码列表
|
|
||||||
|
|
||||||
// 人口统计定向
|
|
||||||
AgeRange *UnifiedAgeRange `bson:"ageRange" json:"ageRange"` // 年龄范围
|
|
||||||
Gender []string `bson:"gender" json:"gender"` // 性别
|
|
||||||
Income []string `bson:"income" json:"income"` // 收入水平
|
|
||||||
Education []string `bson:"education" json:"education"` // 教育程度
|
|
||||||
Occupation []string `bson:"occupation" json:"occupation"` // 职业类型
|
|
||||||
|
|
||||||
// 兴趣定向
|
|
||||||
Interests []string `bson:"interests" json:"interests"` // 兴趣标签
|
|
||||||
Lifestyle []string `bson:"lifestyle" json:"lifestyle"` // 生活方式
|
|
||||||
|
|
||||||
// 行为定向
|
|
||||||
SearchHistory []string `bson:"searchHistory" json:"searchHistory"` // 搜索历史
|
|
||||||
BrowseHistory []string `bson:"browseHistory" json:"browseHistory"` // 浏览历史
|
|
||||||
PurchaseHistory []string `bson:"purchaseHistory" json:"purchaseHistory"` // 购买历史
|
|
||||||
AdInteractions []string `bson:"adInteractions" json:"adInteractions"` // 广告互动
|
|
||||||
Behaviors []string `bson:"behaviors" json:"behaviors"` // 行为标签
|
|
||||||
Segments []string `bson:"segments" json:"segments"` // 用户分群
|
|
||||||
|
|
||||||
// 上下文定向
|
|
||||||
Categories []string `bson:"categories" json:"categories"` // 内容分类
|
|
||||||
Keywords []string `bson:"keywords" json:"keywords"` // 关键词
|
|
||||||
Tags []string `bson:"tags" json:"tags"` // 标签
|
|
||||||
Sentiment string `bson:"sentiment" json:"sentiment"` // 情感倾向
|
|
||||||
ContentType string `bson:"contentType" json:"contentType"` // 内容类型
|
|
||||||
ContentRating string `bson:"contentRating" json:"contentRating"` // 内容评级
|
|
||||||
|
|
||||||
// 设备定向
|
|
||||||
DeviceTypes []string `bson:"deviceTypes" json:"deviceTypes"` // 设备类型
|
|
||||||
OS []string `bson:"os" json:"os"` // 操作系统
|
|
||||||
Browsers []string `bson:"browsers" json:"browsers"` // 浏览器
|
|
||||||
Carriers []string `bson:"carriers" json:"carriers"` // 运营商
|
|
||||||
ConnectionTypes []string `bson:"connectionTypes" json:"connectionTypes"` // 连接类型
|
|
||||||
|
|
||||||
// 时间定向
|
|
||||||
TimeSlots []UnifiedTimeSlot `bson:"timeSlots" json:"timeSlots"` // 时间段
|
|
||||||
DaysOfWeek []int `bson:"daysOfWeek" json:"daysOfWeek"` // 星期几
|
|
||||||
Dates []string `bson:"dates" json:"dates"` // 日期范围
|
|
||||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
|
||||||
ExcludeHolidays bool `bson:"excludeHolidays" json:"excludeHolidays"` // 排除节假日
|
|
||||||
|
|
||||||
// 扩展定向条件
|
|
||||||
CustomTargeting map[string]interface{} `bson:"customTargeting" json:"customTargeting"` // 自定义定向
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnifiedAgeRange 统一的年龄范围
|
|
||||||
type UnifiedAgeRange struct {
|
|
||||||
Min int `bson:"min" json:"min"` // 最小年龄
|
|
||||||
Max int `bson:"max" json:"max"` // 最大年龄
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnifiedTimeSlot 统一的时间段
|
|
||||||
type UnifiedTimeSlot struct {
|
|
||||||
DayOfWeek int `bson:"dayOfWeek" json:"dayOfWeek"` // 星期几:0-6,0表示星期日
|
|
||||||
StartTime string `bson:"startTime" json:"startTime"` // 开始时间,格式:HH:mm
|
|
||||||
EndTime string `bson:"endTime" json:"endTime"` // 结束时间,格式:HH:mm
|
|
||||||
Timezone string `bson:"timezone" json:"timezone"` // 时区
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,167 +0,0 @@
|
|||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cid/dao"
|
|
||||||
"cid/model/dto"
|
|
||||||
"cid/model/entity"
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/gogf/gf/v2/errors/gerror"
|
|
||||||
"github.com/gogf/gf/v2/frame/g"
|
|
||||||
"go.mongodb.org/mongo-driver/v2/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
var AdPosition = new(adPosition)
|
|
||||||
|
|
||||||
type adPosition struct{}
|
|
||||||
|
|
||||||
// Add 添加广告位
|
|
||||||
func (s *adPosition) Add(ctx context.Context, req *dto.AddAdPositionReq) (res *dto.AddAdPositionRes, err error) {
|
|
||||||
ids, err := dao.AdPosition.Insert(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res = &dto.AddAdPositionRes{Id: ids[0].(*bson.ObjectID)}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update 更新广告位
|
|
||||||
func (s *adPosition) Update(ctx context.Context, req *dto.UpdateAdPositionReq) error {
|
|
||||||
// 转换ID
|
|
||||||
id, err := bson.ObjectIDFromHex(req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return gerror.Wrap(err, "无效的ID格式")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先获取原始广告位信息
|
|
||||||
originalAdPosition, err := dao.AdPosition.GetOne(ctx, &id)
|
|
||||||
if err != nil {
|
|
||||||
return gerror.Wrap(err, "获取原始广告位信息失败")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改字段
|
|
||||||
if !g.IsEmpty(req.Name) {
|
|
||||||
originalAdPosition.Name = req.Name
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Description) {
|
|
||||||
originalAdPosition.Description = req.Description
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.PositionCode) {
|
|
||||||
originalAdPosition.PositionCode = req.PositionCode
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.AdFormat) {
|
|
||||||
originalAdPosition.AdFormat = req.AdFormat
|
|
||||||
}
|
|
||||||
if req.Width != nil {
|
|
||||||
originalAdPosition.Width = int64(*req.Width)
|
|
||||||
}
|
|
||||||
if req.Height != nil {
|
|
||||||
originalAdPosition.Height = int64(*req.Height)
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Page) {
|
|
||||||
originalAdPosition.Page = req.Page
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Section) {
|
|
||||||
originalAdPosition.Section = req.Section
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.Location) {
|
|
||||||
originalAdPosition.Location = req.Location
|
|
||||||
}
|
|
||||||
if req.MaxAds != nil {
|
|
||||||
originalAdPosition.MaxAds = *req.MaxAds
|
|
||||||
}
|
|
||||||
if req.RefreshInterval != nil {
|
|
||||||
originalAdPosition.RefreshInterval = *req.RefreshInterval
|
|
||||||
}
|
|
||||||
if req.IsLazyLoad != nil {
|
|
||||||
originalAdPosition.IsLazyLoad = *req.IsLazyLoad
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.PricingModel) {
|
|
||||||
originalAdPosition.PricingModel = req.PricingModel
|
|
||||||
}
|
|
||||||
if req.BasePrice != nil {
|
|
||||||
originalAdPosition.BasePrice = *req.BasePrice
|
|
||||||
}
|
|
||||||
if req.FloorPrice != nil {
|
|
||||||
originalAdPosition.FloorPrice = *req.FloorPrice
|
|
||||||
}
|
|
||||||
if !g.IsEmpty(req.PriceUnit) {
|
|
||||||
originalAdPosition.PriceUnit = req.PriceUnit
|
|
||||||
}
|
|
||||||
if req.DisplayRules != nil {
|
|
||||||
originalAdPosition.DisplayRules = req.DisplayRules
|
|
||||||
}
|
|
||||||
if req.Status != nil {
|
|
||||||
originalAdPosition.Status = *req.Status
|
|
||||||
}
|
|
||||||
if req.IsExclusive != nil {
|
|
||||||
originalAdPosition.IsExclusive = *req.IsExclusive
|
|
||||||
}
|
|
||||||
|
|
||||||
return dao.AdPosition.Update(ctx, &id, originalAdPosition)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus 更新广告位状态
|
|
||||||
func (s *adPosition) UpdateStatus(ctx context.Context, req *dto.UpdateAdPositionStatusReq) error {
|
|
||||||
id, err := bson.ObjectIDFromHex(req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return gerror.Wrap(err, "无效的ID格式")
|
|
||||||
}
|
|
||||||
return dao.AdPosition.UpdateStatus(ctx, &id, req.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOne 获取广告位详情
|
|
||||||
func (s *adPosition) GetOne(ctx context.Context, req *dto.GetAdPositionReq) (res *dto.GetAdPositionRes, err error) {
|
|
||||||
id, err := bson.ObjectIDFromHex(req.Id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, gerror.Wrap(err, "无效的ID格式")
|
|
||||||
}
|
|
||||||
|
|
||||||
adPosition, err := dao.AdPosition.GetOne(ctx, &id)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res = &dto.GetAdPositionRes{
|
|
||||||
AdPosition: adPosition,
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// List 获取广告位列表
|
|
||||||
func (s *adPosition) List(ctx context.Context, req *dto.ListAdPositionReq) (res *dto.ListAdPositionRes, err error) {
|
|
||||||
list, total, err := dao.AdPosition.List(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res = &dto.ListAdPositionRes{
|
|
||||||
List: list,
|
|
||||||
Total: int(total),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAvailableAdPositions 获取可用的广告位列表
|
|
||||||
func (s *adPosition) GetAvailableAdPositions(ctx context.Context) (list []*entity.AdPosition, err error) {
|
|
||||||
return dao.AdPosition.GetAvailableAdPositions(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchAd 匹配广告
|
|
||||||
func (s *adPosition) MatchAd(ctx context.Context, positionCode string, userInfo map[string]interface{}) (ad *entity.Advertisement, err error) {
|
|
||||||
// 返回匹配的广告
|
|
||||||
// 这里返回第一个广告作为示例
|
|
||||||
ad = &entity.Advertisement{
|
|
||||||
Title: "示例广告",
|
|
||||||
MaterialUrl: "https://example.com/ad.jpg",
|
|
||||||
TargetUrl: "https://example.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateAdPositionStatistics 更新广告位统计
|
|
||||||
func (s *adPosition) UpdateAdPositionStatistics(ctx context.Context, id string, impressions, clicks, revenue int64) (err error) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user