Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 450c026a6f | |||
| d9d6acee5f | |||
| 164d8956de | |||
| 3f1a08374e | |||
| 334d597f9a | |||
| 98eb15f4e4 | |||
| 3a2e679b85 | |||
| 921192a914 | |||
| 107b472cf7 | |||
| 14108f6ba3 | |||
| a22f559889 | |||
| ececfa344d | |||
| 5ba9e38e1a | |||
| 6eb4bc6d8a | |||
| 17e6c0a789 | |||
| f067ed2ad0 | |||
| 7bfc7a58ab | |||
| 1ad0c285f2 | |||
| 498c51c585 | |||
| 6a6716655b | |||
| ddc0949e56 | |||
| a723733562 | |||
| e7307182dd | |||
| 92ccebfa4e | |||
| 30dd8a8dfe | |||
| 788f1f4de7 | |||
| 54d81b5ba8 | |||
| 4912a27348 | |||
| 085820892f | |||
| 391a4c2ccb | |||
| 92363c8185 | |||
| 73b6c01cf9 | |||
| f703344485 | |||
| d9049095e3 | |||
| b2f0f91712 | |||
| ac93a5385e | |||
| 644ceed436 | |||
| 77ea55eda2 | |||
| 0f83cfc9b9 | |||
| 83749fc647 | |||
| bd5f8a9b15 | |||
| 8889be8ca2 | |||
| 6d58222143 | |||
| c3019b741c | |||
| b5b2103372 | |||
| b234c87048 | |||
| f982aa5e0c | |||
| 22823328c0 | |||
| 323e49e375 | |||
| 526e4ac198 | |||
| 7469813e37 |
+7
-11
@@ -1,20 +1,16 @@
|
||||
FROM gocv/opencv:latest AS backend-builder
|
||||
RUN echo "开始安装依赖包..."
|
||||
RUN apt update && apt install -y upx-ucl
|
||||
|
||||
FROM golang:alpine AS backend-builder
|
||||
WORKDIR /build
|
||||
COPY . .
|
||||
ENV CGO_ENABLED=1
|
||||
RUN echo "开始打包二进制文件"
|
||||
|
||||
RUN go build -ldflags="-s -w" -o bin/server
|
||||
RUN echo "开始压缩二进制文件"
|
||||
|
||||
RUN apk add --no-cache upx
|
||||
|
||||
RUN upx --best --lzma bin/server
|
||||
|
||||
FROM gocv/opencv:latest
|
||||
|
||||
FROM alpine:latest
|
||||
COPY --from=backend-builder /build/bin/server /app/server
|
||||
#COPY static /app/static
|
||||
#COPY static/*.so /app/
|
||||
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
RUN ls -a
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"likedream-goframe/internal/application/cpdaily/login"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const testSmsPhoneNumber = ""
|
||||
handler := login.SmsLoginHandler{}
|
||||
ctx := gctx.GetInitCtx()
|
||||
sendSmsData := handler.SendSms(ctx, testSmsPhoneNumber)
|
||||
// 读取验证码手动输入
|
||||
var code string
|
||||
println("请输入收到的验证码:")
|
||||
_, _ = fmt.Scanln(&code)
|
||||
loginData := handler.LoginByCode(ctx, testSmsPhoneNumber, code, sendSmsData.CookieJar)
|
||||
handler.SetLoginCookie(ctx, sendSmsData.CookieJar, loginData)
|
||||
}
|
||||
+11
-4
@@ -3,7 +3,7 @@ url = "https://devocr.likedream.xyz"
|
||||
|
||||
[database]
|
||||
type = "mysql"
|
||||
dsn = "test_likedream_go:EpXckXmxawDEQGxJ@tcp(database.out:3306)/test_likedream_go?parseTime=true"
|
||||
dsn = "test_likedream_go:EpXckXmxawDEQGxJ@tcp(database.out:3306)/test_likedream_go?parseTime=true&loc=Asia%2FShanghai"
|
||||
dsn2 = "host=database.out user=dev password=JPmKjmpcaG3EYAJZ dbname=dev port=5432 sslmode=disable TimeZone=Asia/Shanghai"
|
||||
# host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai
|
||||
[server]
|
||||
@@ -18,8 +18,9 @@ balanceMigrateUrl = "http://localhost:3200/balance-migrate/"
|
||||
# 可选值: dev, prod
|
||||
mode = "dev"
|
||||
|
||||
[ruoliCaptcha]
|
||||
baseUrl = ""
|
||||
[captcha]
|
||||
baseUrl = "http://captcha-resolver.out"
|
||||
#baseUrl = "http://localhost:8890"
|
||||
[redis]
|
||||
url = "redis://:jhkdjhkjdhsIUTYURTU_pEGmFP@database.out:56379"
|
||||
|
||||
@@ -42,10 +43,16 @@ baseUrl = "http://s3.out"
|
||||
bucket = "likedream"
|
||||
|
||||
[cpdaily]
|
||||
appVersion = "9.7.2"
|
||||
appVersion = "9.8.8"
|
||||
systemVersion = "iOS 17"
|
||||
calVersion = "firstv"
|
||||
sliderIds = ["1018764144934965", "sdhyxy", "hqdx"]
|
||||
|
||||
|
||||
|
||||
[basePoint]
|
||||
cpdailyTask = "0.5"
|
||||
cpdailyLeave = "4"
|
||||
cpdailyPhone = "0.25"
|
||||
[task]
|
||||
concurrency = 20
|
||||
@@ -0,0 +1,403 @@
|
||||
# 刷课接口文档
|
||||
|
||||
## 接口列表
|
||||
|
||||
### 1. 获取刷课列表
|
||||
|
||||
**接口地址**: `GET /course`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| type | string | 否 | 类型,可选值:`xxt`(学习通) |
|
||||
| username | string | 否 | 账号(模糊搜索) |
|
||||
| status | string | 否 | 状态,可选值:`not_start`(未开始)、`waiting`(等待中)、`doing`(进行中)、`done`(已完成)、`fail`(失败)、`pause`(暂停) |
|
||||
| page | int | 否 | 页码,默认 1 |
|
||||
| size | int | 否 | 每页数量,默认 10 |
|
||||
|
||||
**返回示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"user_id": 1,
|
||||
"username": "学习通账号",
|
||||
"password": "",
|
||||
"type": "xxt",
|
||||
"course_name": "大学英语",
|
||||
"course_id": "123456",
|
||||
"need": "task",
|
||||
"status": "waiting",
|
||||
"task_count": 10,
|
||||
"success_count": 5,
|
||||
"exam_state": "not_start",
|
||||
"violence": "no",
|
||||
"desc": "备注信息",
|
||||
"create_time": "2024-01-01T00:00:00Z",
|
||||
"update_time": "2024-01-01T00:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 100
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
|
||||
- `type`: 类型 - `xxt`(学习通)
|
||||
- `need`: 需要刷的内容 - `task`(任务点)、`exam`(考试)、`all`(全部)
|
||||
- `status`: 状态 - `not_start`(未开始)、`waiting`(等待中)、`doing`(进行中)、`done`(已完成)、`fail`(失败)、`pause`(暂停)
|
||||
- `exam_state`: 考试状态 - `not_start`(未开始)、`waiting`(等待中)、`doing`(进行中)、`done`(已完成)、`fail`(失败)
|
||||
- `violence`: 是否暴力刷课 - `no`(否)、`yes`(是)
|
||||
|
||||
---
|
||||
|
||||
### 2. 查询课程列表
|
||||
|
||||
**接口地址**: `POST /course/query`
|
||||
|
||||
**说明**: 通过学习通账号密码查询当前可选的课程列表,用于在添加刷课前选择课程。
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| username | string | 是 | 学习通账号 |
|
||||
| password | string | 是 | 学习通密码 |
|
||||
|
||||
**请求示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "学习通账号",
|
||||
"password": "学习通密码"
|
||||
}
|
||||
```
|
||||
|
||||
**返回示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": [
|
||||
{
|
||||
"cpi": 123456,
|
||||
"key": "234567",
|
||||
"courseId": "345678",
|
||||
"chatId": "456789",
|
||||
"courseTeacher": "张老师",
|
||||
"courseName": "大学英语",
|
||||
"courseImage": "https://example.com/image.jpg",
|
||||
"courseImageBase64": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAA...",
|
||||
"courseDataId": 567890,
|
||||
"ContentID": 678901,
|
||||
"isstart": true,
|
||||
"state": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
|
||||
- `cpi`: 用户唯一标识
|
||||
- `key`: 课程班级ID(classId)
|
||||
- `courseId`: 课程ID(**添加刷课时需要使用**)
|
||||
- `chatId`: 聊天ID
|
||||
- `courseTeacher`: 授课教师
|
||||
- `courseName`: 课程名称(**添加刷课时需要使用**)
|
||||
- `courseImage`: 课程封面图片URL
|
||||
- `courseImageBase64`: 课程封面图片Base64编码(包含Data URL前缀,可直接用于img标签的src属性)
|
||||
- `courseDataId`: 课程数据ID
|
||||
- `ContentID`: 内容ID
|
||||
- `isstart`: 是否已开课(true:已开课,false:未开课)
|
||||
- `state`: 课程状态(0:正常,1:已结束)
|
||||
|
||||
**注意事项**:
|
||||
|
||||
- `courseImageBase64` 字段已经包含了 Data URL 前缀(如 `data:image/jpeg;base64,`),可以直接设置到 `<img>` 标签的 `src` 属性
|
||||
- 如果图片下载失败,`courseImageBase64` 字段将为空字符串,此时可以使用 `courseImage` URL 作为备用
|
||||
|
||||
**错误示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "登录失败,请检查账号密码",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 添加刷课
|
||||
|
||||
**接口地址**: `POST /course`
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| username | string | 是 | 学习通账号 |
|
||||
| password | string | 是 | 学习通密码 |
|
||||
| type | string | 是 | 类型,目前只支持 `xxt`(学习通) |
|
||||
| course_name | string | 是 | 课程名称 |
|
||||
| course_id | string | 是 | 课程ID |
|
||||
| need | string | 是 | 需要刷的内容,可选值:`task`(任务点)、`exam`(考试)、`all`(全部) |
|
||||
| violence | string | 否 | 是否暴力刷课,可选值:`no`(否,默认)、`yes`(是) |
|
||||
| desc | string | 否 | 备注信息 |
|
||||
|
||||
**请求示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "学习通账号",
|
||||
"password": "学习通密码",
|
||||
"type": "xxt",
|
||||
"course_name": "大学英语",
|
||||
"course_id": "123456",
|
||||
"need": "task",
|
||||
"violence": "no",
|
||||
"desc": "备注信息"
|
||||
}
|
||||
```
|
||||
|
||||
**返回示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "添加成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**错误示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "该课程已存在刷课任务",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 修改刷课密码
|
||||
|
||||
**接口地址**: `PUT /course/password/{id}`
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | int64 | 是 | 刷课任务ID |
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| password | string | 是 | 新密码 |
|
||||
|
||||
**请求示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"password": "新密码"
|
||||
}
|
||||
```
|
||||
|
||||
**返回示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "密码修改成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**错误示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "课程不存在或无权限操作",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 重刷课程
|
||||
|
||||
**接口地址**: `POST /course/restart/{id}`
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | int64 | 是 | 刷课任务ID |
|
||||
|
||||
**说明**: 只有状态为 `done`(已完成)的课程才能重刷,重刷后会重置课程状态、任务数量、成功数量和考试状态。
|
||||
|
||||
**返回示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "重刷成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**错误示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "只有已完成的课程才能重刷",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 暂停/恢复刷课
|
||||
|
||||
**接口地址**: `POST /course/pause/{id}`
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | int64 | 是 | 刷课任务ID |
|
||||
|
||||
**说明**: 该接口会在暂停和恢复之间切换:
|
||||
- 如果当前状态是 `pause`(暂停),则恢复为 `waiting`(等待中)
|
||||
- 如果当前状态不是暂停,则设置为 `pause`(暂停)
|
||||
|
||||
**返回示例(暂停)**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "已暂停刷课",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**返回示例(恢复)**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "已恢复刷课",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. 删除刷课
|
||||
|
||||
**接口地址**: `DELETE /course/{id}`
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | int64 | 是 | 刷课任务ID |
|
||||
|
||||
**返回示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "删除成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**错误示例**:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 400,
|
||||
"message": "课程不存在或无权限操作",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 枚举值说明
|
||||
|
||||
### 类型 (type)
|
||||
|
||||
| 值 | 说明 |
|
||||
|-----|------|
|
||||
| xxt | 学习通 |
|
||||
|
||||
### 需要刷的内容 (need)
|
||||
|
||||
| 值 | 说明 |
|
||||
|-----|------|
|
||||
| task | 任务点 |
|
||||
| exam | 考试 |
|
||||
| all | 全部 |
|
||||
|
||||
### 状态 (status)
|
||||
|
||||
| 值 | 说明 |
|
||||
|-----|------|
|
||||
| not_start | 未开始 |
|
||||
| waiting | 等待中 |
|
||||
| doing | 进行中 |
|
||||
| done | 已完成 |
|
||||
| fail | 失败 |
|
||||
| pause | 暂停 |
|
||||
|
||||
### 考试状态 (exam_state)
|
||||
|
||||
| 值 | 说明 |
|
||||
|-----|------|
|
||||
| not_start | 未开始 |
|
||||
| waiting | 等待中 |
|
||||
| doing | 进行中 |
|
||||
| done | 已完成 |
|
||||
| fail | 失败 |
|
||||
|
||||
### 是否暴力刷课 (violence)
|
||||
|
||||
| 值 | 说明 |
|
||||
|-----|------|
|
||||
| no | 否 |
|
||||
| yes | 是 |
|
||||
|
||||
---
|
||||
|
||||
## 通用说明
|
||||
|
||||
### 认证
|
||||
|
||||
所有接口都需要用户认证,需要在请求头中携带认证信息(具体认证方式根据项目配置)。
|
||||
|
||||
### 权限
|
||||
|
||||
用户只能操作自己创建的刷课任务,无法访问或修改其他用户的数据。
|
||||
|
||||
### 错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 200 | 成功 |
|
||||
| 400 | 业务错误(如参数错误、权限不足等) |
|
||||
| 401 | 未认证 |
|
||||
| 500 | 服务器错误 |
|
||||
@@ -19,21 +19,17 @@ require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hibiken/asynq v0.25.1
|
||||
github.com/joomcode/errorx v1.2.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/redis/go-redis/v9 v9.11.0
|
||||
github.com/samber/oops v1.19.0
|
||||
github.com/shirou/gopsutil/v3 v3.24.5
|
||||
github.com/shopspring/decimal v1.4.0
|
||||
github.com/thedevsaddam/gojsonq v1.9.1
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/tidwall/match v1.1.1
|
||||
github.com/wenlng/go-captcha-assets v1.0.7
|
||||
github.com/wenlng/go-captcha/v2 v2.0.4
|
||||
github.com/wneessen/go-mail v0.6.2
|
||||
github.com/yalue/onnxruntime_go v1.12.1
|
||||
go.uber.org/automaxprocs v1.6.0
|
||||
go.uber.org/zap v1.27.0
|
||||
gocv.io/x/gocv v0.42.0
|
||||
golang.org/x/crypto v0.43.0
|
||||
gorm.io/driver/postgres v1.6.0
|
||||
gorm.io/gorm v1.31.1
|
||||
|
||||
@@ -150,8 +150,6 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s=
|
||||
github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
@@ -199,8 +197,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/thedevsaddam/gojsonq v1.9.1 h1:zQulEP43nwmq5EKrNWyIgJVbqDeMdC1qzXM/f5O15a0=
|
||||
github.com/thedevsaddam/gojsonq v1.9.1/go.mod h1:RBcQaITThgJAAYKH7FNp2onYodRz8URfsuEGpAch0NA=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
@@ -219,8 +215,6 @@ github.com/wenlng/go-captcha/v2 v2.0.4 h1:5cSUF36ZyA03qeDMjKmeXGpbYJMXEexZIYK3Vg
|
||||
github.com/wenlng/go-captcha/v2 v2.0.4/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34=
|
||||
github.com/wneessen/go-mail v0.6.2 h1:c6V7c8D2mz868z9WJ+8zDKtUyLfZ1++uAZmo2GRFji8=
|
||||
github.com/wneessen/go-mail v0.6.2/go.mod h1:L/PYjPK3/2ZlNb2/FjEBIn9n1rUWjW+Toy531oVmeb4=
|
||||
github.com/yalue/onnxruntime_go v1.12.1 h1:joCCmBnNjHy04jK9EMP/UV6oPPqySXlRgf3gcUcnI/g=
|
||||
github.com/yalue/onnxruntime_go v1.12.1/go.mod h1:b4X26A8pekNb1ACJ58wAXgNKeUCGEAQ9dmACut9Sm/4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
@@ -244,8 +238,6 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
gocv.io/x/gocv v0.42.0 h1:AAsrFJH2aIsQHukkCovWqj0MCGZleQpVyf5gNVRXjQI=
|
||||
gocv.io/x/gocv v0.42.0/go.mod h1:zYdWMj29WAEznM3Y8NsU3A0TRq/wR/cy75jeUypThqU=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
||||
@@ -4,8 +4,11 @@ import (
|
||||
"context"
|
||||
"likedream-goframe/internal/common/cst"
|
||||
"likedream-goframe/internal/controller/agent"
|
||||
"likedream-goframe/internal/controller/balance"
|
||||
"likedream-goframe/internal/controller/card"
|
||||
"likedream-goframe/internal/controller/common"
|
||||
"likedream-goframe/internal/controller/config"
|
||||
"likedream-goframe/internal/controller/course"
|
||||
"likedream-goframe/internal/controller/cpdaily"
|
||||
"likedream-goframe/internal/controller/menu"
|
||||
"likedream-goframe/internal/controller/music"
|
||||
@@ -40,10 +43,12 @@ func StartServer(ctx context.Context) {
|
||||
systemGroup.Bind(role.NewV1())
|
||||
systemGroup.Bind(menu.NewV1())
|
||||
systemGroup.Bind(user.NewUserCtrlV1())
|
||||
systemGroup.Bind(config.NewConfigCtrlV1())
|
||||
//systemGroup.Bind(agent.NewV1())
|
||||
// 用户信息路由
|
||||
userGroup := group.Group("/user").Middleware(middleware.AuthHandler, middleware.PermissionHandler)
|
||||
userGroup.Bind(user_login.NewUserInfoV1())
|
||||
userGroup.Bind(balance.NewBalanceCtrlV1())
|
||||
// 代理信息路由
|
||||
agentGroup := group.Group("/agent").Middleware(middleware.AuthHandler, middleware.PermissionHandler)
|
||||
agentGroup.Bind(agent.NewV1())
|
||||
@@ -54,8 +59,13 @@ func StartServer(ctx context.Context) {
|
||||
cpdailyGroup.Bind(cpdaily.NewCpTaskCtrlV1())
|
||||
cpdailyGroup.Bind(cpdaily.NewCpImageCtrlV1())
|
||||
cpdailyGroup.Bind(cpdaily.NewCpTaskLogCtrlV1())
|
||||
cpdailyGroup.Bind(cpdaily.NewCpLeaveCtrlV1())
|
||||
// 娱乐
|
||||
musicGroup := group.Group("/music").Middleware(middleware.AuthHandler, middleware.PermissionHandler)
|
||||
musicGroup.Bind(music.NewMusicCtrlV1())
|
||||
// 网课
|
||||
courseGroup := group.Group("/course").Middleware(middleware.AuthHandler, middleware.PermissionHandler)
|
||||
courseGroup.Bind(course.NewXxtCtrlV1())
|
||||
})
|
||||
|
||||
s.SetPort(port.Int())
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
type BalanceRecordListReq struct {
|
||||
g.Meta `path:"/balance/records" method:"get" tags:"Balance" summary:"获取用户余额变动记录列表"`
|
||||
Type string `json:"type" dc:"变动类型: increase-增加, decrease-减少"`
|
||||
Page int `json:"page" d:"1"`
|
||||
Size int `json:"size" d:"10"`
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type ConfigGetReq struct {
|
||||
g.Meta `path:"/config/{key}" method:"get" tags:"Config" summary:"获取配置"`
|
||||
Key string `json:"key" v:"required#配置键不能为空"`
|
||||
}
|
||||
|
||||
type ConfigUpdateReq struct {
|
||||
g.Meta `path:"/config/{key}" method:"put" tags:"Config" summary:"更新配置" permission:"sys:config:edit"`
|
||||
Key string `json:"key" v:"required#配置键不能为空"`
|
||||
Value string `json:"value" v:"required#配置值不能为空"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type ConfigListReq struct {
|
||||
g.Meta `path:"/config" method:"get" tags:"Config" summary:"获取配置列表"`
|
||||
Key string `json:"key"`
|
||||
Page int `json:"page" d:"1"`
|
||||
Size int `json:"size" d:"10"`
|
||||
}
|
||||
|
||||
type ConfigPublicGetReq struct {
|
||||
g.Meta `path:"/config/public/{key}" method:"get" tags:"Config" summary:"获取公开配置(无需认证)"`
|
||||
Key string `json:"key" v:"required#配置键不能为空"`
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"likedream-goframe/internal/ent/courseentity"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type CourseListReq struct {
|
||||
g.Meta `path:"/course" method:"get" tags:"Course" summary:"获取刷课列表"`
|
||||
Type courseentity.Type `json:"type"`
|
||||
Username string `json:"username"`
|
||||
Status courseentity.Status `json:"status"`
|
||||
Page int `json:"page" d:"1"`
|
||||
Size int `json:"size" d:"10"`
|
||||
}
|
||||
|
||||
type AddCourseReq struct {
|
||||
g.Meta `path:"/course" method:"post" tags:"Course" summary:"添加刷课"`
|
||||
Username string `json:"username" v:"required#账号不能为空"`
|
||||
Password string `json:"password" v:"required#密码不能为空"`
|
||||
Type courseentity.Type `json:"type" v:"required#类型不能为空"`
|
||||
CourseName string `json:"course_name" v:"required#课程名称不能为空"`
|
||||
CourseID string `json:"course_id" v:"required#课程ID不能为空"`
|
||||
Need courseentity.Need `json:"need" v:"required#需要刷的内容不能为空"`
|
||||
Violence courseentity.Violence `json:"violence" d:"no"`
|
||||
Desc string `json:"desc"`
|
||||
}
|
||||
|
||||
type UpdateCoursePasswordReq struct {
|
||||
g.Meta `path:"/course/password/{id}" method:"put" tags:"Course" summary:"修改刷课密码"`
|
||||
ID int64 `json:"id"`
|
||||
Password string `json:"password" v:"required#密码不能为空"`
|
||||
}
|
||||
|
||||
type RestartCourseReq struct {
|
||||
g.Meta `path:"/course/restart/{id}" method:"post" tags:"Course" summary:"重刷课程"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type PauseCourseReq struct {
|
||||
g.Meta `path:"/course/pause/{id}" method:"post" tags:"Course" summary:"暂停刷课"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type DeleteCourseReq struct {
|
||||
g.Meta `path:"/course/{id}" method:"delete" tags:"Course" summary:"删除刷课"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type QueryCourseReq struct {
|
||||
g.Meta `path:"/course/query" method:"post" tags:"Course" summary:"查询课程列表"`
|
||||
Username string `json:"username" v:"required#账号不能为空"`
|
||||
Password string `json:"password" v:"required#密码不能为空"`
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package v1
|
||||
|
||||
// TaskStatisticsItem 每日任务统计项
|
||||
type TaskStatisticsItem struct {
|
||||
Date string `json:"date"` // 日期 格式:2006-01-02
|
||||
PendingTask int `json:"pendingTask"` // 需要完成的任务数
|
||||
SuccessTask int `json:"successTask"` // 成功执行的任务数
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type CpLeaveListReq struct {
|
||||
g.Meta `path:"/leave" method:"get" tags:"CpLeave" summary:"获取销假记录列表"`
|
||||
CpUserId int64 `json:"cpUserId"`
|
||||
Username string `json:"username"`
|
||||
Status string `json:"status"`
|
||||
Page int `json:"page" d:"1"`
|
||||
Size int `json:"size" d:"10"`
|
||||
}
|
||||
|
||||
type GetLeaveListFromSystemReq struct {
|
||||
g.Meta `path:"/leave/system/{cpUserId}" method:"get" tags:"CpLeave" summary:"获取今日校园系统中的请假列表"`
|
||||
CpUserId int64 `json:"cpUserId" v:"required#今日校园账号ID不能为空"`
|
||||
}
|
||||
|
||||
type CpLeaveReportReq struct {
|
||||
g.Meta `path:"/leave/report" method:"post" tags:"CpLeave" summary:"执行销假"`
|
||||
CpUserId int64 `json:"cpUserId" v:"required#今日校园账号ID不能为空"`
|
||||
LeaveId string `json:"leaveId" v:"required#请假记录ID不能为空"`
|
||||
Title string `json:"title" v:"required#请假记录标题不能为空"`
|
||||
}
|
||||
@@ -67,3 +67,12 @@ type PauseTaskReq struct {
|
||||
g.Meta `path:"/task/pause/{id}" method:"post" tags:"CpTask" summary:"暂停任务"`
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
type FindLocationReq struct {
|
||||
g.Meta `path:"/task/location" method:"get" tags:"CpTask" summary:"查找地址"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
type GetTaskStatisticsReq struct {
|
||||
g.Meta `path:"/task/statistics" method:"get" tags:"CpTask" summary:"获取近七日任务统计数据"`
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
import (
|
||||
"likedream-goframe/internal/framework/captcha"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type CpSchoolListReq struct {
|
||||
g.Meta `path:"/school" method:"get" tags:"CpSchool" summary:"获取cp学校列表"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type CpUserLoginUrlReq struct {
|
||||
g.Meta `path:"/loginUrl" method:"get" tags:"CpUser" summary:"获取登录url" auth:"false"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type CpUserAddReq struct {
|
||||
g.Meta `path:"/user" method:"post" tags:"CpUser" summary:"添加cp用户"`
|
||||
Username string `json:"username" v:"required"`
|
||||
@@ -14,6 +21,24 @@ type CpUserAddReq struct {
|
||||
SchoolId string `json:"school_id"`
|
||||
Email string `json:"email" v:"email|regex:^.*@qq\\.com$#邮箱格式不正确|必须是QQ邮箱"`
|
||||
}
|
||||
type LoginGetCode struct {
|
||||
g.Meta `path:"/user/getCode" method:"post" tags:"CpUser" summary:"获取手机号登录验证码"`
|
||||
Mobile string `json:"mobile" v:"required#手机号不能为空"`
|
||||
CaptchaKey string `json:"captchaKey" v:"required#验证码不能不能为空"`
|
||||
Dots []captcha.ConfirmData `json:"dots" v:"required#验证码不能为空"`
|
||||
}
|
||||
|
||||
type AddByCode struct {
|
||||
g.Meta `path:"/user/addByCode" method:"post" tags:"CpUser" summary:"手机号登录"`
|
||||
Id int64 `json:"id"`
|
||||
CaptchaKey string `json:"captchaKey" v:"required#验证码不能不能为空"`
|
||||
Dots []captcha.ConfirmData `json:"dots" v:"required#验证码不能为空"`
|
||||
Mobile string `json:"mobile" v:"required#手机号不能为空"`
|
||||
SchoolId string `json:"school_id"`
|
||||
Code string `json:"code"`
|
||||
Email string `json:"email" v:"email|regex:^.*@qq\\.com$#邮箱格式不正确|必须是QQ邮箱"`
|
||||
}
|
||||
|
||||
type CpUserConfirmAddReq struct {
|
||||
g.Meta `path:"/user/confirm" method:"post" tags:"CpUser" summary:"多因子确认添加cp用户"`
|
||||
Key string `json:"key"`
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/common/cst"
|
||||
"likedream-goframe/internal/utils"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/samber/oops"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func ApiSemiOCRVerification(bytes []byte, shape1, shape2 int64) string {
|
||||
data := Bytes2Base64(bytes)
|
||||
ctx := gctx.GetInitCtx()
|
||||
baseUrl := g.Config().MustGetWithEnv(ctx, cst.ConfigCaptchaBaseUrl).String() + "/semiOcr"
|
||||
client := httpclient.Cpdaily.Clone(ctx)
|
||||
client.SetDoNotParseResponse(false)
|
||||
post, err := client.R().SetBody(map[string]any{
|
||||
"base64": data,
|
||||
"shape1": shape1,
|
||||
"shape2": shape2,
|
||||
}).Post(baseUrl)
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
With("SemiOCRVerification", baseUrl).
|
||||
WithContext(ctx).
|
||||
Wrap(err)
|
||||
})
|
||||
result := post.String()
|
||||
return gjson.Get(result, "data").String()
|
||||
}
|
||||
|
||||
func ApiAutoOCRVerification(bytes []byte) string {
|
||||
data := Bytes2Base64(bytes)
|
||||
ctx := gctx.GetInitCtx()
|
||||
baseUrl := g.Config().MustGetWithEnv(ctx, cst.ConfigCaptchaBaseUrl).String() + "/ocr"
|
||||
client := httpclient.Cpdaily.Clone(ctx)
|
||||
client.SetDoNotParseResponse(false)
|
||||
post, err := client.R().SetBody(map[string]any{
|
||||
"base64": data,
|
||||
}).Post(baseUrl)
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
With("AutoOCRVerification", baseUrl).
|
||||
WithContext(ctx).
|
||||
Wrap(err)
|
||||
})
|
||||
result := post.String()
|
||||
return gjson.Get(result, "data").String()
|
||||
}
|
||||
func Bytes2Base64(data []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(data)
|
||||
}
|
||||
@@ -8,20 +8,21 @@ import (
|
||||
"likedream-goframe/internal/utils"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type domainMap map[string]cookieMap
|
||||
|
||||
// AllSavePersistCookieJar 支持泛域名的 Cookie Jar
|
||||
// 不同的二级域名会共享相同主域名的 cookies
|
||||
// 例如: passport2.chaoxing.com 和 mooc1-api.chaoxing.com 共享 .chaoxing.com 的 cookies
|
||||
// AllSavePersistCookieJar 完全无限制的 Cookie Jar
|
||||
// 所有域名的 cookies 都保存在一起,访问任何域名都返回所有 cookies
|
||||
// 不检查域名、路径等限制,适用于需要跨域共享 session 的场景
|
||||
type AllSavePersistCookieJar struct {
|
||||
domainMap domainMap
|
||||
*sync.RWMutex
|
||||
}
|
||||
|
||||
const globalDomain = "*" // 使用全局域名存储所有 cookies
|
||||
|
||||
func NewAllSavePersistCookieJar() *AllSavePersistCookieJar {
|
||||
return &AllSavePersistCookieJar{
|
||||
domainMap: make(domainMap),
|
||||
@@ -29,47 +30,22 @@ func NewAllSavePersistCookieJar() *AllSavePersistCookieJar {
|
||||
}
|
||||
}
|
||||
|
||||
// extractMainDomain 提取主域名
|
||||
// 例如: passport2.chaoxing.com -> chaoxing.com
|
||||
//
|
||||
// mooc1-api.chaoxing.com -> chaoxing.com
|
||||
// www.example.co.uk -> example.co.uk
|
||||
func extractMainDomain(host string) string {
|
||||
// 移除端口号
|
||||
if colonIndex := strings.Index(host, ":"); colonIndex != -1 {
|
||||
host = host[:colonIndex]
|
||||
}
|
||||
|
||||
parts := strings.Split(host, ".")
|
||||
if len(parts) <= 2 {
|
||||
// 已经是主域名或单级域名
|
||||
return host
|
||||
}
|
||||
|
||||
// 处理特殊的二级顶级域名,如 .co.uk, .com.cn 等
|
||||
// 简化处理:取最后两部分
|
||||
// 更复杂的情况可以使用 publicsuffix 包
|
||||
return strings.Join(parts[len(parts)-2:], ".")
|
||||
}
|
||||
|
||||
func (a *AllSavePersistCookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
// 提取主域名
|
||||
mainDomain := extractMainDomain(u.Host)
|
||||
|
||||
if _, exists := a.domainMap[mainDomain]; !exists {
|
||||
a.domainMap[mainDomain] = make(cookieMap)
|
||||
// 使用全局域名,所有 cookies 保存在一起
|
||||
if _, exists := a.domainMap[globalDomain]; !exists {
|
||||
a.domainMap[globalDomain] = make(cookieMap)
|
||||
}
|
||||
|
||||
for _, cookie := range cookies {
|
||||
if a.domainMap[mainDomain] == nil {
|
||||
a.domainMap[mainDomain] = make(cookieMap)
|
||||
if a.domainMap[globalDomain] == nil {
|
||||
a.domainMap[globalDomain] = make(cookieMap)
|
||||
}
|
||||
|
||||
// 查找是否存在相同 name, path 和 domain 的 cookie
|
||||
existingCookies := a.domainMap[mainDomain][cookie.Name]
|
||||
// 查找是否存在相同 name 的 cookie(忽略 path 和 domain)
|
||||
existingCookies := a.domainMap[globalDomain][cookie.Name]
|
||||
found := false
|
||||
for i, existing := range existingCookies {
|
||||
if existing.Path == cookie.Path && existing.Domain == cookie.Domain {
|
||||
@@ -82,7 +58,7 @@ func (a *AllSavePersistCookieJar) SetCookies(u *url.URL, cookies []*http.Cookie)
|
||||
|
||||
if !found {
|
||||
// 没有找到匹配的,添加新的 cookie
|
||||
a.domainMap[mainDomain][cookie.Name] = append(a.domainMap[mainDomain][cookie.Name], cookie)
|
||||
a.domainMap[globalDomain][cookie.Name] = append(a.domainMap[globalDomain][cookie.Name], cookie)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,15 +67,9 @@ func (a *AllSavePersistCookieJar) Cookies(u *url.URL) []*http.Cookie {
|
||||
a.RLock()
|
||||
defer a.RUnlock()
|
||||
|
||||
// 提取主域名
|
||||
mainDomain := extractMainDomain(u.Host)
|
||||
|
||||
if cookiesList, exists := a.domainMap[mainDomain]; exists {
|
||||
// 直接返回全局域名下的所有 cookies,不检查域名和路径
|
||||
if cookiesList, exists := a.domainMap[globalDomain]; exists {
|
||||
result := make([]*http.Cookie, 0, len(cookiesList))
|
||||
requestPath := u.Path
|
||||
if requestPath == "" {
|
||||
requestPath = "/"
|
||||
}
|
||||
|
||||
for _, cookies := range cookiesList {
|
||||
// 如果只有一个 cookie,直接返回
|
||||
@@ -108,28 +78,9 @@ func (a *AllSavePersistCookieJar) Cookies(u *url.URL) []*http.Cookie {
|
||||
continue
|
||||
}
|
||||
|
||||
// 有多个同名 cookie,选择最匹配的(path 最长且匹配请求路径的)
|
||||
var bestMatch *http.Cookie
|
||||
bestMatchLen := -1
|
||||
|
||||
for _, cookie := range cookies {
|
||||
cookiePath := cookie.Path
|
||||
if cookiePath == "" {
|
||||
cookiePath = "/"
|
||||
}
|
||||
|
||||
// 检查 path 是否匹配
|
||||
if pathMatch(requestPath, cookiePath) {
|
||||
if len(cookiePath) > bestMatchLen {
|
||||
bestMatch = cookie
|
||||
bestMatchLen = len(cookiePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到匹配的,添加到结果中
|
||||
if bestMatch != nil {
|
||||
result = append(result, bestMatch)
|
||||
// 有多个同名 cookie,返回最后设置的那个(列表最后一个)
|
||||
if len(cookies) > 0 {
|
||||
result = append(result, cookies[len(cookies)-1])
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -43,6 +43,11 @@ func (p *PersistCookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
|
||||
p.hostMap[host] = make(cookieMap)
|
||||
}
|
||||
|
||||
// 检查并删除全局 cookie 中同名的 cookie
|
||||
if globalCookies, exists := p.hostMap[""]; exists {
|
||||
delete(globalCookies, cookie.Name)
|
||||
}
|
||||
|
||||
// 查找是否存在相同 name, path 和 domain 的 cookie
|
||||
existingCookies := p.hostMap[host][cookie.Name]
|
||||
found := false
|
||||
@@ -68,17 +73,21 @@ func (p *PersistCookieJar) Cookies(u *url.URL) []*http.Cookie {
|
||||
defer p.RUnlock()
|
||||
|
||||
host := u.Host
|
||||
if cookiesList, exists := p.hostMap[host]; exists {
|
||||
result := make([]*http.Cookie, 0, len(cookiesList))
|
||||
requestPath := u.Path
|
||||
if requestPath == "" {
|
||||
requestPath = "/"
|
||||
}
|
||||
requestPath := u.Path
|
||||
if requestPath == "" {
|
||||
requestPath = "/"
|
||||
}
|
||||
|
||||
for _, cookies := range cookiesList {
|
||||
result := make([]*http.Cookie, 0)
|
||||
addedNames := make(map[string]bool)
|
||||
|
||||
// 先添加匹配 host 的 cookie
|
||||
if cookiesList, exists := p.hostMap[host]; exists {
|
||||
for cookieName, cookies := range cookiesList {
|
||||
// 如果只有一个 cookie,直接返回
|
||||
if len(cookies) == 1 {
|
||||
result = append(result, cookies[0])
|
||||
addedNames[cookieName] = true
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -104,11 +113,50 @@ func (p *PersistCookieJar) Cookies(u *url.URL) []*http.Cookie {
|
||||
// 如果找到匹配的,添加到结果中
|
||||
if bestMatch != nil {
|
||||
result = append(result, bestMatch)
|
||||
addedNames[cookieName] = true
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
|
||||
// 再添加没有 host 的全局 cookie(避免重复)
|
||||
if globalCookies, exists := p.hostMap[""]; exists {
|
||||
for cookieName, cookies := range globalCookies {
|
||||
// 如果该名称的 cookie 已经从 host 中添加了,跳过
|
||||
if addedNames[cookieName] {
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果只有一个 cookie,直接返回
|
||||
if len(cookies) == 1 {
|
||||
result = append(result, cookies[0])
|
||||
continue
|
||||
}
|
||||
|
||||
// 有多个同名 cookie,选择最匹配的
|
||||
var bestMatch *http.Cookie
|
||||
bestMatchLen := -1
|
||||
|
||||
for _, cookie := range cookies {
|
||||
cookiePath := cookie.Path
|
||||
if cookiePath == "" {
|
||||
cookiePath = "/"
|
||||
}
|
||||
|
||||
if pathMatch(requestPath, cookiePath) {
|
||||
if len(cookiePath) > bestMatchLen {
|
||||
bestMatch = cookie
|
||||
bestMatchLen = len(cookiePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if bestMatch != nil {
|
||||
result = append(result, bestMatch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// pathMatch 检查请求路径是否匹配 cookie 的 path
|
||||
@@ -275,3 +323,30 @@ func (p *PersistCookieJar) DeserializeReader(reader io.Reader) {
|
||||
|
||||
p.hostMap = hostMap
|
||||
}
|
||||
|
||||
// RemoveCookieInfo 将所有 host 的 cookie 移除 host 信息,存储为全局 cookie
|
||||
func (p *PersistCookieJar) RemoveCookieInfo() {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
// 确保全局 cookie map 存在
|
||||
if _, exists := p.hostMap[""]; !exists {
|
||||
p.hostMap[""] = make(cookieMap)
|
||||
}
|
||||
|
||||
// 将所有 host 的 cookie 移动到全局
|
||||
for host, hostCookies := range p.hostMap {
|
||||
// 跳过全局 cookie 本身
|
||||
if host == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// 将该 host 的所有 cookie 移动到全局
|
||||
for cookieName, cookies := range hostCookies {
|
||||
p.hostMap[""][cookieName] = cookies
|
||||
}
|
||||
|
||||
// 删除该 host 的 cookie
|
||||
delete(p.hostMap, host)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package cryptoutil
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAesDecrypt(t *testing.T) {
|
||||
str := "457xXTd3ZBTY0017ueFiMR0gFff7W2NuXH39lkT/kvTTCKqhXA1vjJwgtmzRgZOC+qEpA3O9GmAroR+A1lORFVqe+q7o3alKOKj4rxPUUSwcyqGUF2LMNbxFXrmWUEPzeedbdUtlI+ufR8SLXNHbZSs0ECPy864bwUAuSDhFcD235c/3AbiTNacXIZZ+paK0T6GWxS291XbffgNCpGFa+5jCaP7/t9erCUjId9Zm4hmoaHkhqGRKAgZrLwuICa4lTFNOQqLA1N/Dljd/ZPVbZGVZaJQ0oV3zEaQQDCWuSTcWF4JVVeaCw9s/8mqkarg+RIz3/OA8dCvc8Wo6auMGzXT6IlisCX+S5TuPlhKKo1ttAW1KrWNg2nkZMxyD+kTKtNijvZRsdQnA8znVp0q2p0byyvzevaB6qSYUM9NBcaxyxkes5Bd1lKCTUHPaG93Jz4SQ+B8MQ1rLm13eWY8uME/WBTOraG7Rgmba32zBccC6BWwV3ncNGhu7hLL0dIhdgIpuxnrFmXDw4HX/IM+cnCxAFo7+EfzKb4l3yDMyr2d+0tDlVl4UbUR2uRTGz5r/7vVI1WtLgM0fiRTk56JU5BwRrutS7KonsLzugbEp/E8="
|
||||
str = strings.ReplaceAll(str, " ", "")
|
||||
decodeString, _ := base64.StdEncoding.DecodeString(str)
|
||||
decrypt := AesDecryptForCat(decodeString)
|
||||
t.Log(string(decrypt))
|
||||
}
|
||||
@@ -0,0 +1,838 @@
|
||||
package cryptoutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RSA Constants
|
||||
const (
|
||||
biRadixBits = 16
|
||||
bitsPerDigit = biRadixBits
|
||||
biRadix = 1 << 16 // 65536
|
||||
biHalfRadix = biRadix >> 1
|
||||
biRadixSquared = biRadix * biRadix
|
||||
maxDigitVal = biRadix - 1
|
||||
maxInteger = 9999999999999998
|
||||
dpl10 = 15
|
||||
)
|
||||
|
||||
var (
|
||||
maxDigits int
|
||||
zeroArray []int
|
||||
bigZero *BigInt
|
||||
bigOne *BigInt
|
||||
lr10 *BigInt
|
||||
highBitMasks = []int{0x0000, 0x8000, 0xC000, 0xE000, 0xF000, 0xF800,
|
||||
0xFC00, 0xFE00, 0xFF00, 0xFF80, 0xFFC0, 0xFFE0,
|
||||
0xFFF0, 0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF}
|
||||
lowBitMasks = []int{0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,
|
||||
0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,
|
||||
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}
|
||||
hexToChar = []byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f'}
|
||||
hexatrigesimalToChar = []byte{
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z'}
|
||||
)
|
||||
|
||||
// BigInt represents a big integer
|
||||
type BigInt struct {
|
||||
digits []int
|
||||
isNeg bool
|
||||
}
|
||||
|
||||
// NewBigInt creates a new BigInt
|
||||
func NewBigInt() *BigInt {
|
||||
digits := make([]int, len(zeroArray))
|
||||
copy(digits, zeroArray)
|
||||
return &BigInt{
|
||||
digits: digits,
|
||||
isNeg: false,
|
||||
}
|
||||
}
|
||||
|
||||
// NewBigIntEmpty creates an empty BigInt
|
||||
func NewBigIntEmpty() *BigInt {
|
||||
return &BigInt{
|
||||
digits: nil,
|
||||
isNeg: false,
|
||||
}
|
||||
}
|
||||
|
||||
// SetMaxDigits sets the maximum number of digits
|
||||
func SetMaxDigits(value int) {
|
||||
maxDigits = value
|
||||
zeroArray = make([]int, maxDigits)
|
||||
bigZero = NewBigInt()
|
||||
bigOne = NewBigInt()
|
||||
bigOne.digits[0] = 1
|
||||
lr10 = BiFromNumber(1000000000000000)
|
||||
}
|
||||
|
||||
// BiFromNumber creates a BigInt from a number
|
||||
func BiFromNumber(i int64) *BigInt {
|
||||
result := NewBigInt()
|
||||
result.isNeg = i < 0
|
||||
i = int64(math.Abs(float64(i)))
|
||||
j := 0
|
||||
for i > 0 {
|
||||
result.digits[j] = int(i & maxDigitVal)
|
||||
j++
|
||||
i = i / biRadix
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BiFromDecimal creates a BigInt from a decimal string
|
||||
func BiFromDecimal(s string) *BigInt {
|
||||
isNeg := len(s) > 0 && s[0] == '-'
|
||||
i := 0
|
||||
if isNeg {
|
||||
i = 1
|
||||
}
|
||||
|
||||
// Skip leading zeros
|
||||
for i < len(s) && s[i] == '0' {
|
||||
i++
|
||||
}
|
||||
|
||||
if i == len(s) {
|
||||
return NewBigInt()
|
||||
}
|
||||
|
||||
digitCount := len(s) - i
|
||||
fgl := digitCount % dpl10
|
||||
if fgl == 0 {
|
||||
fgl = dpl10
|
||||
}
|
||||
|
||||
num := parseNumber(s[i : i+fgl])
|
||||
result := BiFromNumber(num)
|
||||
i += fgl
|
||||
|
||||
for i < len(s) {
|
||||
result = BiAdd(BiMultiply(result, lr10), BiFromNumber(parseNumber(s[i:min(i+dpl10, len(s))])))
|
||||
i += dpl10
|
||||
}
|
||||
|
||||
result.isNeg = isNeg
|
||||
return result
|
||||
}
|
||||
|
||||
// BiCopy copies a BigInt
|
||||
func BiCopy(bi *BigInt) *BigInt {
|
||||
result := NewBigIntEmpty()
|
||||
result.digits = make([]int, len(bi.digits))
|
||||
copy(result.digits, bi.digits)
|
||||
result.isNeg = bi.isNeg
|
||||
return result
|
||||
}
|
||||
|
||||
// ReverseStr reverses a string
|
||||
func ReverseStr(s string) string {
|
||||
runes := []rune(s)
|
||||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||||
runes[i], runes[j] = runes[j], runes[i]
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// BiToString converts BigInt to string with given radix
|
||||
func BiToString(x *BigInt, radix int) string {
|
||||
b := NewBigInt()
|
||||
b.digits[0] = radix
|
||||
qr := BiDivideModulo(x, b)
|
||||
result := string(hexatrigesimalToChar[qr[1].digits[0]])
|
||||
|
||||
for BiCompare(qr[0], bigZero) == 1 {
|
||||
qr = BiDivideModulo(qr[0], b)
|
||||
result += string(hexatrigesimalToChar[qr[1].digits[0]])
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
if x.isNeg {
|
||||
prefix = "-"
|
||||
}
|
||||
return prefix + ReverseStr(result)
|
||||
}
|
||||
|
||||
// BiToDecimal converts BigInt to decimal string
|
||||
func BiToDecimal(x *BigInt) string {
|
||||
b := NewBigInt()
|
||||
b.digits[0] = 10
|
||||
qr := BiDivideModulo(x, b)
|
||||
result := fmt.Sprintf("%d", qr[1].digits[0])
|
||||
|
||||
for BiCompare(qr[0], bigZero) == 1 {
|
||||
qr = BiDivideModulo(qr[0], b)
|
||||
result += fmt.Sprintf("%d", qr[1].digits[0])
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
if x.isNeg {
|
||||
prefix = "-"
|
||||
}
|
||||
return prefix + ReverseStr(result)
|
||||
}
|
||||
|
||||
// DigitToHex converts a digit to hex string
|
||||
func DigitToHex(n int) string {
|
||||
mask := 0xf
|
||||
result := ""
|
||||
for i := 0; i < 4; i++ {
|
||||
result += string(hexToChar[n&mask])
|
||||
n >>= 4
|
||||
}
|
||||
return ReverseStr(result)
|
||||
}
|
||||
|
||||
// BiToHex converts BigInt to hex string
|
||||
func BiToHex(x *BigInt) string {
|
||||
result := ""
|
||||
for i := BiHighIndex(x); i > -1; i-- {
|
||||
result += DigitToHex(x.digits[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CharToHex converts a character code to hex value
|
||||
func CharToHex(c byte) int {
|
||||
const (
|
||||
ZERO = 48
|
||||
NINE = ZERO + 9
|
||||
littleA = 97
|
||||
littleZ = littleA + 25
|
||||
bigA = 65
|
||||
bigZ = 65 + 25
|
||||
)
|
||||
|
||||
if c >= ZERO && c <= NINE {
|
||||
return int(c - ZERO)
|
||||
} else if c >= bigA && c <= bigZ {
|
||||
return 10 + int(c-bigA)
|
||||
} else if c >= littleA && c <= littleZ {
|
||||
return 10 + int(c-littleA)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// HexToDigit converts hex string to digit
|
||||
func HexToDigit(s string) int {
|
||||
result := 0
|
||||
sl := min(len(s), 4)
|
||||
for i := 0; i < sl; i++ {
|
||||
result <<= 4
|
||||
result |= CharToHex(s[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BiFromHex creates BigInt from hex string
|
||||
func BiFromHex(s string) *BigInt {
|
||||
result := NewBigInt()
|
||||
sl := len(s)
|
||||
for i, j := sl, 0; i > 0; i, j = i-4, j+1 {
|
||||
start := max(i-4, 0)
|
||||
length := min(i, 4)
|
||||
if start+length > sl {
|
||||
length = sl - start
|
||||
}
|
||||
result.digits[j] = HexToDigit(s[start : start+length])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BiFromString creates BigInt from string with given radix
|
||||
func BiFromString(s string, radix int) *BigInt {
|
||||
isNeg := len(s) > 0 && s[0] == '-'
|
||||
istop := 0
|
||||
if isNeg {
|
||||
istop = 1
|
||||
}
|
||||
|
||||
result := NewBigInt()
|
||||
place := NewBigInt()
|
||||
place.digits[0] = 1
|
||||
|
||||
for i := len(s) - 1; i >= istop; i-- {
|
||||
c := s[i]
|
||||
digit := CharToHex(c)
|
||||
biDigit := BiMultiplyDigit(place, digit)
|
||||
result = BiAdd(result, biDigit)
|
||||
place = BiMultiplyDigit(place, radix)
|
||||
}
|
||||
|
||||
result.isNeg = isNeg
|
||||
return result
|
||||
}
|
||||
|
||||
// BiAdd adds two BigInts
|
||||
func BiAdd(x, y *BigInt) *BigInt {
|
||||
var result *BigInt
|
||||
|
||||
if x.isNeg != y.isNeg {
|
||||
y.isNeg = !y.isNeg
|
||||
result = BiSubtract(x, y)
|
||||
y.isNeg = !y.isNeg
|
||||
} else {
|
||||
result = NewBigInt()
|
||||
c := 0
|
||||
for i := 0; i < len(x.digits); i++ {
|
||||
n := x.digits[i] + y.digits[i] + c
|
||||
result.digits[i] = n % biRadix
|
||||
if n >= biRadix {
|
||||
c = 1
|
||||
} else {
|
||||
c = 0
|
||||
}
|
||||
}
|
||||
result.isNeg = x.isNeg
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// BiSubtract subtracts two BigInts
|
||||
func BiSubtract(x, y *BigInt) *BigInt {
|
||||
var result *BigInt
|
||||
|
||||
if x.isNeg != y.isNeg {
|
||||
y.isNeg = !y.isNeg
|
||||
result = BiAdd(x, y)
|
||||
y.isNeg = !y.isNeg
|
||||
} else {
|
||||
result = NewBigInt()
|
||||
c := 0
|
||||
|
||||
for i := 0; i < len(x.digits); i++ {
|
||||
n := x.digits[i] - y.digits[i] + c
|
||||
result.digits[i] = n % biRadix
|
||||
if result.digits[i] < 0 {
|
||||
result.digits[i] += biRadix
|
||||
}
|
||||
if n < 0 {
|
||||
c = -1
|
||||
} else {
|
||||
c = 0
|
||||
}
|
||||
}
|
||||
|
||||
if c == -1 {
|
||||
c = 0
|
||||
for i := 0; i < len(x.digits); i++ {
|
||||
n := 0 - result.digits[i] + c
|
||||
result.digits[i] = n % biRadix
|
||||
if result.digits[i] < 0 {
|
||||
result.digits[i] += biRadix
|
||||
}
|
||||
if n < 0 {
|
||||
c = -1
|
||||
} else {
|
||||
c = 0
|
||||
}
|
||||
}
|
||||
result.isNeg = !x.isNeg
|
||||
} else {
|
||||
result.isNeg = x.isNeg
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// BiHighIndex returns the highest non-zero digit index
|
||||
func BiHighIndex(x *BigInt) int {
|
||||
result := len(x.digits) - 1
|
||||
for result > 0 && x.digits[result] == 0 {
|
||||
result--
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BiNumBits returns the number of bits
|
||||
func BiNumBits(x *BigInt) int {
|
||||
n := BiHighIndex(x)
|
||||
d := x.digits[n]
|
||||
m := (n + 1) * bitsPerDigit
|
||||
result := m
|
||||
for result > m-bitsPerDigit {
|
||||
if (d & 0x8000) != 0 {
|
||||
break
|
||||
}
|
||||
d <<= 1
|
||||
result--
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// BiMultiply multiplies two BigInts
|
||||
func BiMultiply(x, y *BigInt) *BigInt {
|
||||
result := NewBigInt()
|
||||
n := BiHighIndex(x)
|
||||
t := BiHighIndex(y)
|
||||
|
||||
for i := 0; i <= t; i++ {
|
||||
c := 0
|
||||
k := i
|
||||
for j := 0; j <= n; j, k = j+1, k+1 {
|
||||
uv := result.digits[k] + x.digits[j]*y.digits[i] + c
|
||||
result.digits[k] = uv & maxDigitVal
|
||||
c = uv >> biRadixBits
|
||||
}
|
||||
result.digits[i+n+1] = c
|
||||
}
|
||||
|
||||
result.isNeg = x.isNeg != y.isNeg
|
||||
return result
|
||||
}
|
||||
|
||||
// BiMultiplyDigit multiplies BigInt by a digit
|
||||
func BiMultiplyDigit(x *BigInt, y int) *BigInt {
|
||||
result := NewBigInt()
|
||||
n := BiHighIndex(x)
|
||||
c := 0
|
||||
|
||||
for j := 0; j <= n; j++ {
|
||||
uv := result.digits[j] + x.digits[j]*y + c
|
||||
result.digits[j] = uv & maxDigitVal
|
||||
c = uv >> biRadixBits
|
||||
}
|
||||
result.digits[1+n] = c
|
||||
return result
|
||||
}
|
||||
|
||||
// ArrayCopy copies array elements
|
||||
func ArrayCopy(src []int, srcStart int, dest []int, destStart int, n int) {
|
||||
m := min(srcStart+n, len(src))
|
||||
for i, j := srcStart, destStart; i < m; i, j = i+1, j+1 {
|
||||
dest[j] = src[i]
|
||||
}
|
||||
}
|
||||
|
||||
// BiShiftLeft shifts BigInt left by n bits
|
||||
func BiShiftLeft(x *BigInt, n int) *BigInt {
|
||||
digitCount := n / bitsPerDigit
|
||||
result := NewBigInt()
|
||||
ArrayCopy(x.digits, 0, result.digits, digitCount, len(result.digits)-digitCount)
|
||||
|
||||
bits := n % bitsPerDigit
|
||||
rightBits := bitsPerDigit - bits
|
||||
|
||||
for i, i1 := len(result.digits)-1, len(result.digits)-2; i > 0; i, i1 = i-1, i1-1 {
|
||||
result.digits[i] = ((result.digits[i] << bits) & maxDigitVal) |
|
||||
((result.digits[i1] & highBitMasks[bits]) >> rightBits)
|
||||
}
|
||||
result.digits[0] = ((result.digits[0] << bits) & maxDigitVal)
|
||||
result.isNeg = x.isNeg
|
||||
return result
|
||||
}
|
||||
|
||||
// BiShiftRight shifts BigInt right by n bits
|
||||
func BiShiftRight(x *BigInt, n int) *BigInt {
|
||||
digitCount := n / bitsPerDigit
|
||||
result := NewBigInt()
|
||||
ArrayCopy(x.digits, digitCount, result.digits, 0, len(x.digits)-digitCount)
|
||||
|
||||
bits := n % bitsPerDigit
|
||||
leftBits := bitsPerDigit - bits
|
||||
|
||||
for i, i1 := 0, 1; i < len(result.digits)-1; i, i1 = i+1, i1+1 {
|
||||
result.digits[i] = (result.digits[i] >> bits) |
|
||||
((result.digits[i1] & lowBitMasks[bits]) << leftBits)
|
||||
}
|
||||
result.digits[len(result.digits)-1] >>= bits
|
||||
result.isNeg = x.isNeg
|
||||
return result
|
||||
}
|
||||
|
||||
// BiMultiplyByRadixPower multiplies BigInt by radix^n
|
||||
func BiMultiplyByRadixPower(x *BigInt, n int) *BigInt {
|
||||
result := NewBigInt()
|
||||
ArrayCopy(x.digits, 0, result.digits, n, len(result.digits)-n)
|
||||
return result
|
||||
}
|
||||
|
||||
// BiDivideByRadixPower divides BigInt by radix^n
|
||||
func BiDivideByRadixPower(x *BigInt, n int) *BigInt {
|
||||
result := NewBigInt()
|
||||
ArrayCopy(x.digits, n, result.digits, 0, len(result.digits)-n)
|
||||
return result
|
||||
}
|
||||
|
||||
// BiModuloByRadixPower computes BigInt mod radix^n
|
||||
func BiModuloByRadixPower(x *BigInt, n int) *BigInt {
|
||||
result := NewBigInt()
|
||||
ArrayCopy(x.digits, 0, result.digits, 0, n)
|
||||
return result
|
||||
}
|
||||
|
||||
// BiCompare compares two BigInts
|
||||
func BiCompare(x, y *BigInt) int {
|
||||
if x.isNeg != y.isNeg {
|
||||
if x.isNeg {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
for i := len(x.digits) - 1; i >= 0; i-- {
|
||||
if x.digits[i] != y.digits[i] {
|
||||
if x.isNeg {
|
||||
if x.digits[i] > y.digits[i] {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
} else {
|
||||
if x.digits[i] < y.digits[i] {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// BiDivideModulo divides two BigInts and returns quotient and remainder
|
||||
func BiDivideModulo(x, y *BigInt) []*BigInt {
|
||||
nb := BiNumBits(x)
|
||||
tb := BiNumBits(y)
|
||||
origYIsNeg := y.isNeg
|
||||
var q, r *BigInt
|
||||
|
||||
if nb < tb {
|
||||
if x.isNeg {
|
||||
q = BiCopy(bigOne)
|
||||
q.isNeg = !y.isNeg
|
||||
x.isNeg = false
|
||||
y.isNeg = false
|
||||
r = BiSubtract(y, x)
|
||||
x.isNeg = true
|
||||
y.isNeg = origYIsNeg
|
||||
} else {
|
||||
q = NewBigInt()
|
||||
r = BiCopy(x)
|
||||
}
|
||||
return []*BigInt{q, r}
|
||||
}
|
||||
|
||||
q = NewBigInt()
|
||||
r = x
|
||||
|
||||
t := int(math.Ceil(float64(tb)/float64(bitsPerDigit))) - 1
|
||||
lambda := 0
|
||||
for y.digits[t] < biHalfRadix {
|
||||
y = BiShiftLeft(y, 1)
|
||||
lambda++
|
||||
tb++
|
||||
t = int(math.Ceil(float64(tb)/float64(bitsPerDigit))) - 1
|
||||
}
|
||||
|
||||
r = BiShiftLeft(r, lambda)
|
||||
nb += lambda
|
||||
n := int(math.Ceil(float64(nb)/float64(bitsPerDigit))) - 1
|
||||
|
||||
b := BiMultiplyByRadixPower(y, n-t)
|
||||
for BiCompare(r, b) != -1 {
|
||||
q.digits[n-t]++
|
||||
r = BiSubtract(r, b)
|
||||
}
|
||||
|
||||
for i := n; i > t; i-- {
|
||||
ri := 0
|
||||
if i < len(r.digits) {
|
||||
ri = r.digits[i]
|
||||
}
|
||||
ri1 := 0
|
||||
if i-1 < len(r.digits) {
|
||||
ri1 = r.digits[i-1]
|
||||
}
|
||||
ri2 := 0
|
||||
if i-2 < len(r.digits) {
|
||||
ri2 = r.digits[i-2]
|
||||
}
|
||||
yt := 0
|
||||
if t < len(y.digits) {
|
||||
yt = y.digits[t]
|
||||
}
|
||||
yt1 := 0
|
||||
if t-1 < len(y.digits) {
|
||||
yt1 = y.digits[t-1]
|
||||
}
|
||||
|
||||
if ri == yt {
|
||||
q.digits[i-t-1] = maxDigitVal
|
||||
} else {
|
||||
q.digits[i-t-1] = (ri*biRadix + ri1) / yt
|
||||
}
|
||||
|
||||
c1 := q.digits[i-t-1] * ((yt * biRadix) + yt1)
|
||||
c2 := (ri * biRadixSquared) + ((ri1 * biRadix) + ri2)
|
||||
|
||||
for c1 > c2 {
|
||||
q.digits[i-t-1]--
|
||||
c1 = q.digits[i-t-1] * ((yt * biRadix) | yt1)
|
||||
c2 = (ri * biRadix * biRadix) + ((ri1 * biRadix) + ri2)
|
||||
}
|
||||
|
||||
b = BiMultiplyByRadixPower(y, i-t-1)
|
||||
r = BiSubtract(r, BiMultiplyDigit(b, q.digits[i-t-1]))
|
||||
if r.isNeg {
|
||||
r = BiAdd(r, b)
|
||||
q.digits[i-t-1]--
|
||||
}
|
||||
}
|
||||
|
||||
r = BiShiftRight(r, lambda)
|
||||
q.isNeg = x.isNeg != origYIsNeg
|
||||
|
||||
if x.isNeg {
|
||||
if origYIsNeg {
|
||||
q = BiAdd(q, bigOne)
|
||||
} else {
|
||||
q = BiSubtract(q, bigOne)
|
||||
}
|
||||
y = BiShiftRight(y, lambda)
|
||||
r = BiSubtract(y, r)
|
||||
}
|
||||
|
||||
if r.digits[0] == 0 && BiHighIndex(r) == 0 {
|
||||
r.isNeg = false
|
||||
}
|
||||
|
||||
return []*BigInt{q, r}
|
||||
}
|
||||
|
||||
// BiDivide divides two BigInts
|
||||
func BiDivide(x, y *BigInt) *BigInt {
|
||||
return BiDivideModulo(x, y)[0]
|
||||
}
|
||||
|
||||
// BiModulo computes x mod y
|
||||
func BiModulo(x, y *BigInt) *BigInt {
|
||||
return BiDivideModulo(x, y)[1]
|
||||
}
|
||||
|
||||
// BiMultiplyMod computes (x * y) mod m
|
||||
func BiMultiplyMod(x, y, m *BigInt) *BigInt {
|
||||
return BiModulo(BiMultiply(x, y), m)
|
||||
}
|
||||
|
||||
// BiPowMod computes x^y mod m
|
||||
func BiPowMod(x, y, m *BigInt) *BigInt {
|
||||
result := BiCopy(bigOne)
|
||||
a := x
|
||||
k := y
|
||||
|
||||
for {
|
||||
if (k.digits[0] & 1) != 0 {
|
||||
result = BiMultiplyMod(result, a, m)
|
||||
}
|
||||
k = BiShiftRight(k, 1)
|
||||
if k.digits[0] == 0 && BiHighIndex(k) == 0 {
|
||||
break
|
||||
}
|
||||
a = BiMultiplyMod(a, a, m)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// BarrettMu represents Barrett reduction
|
||||
type BarrettMu struct {
|
||||
modulus *BigInt
|
||||
k int
|
||||
mu *BigInt
|
||||
bkplus1 *BigInt
|
||||
}
|
||||
|
||||
// NewBarrettMu creates a new BarrettMu
|
||||
func NewBarrettMu(m *BigInt) *BarrettMu {
|
||||
bm := &BarrettMu{
|
||||
modulus: BiCopy(m),
|
||||
k: BiHighIndex(m) + 1,
|
||||
}
|
||||
|
||||
b2k := NewBigInt()
|
||||
if 2*bm.k < len(b2k.digits) {
|
||||
b2k.digits[2*bm.k] = 1
|
||||
}
|
||||
bm.mu = BiDivide(b2k, bm.modulus)
|
||||
|
||||
bm.bkplus1 = NewBigInt()
|
||||
if bm.k+1 < len(bm.bkplus1.digits) {
|
||||
bm.bkplus1.digits[bm.k+1] = 1
|
||||
}
|
||||
|
||||
return bm
|
||||
}
|
||||
|
||||
// Modulo performs Barrett modulo
|
||||
func (bm *BarrettMu) Modulo(x *BigInt) *BigInt {
|
||||
q1 := BiDivideByRadixPower(x, bm.k-1)
|
||||
q2 := BiMultiply(q1, bm.mu)
|
||||
q3 := BiDivideByRadixPower(q2, bm.k+1)
|
||||
r1 := BiModuloByRadixPower(x, bm.k+1)
|
||||
r2term := BiMultiply(q3, bm.modulus)
|
||||
r2 := BiModuloByRadixPower(r2term, bm.k+1)
|
||||
r := BiSubtract(r1, r2)
|
||||
|
||||
if r.isNeg {
|
||||
r = BiAdd(r, bm.bkplus1)
|
||||
}
|
||||
|
||||
for BiCompare(r, bm.modulus) >= 0 {
|
||||
r = BiSubtract(r, bm.modulus)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// MultiplyMod performs modular multiplication
|
||||
func (bm *BarrettMu) MultiplyMod(x, y *BigInt) *BigInt {
|
||||
xy := BiMultiply(x, y)
|
||||
return bm.Modulo(xy)
|
||||
}
|
||||
|
||||
// PowMod performs modular exponentiation
|
||||
func (bm *BarrettMu) PowMod(x, y *BigInt) *BigInt {
|
||||
result := NewBigInt()
|
||||
result.digits[0] = 1
|
||||
a := x
|
||||
k := y
|
||||
|
||||
for {
|
||||
if (k.digits[0] & 1) != 0 {
|
||||
result = bm.MultiplyMod(result, a)
|
||||
}
|
||||
k = BiShiftRight(k, 1)
|
||||
if k.digits[0] == 0 && BiHighIndex(k) == 0 {
|
||||
break
|
||||
}
|
||||
a = bm.MultiplyMod(a, a)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// NutRSAKeyPair represents an RSA key pair
|
||||
type NutRSAKeyPair struct {
|
||||
e *BigInt
|
||||
d *BigInt
|
||||
m *BigInt
|
||||
chunkSize int
|
||||
radix int
|
||||
barrett *BarrettMu
|
||||
}
|
||||
|
||||
// NewNutRSAKeyPair creates a new RSA key pair
|
||||
func NewNutRSAKeyPair(encryptionExponent, decryptionExponent, modulus string) *NutRSAKeyPair {
|
||||
kp := &NutRSAKeyPair{
|
||||
e: BiFromHex(encryptionExponent),
|
||||
d: BiFromHex(decryptionExponent),
|
||||
m: BiFromHex(modulus),
|
||||
radix: 16,
|
||||
}
|
||||
kp.chunkSize = 2 * BiHighIndex(kp.m)
|
||||
kp.barrett = NewBarrettMu(kp.m)
|
||||
return kp
|
||||
}
|
||||
|
||||
// EncryptedString encrypts a string
|
||||
func (kp *NutRSAKeyPair) EncryptedString(s string) string {
|
||||
a := make([]int, 0)
|
||||
for i := 0; i < len(s); i++ {
|
||||
a = append(a, int(s[i]))
|
||||
}
|
||||
|
||||
// Padding
|
||||
for len(a)%kp.chunkSize != 0 {
|
||||
a = append(a, 0)
|
||||
}
|
||||
|
||||
result := ""
|
||||
for i := 0; i < len(a); i += kp.chunkSize {
|
||||
block := NewBigInt()
|
||||
j := 0
|
||||
for k := i; k < i+kp.chunkSize; j++ {
|
||||
if k < len(a) {
|
||||
block.digits[j] = a[k]
|
||||
k++
|
||||
}
|
||||
if k < len(a) {
|
||||
block.digits[j] += a[k] << 8
|
||||
k++
|
||||
}
|
||||
}
|
||||
crypt := kp.barrett.PowMod(block, kp.e)
|
||||
var text string
|
||||
if kp.radix == 16 {
|
||||
text = BiToHex(crypt)
|
||||
} else {
|
||||
text = BiToString(crypt, kp.radix)
|
||||
}
|
||||
result += text + " "
|
||||
}
|
||||
|
||||
if len(result) > 0 {
|
||||
return result[:len(result)-1]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// DecryptedString decrypts a string
|
||||
func (kp *NutRSAKeyPair) DecryptedString(s string) string {
|
||||
blocks := strings.Split(s, " ")
|
||||
result := ""
|
||||
|
||||
for i := 0; i < len(blocks); i++ {
|
||||
var bi *BigInt
|
||||
if kp.radix == 16 {
|
||||
bi = BiFromHex(blocks[i])
|
||||
} else {
|
||||
bi = BiFromString(blocks[i], kp.radix)
|
||||
}
|
||||
block := kp.barrett.PowMod(bi, kp.d)
|
||||
|
||||
for j := 0; j <= BiHighIndex(block); j++ {
|
||||
result += string(rune(block.digits[j] & 255))
|
||||
result += string(rune(block.digits[j] >> 8))
|
||||
}
|
||||
}
|
||||
|
||||
// Remove trailing null
|
||||
if len(result) > 0 && result[len(result)-1] == 0 {
|
||||
result = result[:len(result)-1]
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func parseNumber(s string) int64 {
|
||||
var result int64
|
||||
fmt.Sscanf(s, "%d", &result)
|
||||
return result
|
||||
}
|
||||
|
||||
func init() {
|
||||
SetMaxDigits(130)
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package leave
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"likedream-goframe/internal/application/cpdaily"
|
||||
"likedream-goframe/internal/application/cpdaily/cryptoutil"
|
||||
"likedream-goframe/internal/application/cpdaily/task/leavetype"
|
||||
"likedream-goframe/internal/application/cpdaily/taskhelper"
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/utils"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gvar"
|
||||
"github.com/google/uuid"
|
||||
"github.com/samber/oops"
|
||||
"github.com/tidwall/gjson"
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
/**
|
||||
* @Description: 销假相关功能
|
||||
*/
|
||||
type CpdailyReportApp struct {
|
||||
client *resty.Client
|
||||
host string
|
||||
}
|
||||
|
||||
func NewCpdailyReportApp(client *resty.Client, host string) *CpdailyReportApp {
|
||||
|
||||
return &CpdailyReportApp{
|
||||
client: client,
|
||||
host: host,
|
||||
}
|
||||
}
|
||||
|
||||
// 获取请假记录
|
||||
func (c *CpdailyReportApp) GetLeaveList() []leavetype.LeaveListOne {
|
||||
// https://fzfu.campusphere.net/wec-counselor-leave-apps/leave/stu/listOther
|
||||
post, err := c.client.R().SetBody(map[string]int{
|
||||
"pageNumber": 1,
|
||||
"pageSize": 20,
|
||||
"needApproval": 1,
|
||||
}).Post(fmt.Sprintf("%s/wec-counselor-leave-apps/leave/stu/listOther", c.host))
|
||||
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
With("host", c.host).
|
||||
In("CpdailyReport.GetLeaveList").
|
||||
Wrap(err)
|
||||
})
|
||||
responseJSON := utils.ReadGjsonResult(post.Body)
|
||||
rows := responseJSON.Get("datas.rows")
|
||||
|
||||
if !rows.Exists() {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, "没有获取到待销假信息"), func(err error) error {
|
||||
return oops.
|
||||
With("host", c.host).
|
||||
In("CpdailyReport.GetLeaveList").
|
||||
Wrap(err)
|
||||
})
|
||||
}
|
||||
|
||||
var listList []leavetype.LeaveListOne
|
||||
for _, row := range rows.Array() {
|
||||
// 已完成
|
||||
if row.Get("status").String() == "4" {
|
||||
continue
|
||||
}
|
||||
leaveOne := leavetype.LeaveListOne{
|
||||
Id: row.Get("id").String(),
|
||||
LeaveType: row.Get("leaveType").String(),
|
||||
CreateTime: row.Get("createTime").String(),
|
||||
Reason: row.Get("leaveReason").String(),
|
||||
AceEndTime: row.Get("actEndTime").String(),
|
||||
Status: row.Get("status").String(),
|
||||
}
|
||||
listList = append(listList, leaveOne)
|
||||
}
|
||||
return listList
|
||||
}
|
||||
|
||||
func (c *CpdailyReportApp) LeaveDetail(leaveId string) gjson.Result {
|
||||
// https://fzfu.campusphere.net/wec-counselor-leave-apps/leave/stu/detailOther
|
||||
post, err := c.client.R().SetBody(map[string]any{
|
||||
"id": leaveId,
|
||||
"needApproval": 1,
|
||||
"uaIsCpadaily": "true",
|
||||
}).Post(fmt.Sprintf("%s/wec-counselor-leave-apps/leave/stu/detailOther", c.host))
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
With("host", c.host).
|
||||
In("CpdailyReport.LeaveDetail").
|
||||
Wrap(err)
|
||||
})
|
||||
datas := utils.ReadGjsonResult(post.Body).Get("datas")
|
||||
if !datas.Exists() {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, "没有获取到待销假详情信息"), func(err error) error {
|
||||
return oops.
|
||||
With("host", c.host).
|
||||
In("CpdailyReport.LeaveDetail").
|
||||
Wrap(err)
|
||||
})
|
||||
}
|
||||
return datas
|
||||
}
|
||||
|
||||
func (c *CpdailyReportApp) FillReportForm(detail gjson.Result) map[string]*gvar.Var {
|
||||
resultForm := make(map[string]*gvar.Var)
|
||||
resultForm["id"] = gvar.New(detail.Get("detail.id").String())
|
||||
resultForm["needApproval"] = gvar.New(1)
|
||||
resultForm["leaveType"] = gvar.New(detail.Get("leaveType.code").String())
|
||||
resultForm["reportLocation"] = gvar.New(detail.Get("detail.applyLocation.address").String())
|
||||
resultForm["approverWid"] = gvar.New("")
|
||||
resultForm["reportApplyExplain"] = gvar.New(nil)
|
||||
//resultForm["reportAttach"] = gvar.New(detail.Get("detail.applyAttach").Array())
|
||||
resultForm["reportAttach"] = gvar.New([]string{})
|
||||
resultForm["uaIsCpadaily"] = gvar.New(true)
|
||||
return resultForm
|
||||
}
|
||||
|
||||
func (c *CpdailyReportApp) GetLocation(detail gjson.Result) (lon, lat string) {
|
||||
applyLocation := detail.Get("detail.applyLocation")
|
||||
lon = applyLocation.Get("longitude").String()
|
||||
lat = applyLocation.Get("latitude").String()
|
||||
return
|
||||
}
|
||||
func (c *CpdailyReportApp) SubmitReport(ctx context.Context, form map[string]*gvar.Var, lon, lat, username, deviceId string) {
|
||||
cpdailyInfo := cpdaily.GetInfo(ctx)
|
||||
|
||||
extensionForm := map[string]*gvar.Var{
|
||||
"lon": gvar.New(lon),
|
||||
"lat": gvar.New(lat),
|
||||
"model": gvar.New(uuid.New().String()),
|
||||
"appVersion": gvar.New(cpdailyInfo.AppVersion),
|
||||
"systemVersion": gvar.New(cpdailyInfo.SystemVersion),
|
||||
"userId": gvar.New(username),
|
||||
"systemName": gvar.New("android"),
|
||||
"deviceId": gvar.New(deviceId),
|
||||
}
|
||||
|
||||
extensionString := taskhelper.GetCpdailyExtension(ctx, extensionForm)
|
||||
bodyString := taskhelper.GetBodyString(ctx, form)
|
||||
// 构造提交数据
|
||||
submitData := map[string]*gvar.Var{
|
||||
"lon": gvar.New(lon),
|
||||
"version": gvar.New(cryptoutil.EncryptVersion),
|
||||
"calVersion": gvar.New(cpdailyInfo.CalVersion),
|
||||
"deviceId": extensionForm["deviceId"],
|
||||
"userId": gvar.New(username),
|
||||
"systemName": gvar.New("android"),
|
||||
"bodyString": gvar.New(bodyString),
|
||||
"lat": gvar.New(lat),
|
||||
"systemVersion": gvar.New(cpdailyInfo.SystemVersion),
|
||||
"appVersion": gvar.New(cpdailyInfo.AppVersion),
|
||||
"model": extensionForm["model"],
|
||||
}
|
||||
// https://fzfu.campusphere.net/wec-counselor-leave-apps/leave/report
|
||||
response, e := c.client.R().
|
||||
SetBody(submitData).
|
||||
WithContext(ctx).
|
||||
SetHeader("Cpdaily-Extension", extensionString).
|
||||
Post(fmt.Sprintf("%s/wec-counselor-leave-apps/leave/report", c.host))
|
||||
|
||||
utils.OkOrPanic(e, func(err error) error {
|
||||
return oops.
|
||||
With("host", c.host).
|
||||
With("username", username).
|
||||
With("deviceId", deviceId).
|
||||
In("CpdailySleepCheckTask.Submit").
|
||||
Wrap(err)
|
||||
})
|
||||
|
||||
responseJSON := utils.ReadGjsonResult(response.Body)
|
||||
|
||||
if responseJSON.Get("code").String() != "0" {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, responseJSON.Get("message").String()), oops.WithContext(ctx).Wrap)
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,15 @@ func GetCpdailyLoginBySchoolInfo(ctx context.Context, info *school.SchoolDetailI
|
||||
// 安徽建筑大学
|
||||
case "ahjzu":
|
||||
return NewAhjzu(ctx)
|
||||
// 南宁师范大学
|
||||
case "2ba0ea59-a764-4482-bb2b-c924b726b04c":
|
||||
return NewNnnu(ctx)
|
||||
// 长春大学
|
||||
case "ccu":
|
||||
fallthrough
|
||||
// 河北石油职业技术大学
|
||||
case "01e270d1-00e2-4ce9-b0af-5d5fbd462b8a":
|
||||
return NewIap(ctx)
|
||||
default:
|
||||
if info.IsIap() {
|
||||
return NewIap(ctx)
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/avast/retry-go/v4"
|
||||
"github.com/deatil/go-cryptobin/cryptobin/crypto"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/samber/oops"
|
||||
"github.com/tidwall/gjson"
|
||||
"resty.dev/v3"
|
||||
@@ -192,7 +193,8 @@ func (c *CpdailyCasLogin) Login(ctx context.Context, schoolDetail *school.School
|
||||
}
|
||||
|
||||
// 声明需要滑块验证码的学校id
|
||||
var SliderCaptchaIds = []string{"1018764144934965", "sdhyxy"}
|
||||
var SliderCaptchaIds = g.Cfg().MustGet(ctx, cst.ConfigSliderSchoolIds).Strings()
|
||||
// []string{"1018764144934965", "sdhyxy", "hqdx"}
|
||||
// 判断是否需要验证码
|
||||
if isCasNeedCaptcha(ctx, loginResponseUrl, loginType, username, c.client) {
|
||||
// 如果是滑块验证码
|
||||
@@ -389,6 +391,10 @@ func handleCasLoginSuccess(ctx context.Context, response *resty.Response, school
|
||||
utils.OkOrPanic(errors.NewBusinessError(201, "多因子验证码认证").WithData(key))
|
||||
// 否则应该是登录成功
|
||||
} else if statusCode == 200 || statusCode == 404 {
|
||||
all, _ := io.ReadAll(verifyResponse.Body)
|
||||
if strings.Contains(string(all), "完善资料") || strings.Contains(string(all), "为了你的帐号安全") {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, "请手动学工号登录完善信息,修改密码").WithData(schoolInfo.WecloudUrl))
|
||||
}
|
||||
ActivateSession(ctx, schoolInfo.WecloudUrl, client)
|
||||
} else {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, "未知错误导致今日校园登录失败"),
|
||||
@@ -450,6 +456,12 @@ func submitCasKickOut(ctx context.Context, requestUrl string, doc *goquery.Docum
|
||||
}
|
||||
|
||||
func getCasValidLoginUrl(info *school.SchoolDetailInfo) string {
|
||||
// 特殊学校单独处理
|
||||
// 甘肃农业大学 西安体育学院
|
||||
ids := []string{"gsau", "ddf0639d-394d-48a2-a166-07ed84b7e6f0"}
|
||||
if slices.Contains(ids, info.Id) {
|
||||
return info.IdsUrl
|
||||
}
|
||||
if strings.Contains(info.AmpUrl, "campusphere") || strings.Contains(info.AmpUrl, "wec-portal-mobile") {
|
||||
return info.AmpUrl
|
||||
} else if strings.Contains(info.AmpUrl2, "campusphere") || strings.Contains(info.AmpUrl2, "wec-portal-mobile") {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"likedream-goframe/internal/application/cookiejar"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/ent/cpuser"
|
||||
"likedream-goframe/internal/utils"
|
||||
"strings"
|
||||
|
||||
@@ -14,6 +15,11 @@ import (
|
||||
)
|
||||
|
||||
func ActivateSession(ctx context.Context, host string, client *resty.Client) {
|
||||
// 处理cookie,干掉path
|
||||
jar := client.CookieJar()
|
||||
realJar := jar.(*cookiejar.PersistCookieJar)
|
||||
realJar.RemoveCookieInfo()
|
||||
client.SetCookieJar(realJar)
|
||||
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20))
|
||||
|
||||
host = strings.TrimSuffix(host, "/")
|
||||
@@ -27,7 +33,7 @@ func ActivateSession(ctx context.Context, host string, client *resty.Client) {
|
||||
|
||||
defer sessionResponse.Body.Close()
|
||||
|
||||
if !sessionResponse.IsSuccess() {
|
||||
if !sessionResponse.IsSuccess() && sessionResponse.StatusCode() != 502 {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, "Session激活失败"),
|
||||
func(err error) error {
|
||||
return oops.
|
||||
@@ -81,11 +87,8 @@ func ActivateSession(ctx context.Context, host string, client *resty.Client) {
|
||||
client.SetRedirectPolicy(resty.NoRedirectPolicy())
|
||||
}
|
||||
|
||||
func CookieEnabled(ctx context.Context, host string, client *resty.Client) bool {
|
||||
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20))
|
||||
defer func() {
|
||||
client.SetRedirectPolicy(resty.NoRedirectPolicy())
|
||||
}()
|
||||
func CookieEnabled(ctx context.Context, host string, client *resty.Client, loginType cpuser.LoginType) bool {
|
||||
client.SetRedirectPolicy(resty.NoRedirectPolicy())
|
||||
host = strings.TrimSuffix(host, "/")
|
||||
sessionResponse, err := client.R().
|
||||
WithContext(ctx).
|
||||
@@ -93,13 +96,11 @@ func CookieEnabled(ctx context.Context, host string, client *resty.Client) bool
|
||||
Post(fmt.Sprintf("%s/wec-counselor-attendance-apps/student/attendance/getStuAttendacesInOneDay", host))
|
||||
|
||||
utils.OkOrPanic(err)
|
||||
defer sessionResponse.Body.Close()
|
||||
|
||||
if !sessionResponse.IsSuccess() {
|
||||
return sessionResponse.StatusCode() == 405
|
||||
needLogin := sessionResponse.StatusCode() == 302
|
||||
if needLogin && loginType == cpuser.LoginTypePhone {
|
||||
utils.OkOrPanic(errors.NewBusinessError(500, "登录信息失效,请重新通过短信验证码登录"))
|
||||
}
|
||||
responseContentType := sessionResponse.Header().Get("Content-Type")
|
||||
return strings.Contains(responseContentType, "json")
|
||||
return !needLogin
|
||||
}
|
||||
|
||||
func GetClient(ctx context.Context, cookie string) *resty.Client {
|
||||
|
||||
@@ -45,16 +45,17 @@ func (c *CpdailyIapLogin) Login(ctx context.Context, schoolDetail *school.School
|
||||
preLoginUrl := loginUrl + "/portal/login"
|
||||
c.client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20))
|
||||
loginRedirectResponse, err := c.client.R().Get(preLoginUrl)
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
In("CpdailyIapLogin.Login").
|
||||
With("schoolDetail", schoolDetail).
|
||||
With("username", username).
|
||||
With("password", password).
|
||||
Wrap(err)
|
||||
})
|
||||
u := loginRedirectResponse.RawResponse.Request.URL
|
||||
oldLt := strings.Split(u.String(), "=")[1]
|
||||
oldLt := ""
|
||||
// 部分学校无法直接访问登录页
|
||||
if err == nil {
|
||||
u := loginRedirectResponse.RawResponse.Request.URL
|
||||
oldLt = strings.Split(u.String(), "=")[1]
|
||||
c.client.SetRedirectPolicy(resty.NoRedirectPolicy())
|
||||
} else {
|
||||
preLoginUrl = loginUrl + "/iap/login/mobile.html"
|
||||
c.client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20))
|
||||
loginRedirectResponse, err = c.client.R().Get(preLoginUrl)
|
||||
}
|
||||
c.client.SetRedirectPolicy(resty.NoRedirectPolicy())
|
||||
ltInfoResponse, err := c.client.R().
|
||||
WithContext(ctx).
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"likedream-goframe/internal/application/cookiejar"
|
||||
"likedream-goframe/internal/application/cpdaily/cryptoutil"
|
||||
"likedream-goframe/internal/application/cpdaily/school"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/utils"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/samber/oops"
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
// 南宁师范大学登录实现
|
||||
type CpdailyNnnuLogin struct {
|
||||
client *resty.Client
|
||||
}
|
||||
|
||||
func (c CpdailyNnnuLogin) Login(ctx context.Context, schoolDetail *school.SchoolDetailInfo, username, password string) {
|
||||
jar := cookiejar.NewPersistCookieJar()
|
||||
|
||||
c.client.SetCookieJar(jar).SetRedirectPolicy(resty.FlexibleRedirectPolicy(20))
|
||||
|
||||
// 获取合法的登录URL
|
||||
loginUrl := getCasValidLoginUrl(schoolDetail)
|
||||
|
||||
// 请求登录页面并获取真正的登录URL
|
||||
loginPageResponse, err := c.client.R().
|
||||
WithContext(ctx).
|
||||
Get(loginUrl)
|
||||
|
||||
defer loginPageResponse.Body.Close()
|
||||
loginPageBytes, err := io.ReadAll(loginPageResponse.Body)
|
||||
utils.OkOrPanic(err)
|
||||
loginResponseUrl := loginPageResponse.RawResponse.Request.URL
|
||||
// 关闭client的重定向
|
||||
c.client.SetRedirectPolicy(resty.NoRedirectPolicy())
|
||||
// 解析登录页面
|
||||
loginPage, err := goquery.NewDocumentFromReader(bytes.NewReader(loginPageBytes))
|
||||
utils.OkOrPanic(err)
|
||||
// 判断登录类型
|
||||
var (
|
||||
allInputs = map[string]string{}
|
||||
form = loginPage.Find("form").First()
|
||||
)
|
||||
inputs := form.Find("input")
|
||||
|
||||
for _, input := range inputs.EachIter() {
|
||||
name, exists := input.Attr("name")
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
value, _ := input.Attr("value")
|
||||
allInputs[name] = value
|
||||
}
|
||||
|
||||
allInputs["username"] = username
|
||||
|
||||
// 处理密码
|
||||
allInputs["password"] = cryptoutil.MD5(password)
|
||||
|
||||
// 解决常规图片验证码
|
||||
captchaUrl := getAhjzuCaptchaUrl(loginResponseUrl)
|
||||
captchaResult := ResolveOcrCaptcha(ctx, captchaUrl, c.client)
|
||||
|
||||
allInputs["validateCode"] = captchaResult
|
||||
|
||||
// 登录提交
|
||||
loginPostResponse, err := c.client.R().
|
||||
SetFormData(allInputs).
|
||||
WithContext(ctx).
|
||||
Post(loginResponseUrl.String())
|
||||
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
WithContext(ctx).
|
||||
With("loginResponseUrl", loginResponseUrl).
|
||||
With("allInputs", allInputs).
|
||||
Wrap(err)
|
||||
})
|
||||
|
||||
defer loginPostResponse.Body.Close()
|
||||
|
||||
switch loginPostResponse.StatusCode() {
|
||||
case 302:
|
||||
handleCasLoginSuccess(ctx, loginPostResponse, schoolDetail, username, password, c.client)
|
||||
case 200:
|
||||
fallthrough
|
||||
case 401:
|
||||
doc, err := goquery.NewDocumentFromReader(loginPostResponse.Body)
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
WithContext(ctx).
|
||||
With("loginResponseUrl", loginResponseUrl).
|
||||
With("allInputs", allInputs).
|
||||
Wrap(err)
|
||||
})
|
||||
|
||||
if isCasNeedKickOut(doc) {
|
||||
kickoutResponse := submitCasKickOut(ctx, loginResponseUrl.String(), doc, c.client)
|
||||
handleCasLoginSuccess(ctx, kickoutResponse, schoolDetail, username, password, c.client)
|
||||
return
|
||||
}
|
||||
|
||||
message := getCasErrorMessage(doc)
|
||||
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, fmt.Sprintf("今日校园登录失败: %s", message)), func(err error) error {
|
||||
return oops.
|
||||
WithContext(ctx).
|
||||
With("loginResponseUrl", loginResponseUrl).
|
||||
With("allInputs", allInputs).
|
||||
With("errorMessage", message).
|
||||
Wrap(errors.NewBusinessError(503, message))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getNuuuCaptchaUrl(url *url.URL) string {
|
||||
return fmt.Sprintf("%s://%s/sso/code/code.jsp", url.Scheme, url.Host)
|
||||
}
|
||||
|
||||
func (c CpdailyNnnuLogin) GetCookieJar() http.CookieJar {
|
||||
return c.client.CookieJar()
|
||||
}
|
||||
|
||||
func (c CpdailyNnnuLogin) GetCookieString() string {
|
||||
cookieJar := c.GetCookieJar()
|
||||
serializableJar := cookieJar.(*cookiejar.PersistCookieJar)
|
||||
return serializableJar.Serialize()
|
||||
}
|
||||
|
||||
func (c CpdailyNnnuLogin) GetClient() *resty.Client {
|
||||
return c.client
|
||||
}
|
||||
|
||||
func NewNnnu(ctx context.Context) CpdailyLogin {
|
||||
return &CpdailyNnnuLogin{
|
||||
client: httpclient.NewCpdailyClient(),
|
||||
}
|
||||
}
|
||||
@@ -81,10 +81,8 @@ func (c CpdailyNutLogin) Login(ctx context.Context, schoolDetail *school.SchoolD
|
||||
pubKeyBytes, err := io.ReadAll(pubKeyResponse.Body)
|
||||
utils.OkOrPanic(err)
|
||||
sonic.Unmarshal(pubKeyBytes, &pubKey)
|
||||
pair, err := cryptoutil.NewRSAKeyPair(pubKey.Exponent, "", pubKey.Modulus)
|
||||
utils.OkOrPanic(err)
|
||||
password, err = pair.Encrypt(reverseStringASCII(password))
|
||||
utils.OkOrPanic(err)
|
||||
rsa := cryptoutil.NewNutRSAKeyPair(pubKey.Exponent, "", pubKey.Modulus)
|
||||
password = rsa.EncryptedString(reverseStringASCII(password))
|
||||
allInputs["password"] = password
|
||||
if isNutNeedCaptcha(ctx, loginResponseUrl, c.client) {
|
||||
// 解决常规图片验证码
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"image"
|
||||
"io"
|
||||
"likedream-goframe/internal/application/recognizer/ddddocr"
|
||||
"likedream-goframe/internal/application/captcha"
|
||||
"likedream-goframe/internal/utils"
|
||||
|
||||
"github.com/samber/oops"
|
||||
@@ -14,15 +12,7 @@ import (
|
||||
|
||||
func ResolveOcrCaptcha(ctx context.Context, url string, client *resty.Client) string {
|
||||
byteData := DownCode2Byte(ctx, url, client)
|
||||
img, err := BytesToImage(byteData)
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
With("BytesToImage", url).
|
||||
WithContext(ctx).
|
||||
Wrap(err)
|
||||
})
|
||||
data := ddddocr.AutoOCRVerification(img)
|
||||
return data
|
||||
return captcha.ApiAutoOCRVerification(byteData)
|
||||
}
|
||||
|
||||
func DownCode2Byte(ctx context.Context, url string, client *resty.Client) []byte {
|
||||
@@ -45,12 +35,3 @@ func DownCode2Byte(ctx context.Context, url string, client *resty.Client) []byte
|
||||
})
|
||||
return all
|
||||
}
|
||||
|
||||
// 通用解码函数,自动检测格式
|
||||
func BytesToImage(imgBytes []byte) (image.Image, error) {
|
||||
img, _, err := image.Decode(bytes.NewReader(imgBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
|
||||
@@ -2,14 +2,17 @@ package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"likedream-goframe/internal/application/recognizer/slider"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/common/cst"
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/utils"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/samber/oops"
|
||||
"github.com/tidwall/gjson"
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
@@ -39,12 +42,13 @@ func ResolveCasSliderCaptcha(ctx context.Context, captchaUrl string, verifyUrl s
|
||||
bytes, _ := io.ReadAll(res.Body)
|
||||
var captcha CasSliderCaptchaReponse
|
||||
sonic.Unmarshal(bytes, &captcha)
|
||||
width := slider.VerifySliderWidthByBase64(captcha.BigImage, captcha.SmallImage)
|
||||
//width := slider.VerifySliderWidthByBase64(captcha.BigImage, captcha.SmallImage)
|
||||
width := ApiVerifySliderWidthByBase64(captcha.BigImage, captcha.SmallImage)
|
||||
res2, err2 := client.R().
|
||||
WithContext(ctx).
|
||||
SetFormData(map[string]string{
|
||||
"canvasLength": "280",
|
||||
"moveLength": fmt.Sprintf("%d", width),
|
||||
"moveLength": width,
|
||||
}).
|
||||
Post(verifyUrl)
|
||||
utils.OkOrPanic(err2, func(err error) error {
|
||||
@@ -65,3 +69,22 @@ func ResolveCasSliderCaptcha(ctx context.Context, captchaUrl string, verifyUrl s
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ApiVerifySliderWidthByBase64(bigImage string, smallImage string) string {
|
||||
ctx := gctx.GetInitCtx()
|
||||
baseUrl := g.Config().MustGetWithEnv(ctx, cst.ConfigCaptchaBaseUrl).String() + "/slider"
|
||||
client := httpclient.Cpdaily.Clone(ctx)
|
||||
client.SetDoNotParseResponse(false)
|
||||
post, err := client.R().SetBody(map[string]any{
|
||||
"big_image": bigImage,
|
||||
"small_image": smallImage,
|
||||
}).Post(baseUrl)
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.
|
||||
With("AutoOCRVerification", baseUrl).
|
||||
WithContext(ctx).
|
||||
Wrap(err)
|
||||
})
|
||||
result := post.String()
|
||||
return gjson.Get(result, "data").String()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"likedream-goframe/internal/application/cookiejar"
|
||||
"likedream-goframe/internal/application/cpdaily/cryptoutil"
|
||||
"likedream-goframe/internal/application/cpdaily/school"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/common/cst"
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/utils"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/samber/oops"
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
type cpdailySmsCommonResponse[T any] struct {
|
||||
ErrCode int `json:"errCode"`
|
||||
ErrMsg string `json:"errMsg"`
|
||||
Data T `json:"data"`
|
||||
}
|
||||
|
||||
func (c *cpdailySmsCommonResponse[T]) EnsureSuccess() {
|
||||
if c.ErrCode != 0 {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, c.ErrMsg))
|
||||
}
|
||||
}
|
||||
|
||||
type CpdailySmsSendSmsData struct {
|
||||
Countdown int `json:"countdown"`
|
||||
TipMsg string `json:"tipMsg"`
|
||||
Status int `json:"status"`
|
||||
CookieJar *cookiejar.PersistCookieJar `json:"-"`
|
||||
}
|
||||
|
||||
type CpdailySmsLoginByCodeData struct {
|
||||
AuthID string `json:"authId"`
|
||||
AuthStatus string `json:"authStatus"`
|
||||
CompleteUserInfoStatus string `json:"completeUserInfoStatus"`
|
||||
DeviceExceptionMsg string `json:"deviceExceptionMsg"`
|
||||
DeviceStatus string `json:"deviceStatus"`
|
||||
FirstLogin bool `json:"firstLogin"`
|
||||
Mobile string `json:"mobile"`
|
||||
MsgTip string `json:"msgTip"`
|
||||
Name string `json:"name"`
|
||||
OpenID string `json:"openId"`
|
||||
PersonID string `json:"personId"`
|
||||
SessionToken string `json:"sessionToken"`
|
||||
Status string `json:"status"`
|
||||
TenantID string `json:"tenantId"`
|
||||
TenantName string `json:"tenantName"`
|
||||
Tgc string `json:"tgc"`
|
||||
TgcStatus string `json:"tgcStatus"`
|
||||
UserID string `json:"userId"`
|
||||
UserType string `json:"userType"`
|
||||
}
|
||||
|
||||
func NewSms(deviceID string) *SmsLoginHandler {
|
||||
return &SmsLoginHandler{
|
||||
deviceID: deviceID,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSmsWithoutDeviceID() *SmsLoginHandler {
|
||||
return &SmsLoginHandler{
|
||||
deviceID: "",
|
||||
}
|
||||
}
|
||||
|
||||
type SmsLoginHandler struct {
|
||||
deviceID string
|
||||
client *resty.Client
|
||||
}
|
||||
|
||||
func (s *SmsLoginHandler) SendSms(ctx context.Context, phone string) *CpdailySmsSendSmsData {
|
||||
jar := cookiejar.NewPersistCookieJar()
|
||||
|
||||
phoneEncrypted := base64.StdEncoding.EncodeToString(cryptoutil.AesEncrypt([]byte(phone)))
|
||||
s.client = httpclient.NewCpdailyClient()
|
||||
req := s.client.
|
||||
SetCookieJar(jar).
|
||||
R().
|
||||
SetContext(utils.NewCpdailySmsContextBuilder().
|
||||
WithDeviceID(s.deviceID).
|
||||
Build(ctx)).
|
||||
SetBody(map[string]string{
|
||||
"a": phoneEncrypted,
|
||||
"b": cryptoutil.EncryptVersion,
|
||||
})
|
||||
|
||||
setSmsRequestHeaders(ctx, req)
|
||||
|
||||
resp, e := req.
|
||||
Post("https://mobile.campushoy.com/app/auth/authentication/mobile/messageCode/v-8222")
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
|
||||
respJson := utils.ReadJson[cpdailySmsCommonResponse[CpdailySmsSendSmsData]](resp.Body)
|
||||
respJson.EnsureSuccess()
|
||||
|
||||
respJson.Data.CookieJar = jar
|
||||
|
||||
return &respJson.Data
|
||||
}
|
||||
|
||||
func (s *SmsLoginHandler) LoginByCode(ctx context.Context, phone, code string, jar http.CookieJar) *CpdailySmsLoginByCodeData {
|
||||
payload := map[string]any{
|
||||
"d": code,
|
||||
"e": "CPDAILY",
|
||||
"c": phone,
|
||||
"f": "86",
|
||||
}
|
||||
|
||||
payloadString, e := sonic.Marshal(payload)
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
|
||||
encryptedPayload := cryptoutil.AesEncrypt(payloadString)
|
||||
encodedPayload := base64.StdEncoding.EncodeToString(encryptedPayload)
|
||||
|
||||
payload = map[string]any{
|
||||
"a": encodedPayload,
|
||||
"b": cryptoutil.EncryptVersion,
|
||||
}
|
||||
s.client = httpclient.NewCpdailyClient()
|
||||
s.client.SetCookieJar(jar)
|
||||
req := s.client.R().
|
||||
SetBody(payload).
|
||||
SetContext(utils.NewCpdailySmsContextBuilder().
|
||||
WithDeviceID(s.deviceID).
|
||||
Build(ctx))
|
||||
setSmsRequestHeaders(ctx, req)
|
||||
|
||||
resp, e := req.
|
||||
Post("https://mobile.campushoy.com/app/auth/authentication/mobileLogin/v-8222")
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
|
||||
respJson := utils.ReadJson[cpdailySmsCommonResponse[string]](resp.Body)
|
||||
respJson.EnsureSuccess()
|
||||
|
||||
data := decodeData[CpdailySmsLoginByCodeData](respJson.Data)
|
||||
|
||||
return &data
|
||||
}
|
||||
|
||||
func (s *SmsLoginHandler) SetLoginCookie(ctx context.Context, jar http.CookieJar, loginData *CpdailySmsLoginByCodeData) {
|
||||
detail := school.GetSchoolDetail(ctx, loginData.TenantID)
|
||||
|
||||
getCookieUrl := fmt.Sprintf("%s%s", detail.WecloudUrl, "/wec-im-group/group/imUserToken/getImUserToken")
|
||||
|
||||
cookieMap := map[string]any{
|
||||
"AMP2": []map[string]any{
|
||||
{
|
||||
"path": "/",
|
||||
"value": loginData.SessionToken,
|
||||
"domain": "",
|
||||
"name": "sessionToken",
|
||||
},
|
||||
},
|
||||
"AMP1": []map[string]any{
|
||||
{
|
||||
"path": "/",
|
||||
"value": loginData.SessionToken,
|
||||
"domain": "",
|
||||
"name": "sessionToken",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ampTokenString, e := sonic.Marshal(cookieMap)
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
|
||||
ampTokenEncrypted := cryptoutil.DesEncrypt(ampTokenString, cryptoutil.Normal)
|
||||
ampToken := base64.StdEncoding.EncodeToString(ampTokenEncrypted)
|
||||
|
||||
// 设置cookie到jar: clientType=cpdaily_student; tenantId=ahnu; standAlone=0; sessionToken=5e55bfa7-d17e-4f5a-a06d-99a649855521;
|
||||
targetSchoolUrl, e := url.Parse(detail.WecloudUrl)
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
targetApiUrl, e := url.Parse("https://api.campushoy.com")
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
|
||||
cookieNameValues := map[string]string{
|
||||
"clientType": "cpdaily_student",
|
||||
"tenantId": detail.Id,
|
||||
"standAlone": "0",
|
||||
"sessionToken": loginData.SessionToken,
|
||||
}
|
||||
|
||||
for name, value := range cookieNameValues {
|
||||
cookie := &http.Cookie{
|
||||
Name: name,
|
||||
Value: value,
|
||||
}
|
||||
|
||||
jar.SetCookies(targetSchoolUrl, []*http.Cookie{cookie})
|
||||
jar.SetCookies(targetApiUrl, []*http.Cookie{cookie})
|
||||
}
|
||||
s.client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(50))
|
||||
req := s.client.R().
|
||||
SetHeader("AmpCookies", ampToken).
|
||||
SetContext(ctx)
|
||||
|
||||
ctx = utils.NewCpdailySmsContextBuilder().
|
||||
WithDeviceID(s.deviceID).
|
||||
WithTenantID(detail.Id).
|
||||
WithSessionToken(loginData.SessionToken).
|
||||
Build(ctx)
|
||||
|
||||
setSmsRequestHeaders(ctx, req)
|
||||
|
||||
resp, e := req.
|
||||
Get(getCookieUrl)
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
|
||||
respJson := utils.ReadJson[cpdailySmsCommonResponse[any]](resp.Body)
|
||||
respJson.EnsureSuccess()
|
||||
}
|
||||
|
||||
func decodeData[T any](encodedData string) T {
|
||||
decodedBytes, e := base64.StdEncoding.DecodeString(encodedData)
|
||||
utils.OkOrPanic(e)
|
||||
|
||||
decryptedBytes := cryptoutil.AesDecrypt(decodedBytes)
|
||||
|
||||
result := utils.ReadJson[T](bytes.NewReader(decryptedBytes))
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func setSmsRequestHeaders(ctx context.Context, request *resty.Request) {
|
||||
sessionToken, ok := ctx.Value(cst.CtxCpdailySessionToken).(string)
|
||||
if ok {
|
||||
encryptedSessionToken := cryptoutil.DesEncrypt([]byte(sessionToken), cryptoutil.Normal)
|
||||
encodedSessionToken := base64.StdEncoding.EncodeToString(encryptedSessionToken)
|
||||
request.SetHeader("SessionToken", encodedSessionToken)
|
||||
request.SetHeader("sessionTokenKey", encodedSessionToken)
|
||||
} else {
|
||||
request.SetHeader("SessionToken", sessionToken)
|
||||
request.SetHeader("sessionTokenKey", sessionToken)
|
||||
}
|
||||
|
||||
deviceId, _ := ctx.Value(cst.CtxCpdailyDeviceID).(string)
|
||||
|
||||
cpdailyInfoDetail := map[string]any{
|
||||
"deviceId": deviceId,
|
||||
"systemName": "android",
|
||||
"userId": "",
|
||||
"appVersion": "9.8.8",
|
||||
"model": "Unknown",
|
||||
"lon": "0",
|
||||
"lat": "0",
|
||||
"cpdailyVersion": "9.8.8",
|
||||
"systemVersion": "11",
|
||||
}
|
||||
|
||||
cpdailyInfoStr, e := sonic.Marshal(cpdailyInfoDetail)
|
||||
utils.OkOrPanic(e, oops.WithContext(ctx).Wrap)
|
||||
|
||||
encryptedCpdailyInfo := cryptoutil.DesEncrypt(cpdailyInfoStr, cryptoutil.Normal)
|
||||
encodedCpdailyInfo := base64.StdEncoding.EncodeToString(encryptedCpdailyInfo)
|
||||
|
||||
request.SetHeaders(map[string]string{
|
||||
"clientType": "cpdaily_student",
|
||||
"deviceType": "1",
|
||||
"CpdailyClientType": "CPDAILY",
|
||||
"CpdailyStandAlone": "0",
|
||||
"User-Agent": "Mozilla/5.0 (Linux; Android 11; Redmi Note 8 Pro Build/RP1A.230805.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36 cpdaily/9.8.8 wisedu/9.8.8",
|
||||
"CpdailyInfo": encodedCpdailyInfo,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SmsLoginHandler) GetCookieString() string {
|
||||
cookieJar := s.client.CookieJar()
|
||||
serializableJar := cookieJar.(*cookiejar.PersistCookieJar)
|
||||
return serializableJar.Serialize()
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"likedream-goframe/internal/application/cookiejar"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
const (
|
||||
testSmsPhoneNumber = ""
|
||||
testSmsCode = ""
|
||||
)
|
||||
|
||||
func TestSmsLoginHandler_SendSms(t *testing.T) {
|
||||
handler := SmsLoginHandler{}
|
||||
data := handler.SendSms(context.Background(), testSmsPhoneNumber)
|
||||
|
||||
t.Logf("SendSms Data: %+v", data)
|
||||
}
|
||||
|
||||
func TestSmsLoginHandler_LoginByCode(t *testing.T) {
|
||||
handler := SmsLoginHandler{}
|
||||
jar := cookiejar.NewPersistCookieJar()
|
||||
data := handler.LoginByCode(context.Background(), testSmsPhoneNumber, testSmsCode, jar)
|
||||
t.Logf("LoginByCode Data: %+v", data)
|
||||
|
||||
handler.SetLoginCookie(context.Background(), jar, data)
|
||||
}
|
||||
|
||||
func TestLogin(t *testing.T) {
|
||||
handler := SmsLoginHandler{}
|
||||
ctx := gctx.GetInitCtx()
|
||||
sendSmsData := handler.SendSms(ctx, testSmsPhoneNumber)
|
||||
// 读取验证码手动输入
|
||||
var code string
|
||||
println("请输入收到的验证码:")
|
||||
_, _ = fmt.Scanln(&code)
|
||||
loginData := handler.LoginByCode(ctx, testSmsPhoneNumber, code, sendSmsData.CookieJar)
|
||||
handler.SetLoginCookie(ctx, sendSmsData.CookieJar, loginData)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package map_info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/utils"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/samber/oops"
|
||||
)
|
||||
|
||||
func SearchAddressLongitudeAndLatitude(ctx context.Context, address string) []MapPoi {
|
||||
client := httpclient.Cpdaily.Clone(ctx).SetDoNotParseResponse(false)
|
||||
// 首先访问获取ak
|
||||
response, err := client.R().Get("https://lbsyun.baidu.com/jsdemo/demo/webgl0_5.htm")
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.WithContext(ctx).With("url", "https://lbsyun.baidu.com/jsdemo/demo/webgl0_5.htm").In("SearchAddressLongitudeAndLatitude.GetAk").Wrap(err)
|
||||
})
|
||||
ak := ParseAkString(response.String())
|
||||
timestamp := fmt.Sprintf("%d", time.Now().UnixMilli())
|
||||
mapResponse, err := client.R().
|
||||
SetQueryParams(map[string]string{
|
||||
"qt": "placesug",
|
||||
"query": address,
|
||||
"callback": "BMapGL._rd._cbk25241",
|
||||
"region": "131",
|
||||
"city_limit": "false",
|
||||
"t": timestamp,
|
||||
"from": "jsapi",
|
||||
"ak": ak,
|
||||
"v": "gl",
|
||||
"timeStamp": timestamp,
|
||||
}).
|
||||
SetHeaders(map[string]string{
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Referer": "https://lbsyun.baidu.com/",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
|
||||
}).
|
||||
Get("https://api.map.baidu.com/")
|
||||
utils.OkOrPanic(err, func(err error) error {
|
||||
return oops.WithContext(ctx).With("address", address).In("SearchAddressLongitudeAndLatitude.QueryMap").Wrap(err)
|
||||
})
|
||||
|
||||
// 从JSONP响应中提取JSON数据
|
||||
str := ParseJsonpToJson(mapResponse.String())
|
||||
var jsonData MapJSONData
|
||||
sonic.Unmarshal([]byte(str), &jsonData)
|
||||
return jsonData.Result.PoiList
|
||||
}
|
||||
|
||||
// 正则提取ak // <script type="text/javascript" src="//api.map.baidu.com/api?type=webgl&v=1.0&ak=E4805d16520de693a3fe707cdc962045"></script>
|
||||
func ParseAkString(data string) string {
|
||||
reg := regexp.MustCompile(`ak=([^"]+)`)
|
||||
matches := reg.FindStringSubmatch(data)
|
||||
if len(matches) < 2 {
|
||||
utils.OkOrPanic(errors.NewBusinessError(500, "获取ak出错"))
|
||||
}
|
||||
return matches[1]
|
||||
}
|
||||
|
||||
// 从JSONP响应中提取JSON数据
|
||||
// 输入: /**/BMapGL._rd._cbk25241 && BMapGL._rd._cbk25241({...})
|
||||
// 输出: {...}
|
||||
func ParseJsonpToJson(jsonpData string) string {
|
||||
// 匹配 callback(json) 格式,提取括号中的内容
|
||||
reg := regexp.MustCompile(`\((\{.*\})\)`)
|
||||
matches := reg.FindStringSubmatch(jsonpData)
|
||||
if len(matches) < 2 {
|
||||
utils.OkOrPanic(errors.NewBusinessError(500, "解析JSONP数据出错"))
|
||||
}
|
||||
return matches[1]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package map_info
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func TestMapSearch(t *testing.T) {
|
||||
res := SearchAddressLongitudeAndLatitude(gctx.New(), "河北石油职业技术大学c座")
|
||||
marshal, _ := json.Marshal(res)
|
||||
t.Log(string(marshal))
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package map_info
|
||||
|
||||
type MapJSONData struct {
|
||||
Status int `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Result MapResult `json:"result"`
|
||||
}
|
||||
type MapLocation struct {
|
||||
Lat float64 `json:"lat"`
|
||||
Lng float64 `json:"lng"`
|
||||
}
|
||||
type MapPoi struct {
|
||||
Name string `json:"name"`
|
||||
Location MapLocation `json:"location"`
|
||||
UID string `json:"uid"`
|
||||
Province string `json:"province"`
|
||||
City string `json:"city"`
|
||||
District string `json:"district"`
|
||||
Business string `json:"business"`
|
||||
Cityid string `json:"cityid"`
|
||||
Tag string `json:"tag"`
|
||||
Address string `json:"address"`
|
||||
Children []interface{} `json:"children"`
|
||||
Adcode string `json:"adcode"`
|
||||
}
|
||||
type MapResult struct {
|
||||
Q string `json:"q"`
|
||||
PoiList []MapPoi `json:"poi_list"`
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package school
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
@@ -11,6 +10,7 @@ import (
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/framework/redis"
|
||||
"likedream-goframe/internal/utils"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
@@ -18,6 +18,8 @@ import (
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
var lock = sync.RWMutex{}
|
||||
|
||||
func GetSchoolList(ctx context.Context) []CpdailySchoolBriefInfo {
|
||||
response, err := httpclient.Cpdaily.Clone(ctx).R().
|
||||
WithContext(ctx).
|
||||
@@ -55,13 +57,17 @@ func GetSchoolList(ctx context.Context) []CpdailySchoolBriefInfo {
|
||||
}
|
||||
|
||||
func GetSchoolDetail(ctx context.Context, tenantId string) SchoolDetailInfo {
|
||||
client := redis.GetClient()
|
||||
redisResult := client.Get(ctx, cst2.RedisSchoolInfo+tenantId)
|
||||
if redisResult.Err() == nil {
|
||||
var ret SchoolDetailInfo
|
||||
err := sonic.Unmarshal([]byte(redisResult.Val()), &ret)
|
||||
utils.OkOrPanic(err)
|
||||
return ret
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
if !utils.IsDebug() {
|
||||
client := redis.GetClient()
|
||||
redisResult := client.Get(ctx, cst2.RedisSchoolInfo+tenantId)
|
||||
if redisResult.Err() == nil {
|
||||
var ret SchoolDetailInfo
|
||||
err := sonic.Unmarshal([]byte(redisResult.Val()), &ret)
|
||||
utils.OkOrPanic(err)
|
||||
return parseSpecialSchool(ret)
|
||||
}
|
||||
}
|
||||
response, err := httpclient.Cpdaily.Clone(ctx).R().
|
||||
SetHeaders(map[string]string{
|
||||
@@ -100,6 +106,17 @@ func GetSchoolDetail(ctx context.Context, tenantId string) SchoolDetailInfo {
|
||||
WithContext(ctx).
|
||||
Wrap(errors.NewBusinessError(503, "学校ID不存在").Decorate("empty school detail")))
|
||||
}
|
||||
client.Set(ctx, cst2.RedisSchoolInfo+tenantId, ret[0], time.Duration(cst2.RedisSchoolInfoExpire)*time.Second)
|
||||
return ret[0]
|
||||
if !utils.IsDebug() {
|
||||
client := redis.GetClient()
|
||||
client.Set(ctx, cst2.RedisSchoolInfo+tenantId, ret[0], time.Duration(cst2.RedisSchoolInfoExpire)*time.Second)
|
||||
}
|
||||
return parseSpecialSchool(ret[0])
|
||||
}
|
||||
|
||||
func parseSpecialSchool(s SchoolDetailInfo) SchoolDetailInfo {
|
||||
// 甘肃农业大学
|
||||
if s.Id == "gsau" {
|
||||
s.WecloudUrl = "https://fdm.gsau.edu.cn"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -1,181 +1,182 @@
|
||||
package submitcaptcha
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"likedream-goframe/internal/application/cpdaily/types"
|
||||
"likedream-goframe/internal/application/recognizer/classifier"
|
||||
"likedream-goframe/internal/common/errors"
|
||||
"likedream-goframe/internal/utils"
|
||||
"strings"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
type AIResolver struct {
|
||||
client *resty.Client
|
||||
host string
|
||||
deviceId string
|
||||
taskType types.TaskType
|
||||
}
|
||||
|
||||
func NewAIResolver(client *resty.Client, host, deviceId string, taskType types.TaskType) SubmitCaptchaResolver {
|
||||
return &AIResolver{
|
||||
client: client,
|
||||
host: host,
|
||||
deviceId: deviceId,
|
||||
taskType: taskType,
|
||||
}
|
||||
}
|
||||
func (r *AIResolver) GetValidationInfo(ctx context.Context) ValidationInfo {
|
||||
// GetValidationInfo 获取验证信息
|
||||
reqData := map[string]string{
|
||||
"deviceId": r.deviceId,
|
||||
}
|
||||
|
||||
resp, err := r.client.R().
|
||||
SetBody(reqData).
|
||||
Post(r.getValidateUrl())
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
apiResp := utils.ReadJson[ApiResponse](resp.Body)
|
||||
|
||||
if apiResp.Datas == nil {
|
||||
message := "获取提交验证码信息失败"
|
||||
if apiResp.Message != "" {
|
||||
message = apiResp.Message
|
||||
}
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, message))
|
||||
}
|
||||
|
||||
var validationInfo ValidationInfo
|
||||
err = sonic.Unmarshal(apiResp.Datas, &validationInfo)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
return validationInfo
|
||||
|
||||
}
|
||||
func (r *AIResolver) GetCaptchaTicket(ctx context.Context, info ValidationInfo) string {
|
||||
captchaInfo := r.createCaptcha(info)
|
||||
codes := r.getResult(captchaInfo)
|
||||
return r.submitCaptcha(info, captchaInfo, codes)
|
||||
}
|
||||
|
||||
func (r *AIResolver) getResult(data CpSubmitCaptchaForAI) []string {
|
||||
name := data.Name
|
||||
infos := data.ImageInfos
|
||||
var result []string
|
||||
for _, item := range infos {
|
||||
url := item.Path
|
||||
get, err := r.client.R().Get(url)
|
||||
utils.OkOrPanic(err)
|
||||
defer get.Body.Close()
|
||||
bytes, _ := io.ReadAll(get.Body)
|
||||
//todo 将图片保存方便后面训练
|
||||
//os.WriteFile(item.Code+".png", bytes, 0666)
|
||||
if classifier.ClassifyImage(bytes, name) {
|
||||
result = append(result, item.Code)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// getValidateUrl 根据任务类型获取验证URL
|
||||
func (r *AIResolver) getValidateUrl() string {
|
||||
baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
|
||||
switch r.taskType {
|
||||
case types.TaskTypeCollection:
|
||||
return baseUrl + "/wec-counselor-collector-apps/stu/collector/checkValidation"
|
||||
case types.TaskTypeSign:
|
||||
return baseUrl + "/wec-counselor-sign-apps/stu/sign/checkValidation"
|
||||
case types.TaskTypeSleepCheck:
|
||||
return baseUrl + "/wec-counselor-attendance-apps/student/attendance/checkValidation"
|
||||
default:
|
||||
utils.OkOrPanic(errors.NewBusinessError(400, "不支持的任务类型"))
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// createCaptcha 创建验证码
|
||||
func (r *AIResolver) createCaptcha(info ValidationInfo) CpSubmitCaptchaForAI {
|
||||
baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
url := baseUrl + "/captcha-open-api/v1/captcha/create/scenesImage"
|
||||
|
||||
resp, err := r.client.R().
|
||||
SetHeader("deviceId", r.deviceId).
|
||||
SetMultipartFormData(map[string]string{
|
||||
"accountKey": info.AccountKey,
|
||||
"sceneCode": info.SceneCode,
|
||||
"tenantId": info.TenantId,
|
||||
"userId": info.UserId,
|
||||
}).
|
||||
Post(url)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
apiResp := utils.ReadJson[ApiResponse](resp.Body)
|
||||
|
||||
if apiResp.Result == nil {
|
||||
message := "获取提交验证码失败"
|
||||
if apiResp.Message != "" {
|
||||
message = apiResp.Message
|
||||
}
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, message))
|
||||
}
|
||||
|
||||
var result CpSubmitCaptchaForAI
|
||||
err = sonic.Unmarshal(apiResp.Result, &result)
|
||||
utils.OkOrPanic(err)
|
||||
return result
|
||||
}
|
||||
|
||||
// submitCaptcha 提交验证码
|
||||
func (r *AIResolver) submitCaptcha(info ValidationInfo, submitCaptcha CpSubmitCaptchaForAI, codes []string) string {
|
||||
baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
url := baseUrl + "/captcha-open-api/v1/captcha/validate/scenesImage"
|
||||
|
||||
formData := map[string]string{
|
||||
"accountKey": info.AccountKey,
|
||||
"sceneCode": info.SceneCode,
|
||||
"tenantId": info.TenantId,
|
||||
"userId": info.UserId,
|
||||
"scenesImageCode": submitCaptcha.Code,
|
||||
}
|
||||
|
||||
// 创建multipart form request
|
||||
req := r.client.R().SetHeader("deviceId", r.deviceId)
|
||||
|
||||
// 添加基本表单数据
|
||||
for key, value := range formData {
|
||||
req = req.SetMultipartFormData(map[string]string{key: value})
|
||||
}
|
||||
|
||||
// 添加验证码列表
|
||||
for _, code := range codes {
|
||||
req = req.SetMultipartField("scenesImageCodes", "", "", strings.NewReader(code))
|
||||
}
|
||||
|
||||
resp, err := req.Post(url)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
apiResp := utils.ReadJson[ApiResponse](resp.Body)
|
||||
|
||||
if apiResp.Code != "200" {
|
||||
message := "提交验证码失败"
|
||||
if apiResp.Message != "" {
|
||||
message = apiResp.Message
|
||||
}
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, message))
|
||||
}
|
||||
|
||||
if apiResp.Result == nil {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, "今日校园返回空验证码结果"))
|
||||
}
|
||||
|
||||
var result string
|
||||
err = sonic.Unmarshal(apiResp.Result, &result)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
return result
|
||||
}
|
||||
//
|
||||
//import (
|
||||
// "context"
|
||||
// "io"
|
||||
// "likedream-goframe/internal/application/cpdaily/types"
|
||||
// "likedream-goframe/internal/application/recognizer/classifier"
|
||||
// "likedream-goframe/internal/common/errors"
|
||||
// "likedream-goframe/internal/utils"
|
||||
// "strings"
|
||||
//
|
||||
// "github.com/bytedance/sonic"
|
||||
// "resty.dev/v3"
|
||||
//)
|
||||
//
|
||||
//type AIResolver struct {
|
||||
// client *resty.Client
|
||||
// host string
|
||||
// deviceId string
|
||||
// taskType types.TaskType
|
||||
//}
|
||||
//
|
||||
//func NewAIResolver(client *resty.Client, host, deviceId string, taskType types.TaskType) SubmitCaptchaResolver {
|
||||
// return &AIResolver{
|
||||
// client: client,
|
||||
// host: host,
|
||||
// deviceId: deviceId,
|
||||
// taskType: taskType,
|
||||
// }
|
||||
//}
|
||||
//func (r *AIResolver) GetValidationInfo(ctx context.Context) ValidationInfo {
|
||||
// // GetValidationInfo 获取验证信息
|
||||
// reqData := map[string]string{
|
||||
// "deviceId": r.deviceId,
|
||||
// }
|
||||
//
|
||||
// resp, err := r.client.R().
|
||||
// SetBody(reqData).
|
||||
// Post(r.getValidateUrl())
|
||||
// utils.OkOrPanic(err)
|
||||
//
|
||||
// apiResp := utils.ReadJson[ApiResponse](resp.Body)
|
||||
//
|
||||
// if apiResp.Datas == nil {
|
||||
// message := "获取提交验证码信息失败"
|
||||
// if apiResp.Message != "" {
|
||||
// message = apiResp.Message
|
||||
// }
|
||||
// utils.OkOrPanic(errors.NewBusinessError(503, message))
|
||||
// }
|
||||
//
|
||||
// var validationInfo ValidationInfo
|
||||
// err = sonic.Unmarshal(apiResp.Datas, &validationInfo)
|
||||
// utils.OkOrPanic(err)
|
||||
//
|
||||
// return validationInfo
|
||||
//
|
||||
//}
|
||||
//func (r *AIResolver) GetCaptchaTicket(ctx context.Context, info ValidationInfo) string {
|
||||
// captchaInfo := r.createCaptcha(info)
|
||||
// codes := r.getResult(captchaInfo)
|
||||
// return r.submitCaptcha(info, captchaInfo, codes)
|
||||
//}
|
||||
//
|
||||
//func (r *AIResolver) getResult(data CpSubmitCaptchaForAI) []string {
|
||||
// name := data.Name
|
||||
// infos := data.ImageInfos
|
||||
// var result []string
|
||||
// for _, item := range infos {
|
||||
// url := item.Path
|
||||
// get, err := r.client.R().Get(url)
|
||||
// utils.OkOrPanic(err)
|
||||
// defer get.Body.Close()
|
||||
// bytes, _ := io.ReadAll(get.Body)
|
||||
// //todo 将图片保存方便后面训练
|
||||
// //os.WriteFile(item.Code+".png", bytes, 0666)
|
||||
// if classifier.ClassifyImage(bytes, name) {
|
||||
// result = append(result, item.Code)
|
||||
// }
|
||||
// }
|
||||
// return result
|
||||
//}
|
||||
//
|
||||
//// getValidateUrl 根据任务类型获取验证URL
|
||||
//func (r *AIResolver) getValidateUrl() string {
|
||||
// baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
//
|
||||
// switch r.taskType {
|
||||
// case types.TaskTypeCollection:
|
||||
// return baseUrl + "/wec-counselor-collector-apps/stu/collector/checkValidation"
|
||||
// case types.TaskTypeSign:
|
||||
// return baseUrl + "/wec-counselor-sign-apps/stu/sign/checkValidation"
|
||||
// case types.TaskTypeSleepCheck:
|
||||
// return baseUrl + "/wec-counselor-attendance-apps/student/attendance/checkValidation"
|
||||
// default:
|
||||
// utils.OkOrPanic(errors.NewBusinessError(400, "不支持的任务类型"))
|
||||
// return ""
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// createCaptcha 创建验证码
|
||||
//func (r *AIResolver) createCaptcha(info ValidationInfo) CpSubmitCaptchaForAI {
|
||||
// baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
// url := baseUrl + "/captcha-open-api/v1/captcha/create/scenesImage"
|
||||
//
|
||||
// resp, err := r.client.R().
|
||||
// SetHeader("deviceId", r.deviceId).
|
||||
// SetMultipartFormData(map[string]string{
|
||||
// "accountKey": info.AccountKey,
|
||||
// "sceneCode": info.SceneCode,
|
||||
// "tenantId": info.TenantId,
|
||||
// "userId": info.UserId,
|
||||
// }).
|
||||
// Post(url)
|
||||
// utils.OkOrPanic(err)
|
||||
//
|
||||
// apiResp := utils.ReadJson[ApiResponse](resp.Body)
|
||||
//
|
||||
// if apiResp.Result == nil {
|
||||
// message := "获取提交验证码失败"
|
||||
// if apiResp.Message != "" {
|
||||
// message = apiResp.Message
|
||||
// }
|
||||
// utils.OkOrPanic(errors.NewBusinessError(503, message))
|
||||
// }
|
||||
//
|
||||
// var result CpSubmitCaptchaForAI
|
||||
// err = sonic.Unmarshal(apiResp.Result, &result)
|
||||
// utils.OkOrPanic(err)
|
||||
// return result
|
||||
//}
|
||||
//
|
||||
//// submitCaptcha 提交验证码
|
||||
//func (r *AIResolver) submitCaptcha(info ValidationInfo, submitCaptcha CpSubmitCaptchaForAI, codes []string) string {
|
||||
// baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
// url := baseUrl + "/captcha-open-api/v1/captcha/validate/scenesImage"
|
||||
//
|
||||
// formData := map[string]string{
|
||||
// "accountKey": info.AccountKey,
|
||||
// "sceneCode": info.SceneCode,
|
||||
// "tenantId": info.TenantId,
|
||||
// "userId": info.UserId,
|
||||
// "scenesImageCode": submitCaptcha.Code,
|
||||
// }
|
||||
//
|
||||
// // 创建multipart form request
|
||||
// req := r.client.R().SetHeader("deviceId", r.deviceId)
|
||||
//
|
||||
// // 添加基本表单数据
|
||||
// for key, value := range formData {
|
||||
// req = req.SetMultipartFormData(map[string]string{key: value})
|
||||
// }
|
||||
//
|
||||
// // 添加验证码列表
|
||||
// for _, code := range codes {
|
||||
// req = req.SetMultipartField("scenesImageCodes", "", "", strings.NewReader(code))
|
||||
// }
|
||||
//
|
||||
// resp, err := req.Post(url)
|
||||
// utils.OkOrPanic(err)
|
||||
//
|
||||
// apiResp := utils.ReadJson[ApiResponse](resp.Body)
|
||||
//
|
||||
// if apiResp.Code != "200" {
|
||||
// message := "提交验证码失败"
|
||||
// if apiResp.Message != "" {
|
||||
// message = apiResp.Message
|
||||
// }
|
||||
// utils.OkOrPanic(errors.NewBusinessError(503, message))
|
||||
// }
|
||||
//
|
||||
// if apiResp.Result == nil {
|
||||
// utils.OkOrPanic(errors.NewBusinessError(503, "今日校园返回空验证码结果"))
|
||||
// }
|
||||
//
|
||||
// var result string
|
||||
// err = sonic.Unmarshal(apiResp.Result, &result)
|
||||
// utils.OkOrPanic(err)
|
||||
//
|
||||
// return result
|
||||
//}
|
||||
|
||||
@@ -42,9 +42,7 @@ type ApiResponse struct {
|
||||
type ITStarResponse struct {
|
||||
Code json.Number `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
SuccCode []string `json:"succCode"`
|
||||
} `json:"data"`
|
||||
Data []string `json:"data"`
|
||||
}
|
||||
|
||||
type SubmitCaptchaResolver interface {
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
type RuoliSubmitCaptchaResolver struct {
|
||||
type NormalSubmitCaptchaResolver struct {
|
||||
client *resty.Client
|
||||
host string
|
||||
deviceId string
|
||||
@@ -24,12 +24,12 @@ type RuoliSubmitCaptchaResolver struct {
|
||||
itstarUrl string
|
||||
}
|
||||
|
||||
var _ SubmitCaptchaResolver = (*RuoliSubmitCaptchaResolver)(nil)
|
||||
var _ SubmitCaptchaResolver = (*NormalSubmitCaptchaResolver)(nil)
|
||||
|
||||
// NewRuoliResolver 创建若李验证码解析器
|
||||
func NewRuoliResolver(client *resty.Client, host, deviceId string, taskType types.TaskType) *RuoliSubmitCaptchaResolver {
|
||||
baseUrl := g.Config().MustGetWithEnv(gctx.GetInitCtx(), cst.ConfigRuoliCaptchaBaseUrl).String()
|
||||
return &RuoliSubmitCaptchaResolver{
|
||||
// NewNormalResolver 创建若李验证码解析器
|
||||
func NewNormalResolver(client *resty.Client, host, deviceId string, taskType types.TaskType) *NormalSubmitCaptchaResolver {
|
||||
baseUrl := g.Config().MustGetWithEnv(gctx.GetInitCtx(), cst.ConfigCaptchaBaseUrl).String() + "/classifier"
|
||||
return &NormalSubmitCaptchaResolver{
|
||||
client: client,
|
||||
host: host,
|
||||
deviceId: deviceId,
|
||||
@@ -39,12 +39,12 @@ func NewRuoliResolver(client *resty.Client, host, deviceId string, taskType type
|
||||
}
|
||||
|
||||
// getITStarUrl 获取ITStar服务URL
|
||||
func (r *RuoliSubmitCaptchaResolver) getITStarUrl() string {
|
||||
func (r *NormalSubmitCaptchaResolver) getITStarUrl() string {
|
||||
if r.itstarUrl != "" {
|
||||
return r.itstarUrl
|
||||
}
|
||||
|
||||
r.itstarUrl = g.Config().MustGetWithEnv(gctx.GetInitCtx(), cst.ConfigRuoliCaptchaBaseUrl).String()
|
||||
r.itstarUrl = g.Config().MustGetWithEnv(gctx.GetInitCtx(), cst.ConfigCaptchaBaseUrl).String() + "/classifier"
|
||||
if r.itstarUrl == "" {
|
||||
utils.OkOrPanic(errors.NewBusinessError(500, "未配置ITStarUrl"))
|
||||
}
|
||||
@@ -53,7 +53,7 @@ func (r *RuoliSubmitCaptchaResolver) getITStarUrl() string {
|
||||
}
|
||||
|
||||
// getValidateUrl 根据任务类型获取验证URL
|
||||
func (r *RuoliSubmitCaptchaResolver) getValidateUrl() string {
|
||||
func (r *NormalSubmitCaptchaResolver) getValidateUrl() string {
|
||||
baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
|
||||
switch r.taskType {
|
||||
@@ -70,7 +70,7 @@ func (r *RuoliSubmitCaptchaResolver) getValidateUrl() string {
|
||||
}
|
||||
|
||||
// GetValidationInfo 获取验证信息
|
||||
func (r *RuoliSubmitCaptchaResolver) GetValidationInfo(ctx context.Context) ValidationInfo {
|
||||
func (r *NormalSubmitCaptchaResolver) GetValidationInfo(ctx context.Context) ValidationInfo {
|
||||
reqData := map[string]string{
|
||||
"deviceId": r.deviceId,
|
||||
}
|
||||
@@ -98,14 +98,14 @@ func (r *RuoliSubmitCaptchaResolver) GetValidationInfo(ctx context.Context) Vali
|
||||
}
|
||||
|
||||
// GetCaptchaTicket 获取验证码票据
|
||||
func (r *RuoliSubmitCaptchaResolver) GetCaptchaTicket(ctx context.Context, info ValidationInfo) string {
|
||||
func (r *NormalSubmitCaptchaResolver) GetCaptchaTicket(ctx context.Context, info ValidationInfo) string {
|
||||
captchaInfo := r.createCaptcha(info)
|
||||
codes := r.getResultFromItStar(captchaInfo.RawResponseJson)
|
||||
return r.submitCaptcha(info, captchaInfo, codes)
|
||||
}
|
||||
|
||||
// createCaptcha 创建验证码
|
||||
func (r *RuoliSubmitCaptchaResolver) createCaptcha(info ValidationInfo) CpSubmitCaptcha {
|
||||
func (r *NormalSubmitCaptchaResolver) createCaptcha(info ValidationInfo) CpSubmitCaptcha {
|
||||
baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
url := baseUrl + "/captcha-open-api/v1/captcha/create/scenesImage"
|
||||
|
||||
@@ -139,16 +139,13 @@ func (r *RuoliSubmitCaptchaResolver) createCaptcha(info ValidationInfo) CpSubmit
|
||||
}
|
||||
|
||||
// getResultFromItStar 从ITStar获取识别结果
|
||||
func (r *RuoliSubmitCaptchaResolver) getResultFromItStar(rawResponse json.RawMessage) []string {
|
||||
func (r *NormalSubmitCaptchaResolver) getResultFromItStar(rawResponse json.RawMessage) []string {
|
||||
// 解析原始响应为map以便添加authKey
|
||||
var responseMap map[string]any
|
||||
err := sonic.Unmarshal(rawResponse, &responseMap)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
responseMap["authKey"] = "ITStarYYDS"
|
||||
|
||||
itstarUrl := strings.TrimSuffix(r.getITStarUrl(), "/")
|
||||
url := itstarUrl + "/captcha/unLimitValidate"
|
||||
url := r.getITStarUrl()
|
||||
|
||||
resp, err := r.client.R().
|
||||
SetBody(responseMap).
|
||||
@@ -161,11 +158,11 @@ func (r *RuoliSubmitCaptchaResolver) getResultFromItStar(rawResponse json.RawMes
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, fmt.Sprintf("验证码识别出错: %s", itstarResp.Msg)))
|
||||
}
|
||||
|
||||
return itstarResp.Data.SuccCode
|
||||
return itstarResp.Data
|
||||
}
|
||||
|
||||
// submitCaptcha 提交验证码
|
||||
func (r *RuoliSubmitCaptchaResolver) submitCaptcha(info ValidationInfo, submitCaptcha CpSubmitCaptcha, codes []string) string {
|
||||
func (r *NormalSubmitCaptchaResolver) submitCaptcha(info ValidationInfo, submitCaptcha CpSubmitCaptcha, codes []string) string {
|
||||
baseUrl := strings.TrimSuffix(r.host, "/")
|
||||
url := baseUrl + "/captcha-open-api/v1/captcha/validate/scenesImage"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
func TestRuoliSubmitCaptchaResolver_GetCaptchaTicket(t *testing.T) {
|
||||
loginClient, detail := testutil.LoginTestUser()
|
||||
|
||||
resolver := NewRuoliResolver(loginClient, detail.WecloudUrl, "abcdefg", types.TaskTypeSleepCheck)
|
||||
resolver := NewNormalResolver(loginClient, detail.WecloudUrl, "abcdefg", types.TaskTypeSleepCheck)
|
||||
|
||||
info := resolver.GetValidationInfo(context.Background())
|
||||
|
||||
|
||||
@@ -15,4 +15,5 @@ type CpTaskFormItem struct {
|
||||
Sort uint `json:"sort,omitempty"`
|
||||
CacheKey string `json:"cacheKey,omitempty"`
|
||||
Show bool `json:"show,omitempty"`
|
||||
Tip string `json:"tip,omitempty"`
|
||||
}
|
||||
|
||||
@@ -8,4 +8,5 @@ const (
|
||||
ItemTypeMulti
|
||||
ItemTypeImage
|
||||
ItemTypeAddress
|
||||
ItemTypeLatAndLon
|
||||
)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package leavetype
|
||||
|
||||
type LeaveListOne struct {
|
||||
Id string `json:"id"`
|
||||
LeaveType string `json:"leaveType"`
|
||||
CreateTime string `json:"createTime"`
|
||||
AceEndTime string `json:"aceEndTime"`
|
||||
Reason string `json:"reason"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
@@ -359,19 +359,27 @@ func (c *CpdailyAutoSignTask) ParseFormJson(ctx context.Context, rawJson map[str
|
||||
var list []*formtype.CpTaskFormItem
|
||||
|
||||
// 经纬度
|
||||
//dto := &formtype.CpTaskFormItem{
|
||||
// Title: "经度",
|
||||
// ColName: "lon",
|
||||
// Type: formtype.ItemTypeInput,
|
||||
// Required: true,
|
||||
//}
|
||||
//list = append(list, dto)
|
||||
//
|
||||
//dto = &formtype.CpTaskFormItem{
|
||||
// Title: "纬度",
|
||||
// ColName: "lat",
|
||||
// Type: formtype.ItemTypeInput,
|
||||
// Required: true,
|
||||
//}
|
||||
//list = append(list, dto)
|
||||
dto := &formtype.CpTaskFormItem{
|
||||
Title: "经度",
|
||||
ColName: "lon",
|
||||
Type: formtype.ItemTypeInput,
|
||||
Required: true,
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
dto = &formtype.CpTaskFormItem{
|
||||
Title: "纬度",
|
||||
ColName: "lat",
|
||||
Type: formtype.ItemTypeInput,
|
||||
Title: "经纬度",
|
||||
ColName: "latAndLon",
|
||||
Type: formtype.ItemTypeLatAndLon,
|
||||
Required: true,
|
||||
Tip: "您可以通过地址搜索签到经纬度,如果觉得不够准确可以自行修改",
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
@@ -380,6 +388,7 @@ func (c *CpdailyAutoSignTask) ParseFormJson(ctx context.Context, rawJson map[str
|
||||
ColName: "address",
|
||||
Type: formtype.ItemTypeInput,
|
||||
Required: true,
|
||||
Tip: "这个就是指签到完毕后查看时最底部那个最详细的地址信息哦",
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
@@ -389,6 +398,7 @@ func (c *CpdailyAutoSignTask) ParseFormJson(ctx context.Context, rawJson map[str
|
||||
ColName: "signImg",
|
||||
Type: formtype.ItemTypeImage,
|
||||
Required: true,
|
||||
Tip: "您可以上传多张图片,会顺序轮换更新的哦~",
|
||||
}
|
||||
list = append(list, dto)
|
||||
}
|
||||
@@ -410,6 +420,7 @@ func (c *CpdailyAutoSignTask) ParseFormJson(ctx context.Context, rawJson map[str
|
||||
IsOtherItems: false,
|
||||
},
|
||||
},
|
||||
Tip: "一般在学校就是选否,如果在外实习、请假之类的才选是",
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
@@ -484,6 +495,11 @@ func (c *CpdailyAutoSignTask) FillCustomForm(ctx context.Context, form map[strin
|
||||
lon = v.Content
|
||||
case "address":
|
||||
address = v.Content
|
||||
case "latAndLon":
|
||||
{
|
||||
res := strings.Split(v.Content, ",")
|
||||
lat, lon = res[1], res[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -520,7 +536,7 @@ func (c *CpdailyAutoSignTask) FillCustomForm(ctx context.Context, form map[strin
|
||||
}
|
||||
|
||||
// 处理验证码
|
||||
submitCaptchaResolver := submitcaptcha.NewRuoliResolver(c.client, c.host, deviceId, types.TaskTypeSign)
|
||||
submitCaptchaResolver := submitcaptcha.NewNormalResolver(c.client, c.host, deviceId, types.TaskTypeSign)
|
||||
captchaInfo := submitCaptchaResolver.GetValidationInfo(ctx)
|
||||
|
||||
if captchaInfo.Validation {
|
||||
|
||||
@@ -435,19 +435,27 @@ func (c *CpdailySleepCheckTask) ParseFormJson(ctx context.Context, rawJson map[s
|
||||
var list []*formtype.CpTaskFormItem
|
||||
|
||||
// 经纬度
|
||||
//dto := &formtype.CpTaskFormItem{
|
||||
// Title: "经度",
|
||||
// ColName: "lon",
|
||||
// Type: formtype.ItemTypeInput,
|
||||
// Required: true,
|
||||
//}
|
||||
//list = append(list, dto)
|
||||
//
|
||||
//dto = &formtype.CpTaskFormItem{
|
||||
// Title: "纬度",
|
||||
// ColName: "lat",
|
||||
// Type: formtype.ItemTypeInput,
|
||||
// Required: true,
|
||||
//}
|
||||
//list = append(list, dto)
|
||||
dto := &formtype.CpTaskFormItem{
|
||||
Title: "经度",
|
||||
ColName: "lon",
|
||||
Type: formtype.ItemTypeInput,
|
||||
Required: true,
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
dto = &formtype.CpTaskFormItem{
|
||||
Title: "纬度",
|
||||
ColName: "lat",
|
||||
Type: formtype.ItemTypeInput,
|
||||
Title: "经纬度",
|
||||
ColName: "latAndLon",
|
||||
Type: formtype.ItemTypeLatAndLon,
|
||||
Required: true,
|
||||
Tip: "您可以通过地址搜索签到经纬度,如果觉得不够准确可以自行修改",
|
||||
}
|
||||
list = append(list, dto)
|
||||
dto = &formtype.CpTaskFormItem{
|
||||
@@ -455,6 +463,7 @@ func (c *CpdailySleepCheckTask) ParseFormJson(ctx context.Context, rawJson map[s
|
||||
ColName: "address",
|
||||
Type: formtype.ItemTypeInput,
|
||||
Required: true,
|
||||
Tip: "这个就是指签到完毕后查看时最底部那个最详细的地址信息哦",
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
@@ -464,6 +473,7 @@ func (c *CpdailySleepCheckTask) ParseFormJson(ctx context.Context, rawJson map[s
|
||||
ColName: "signImg",
|
||||
Type: formtype.ItemTypeImage,
|
||||
Required: true,
|
||||
Tip: "您可以上传多张图片,会顺序轮换更新的哦~",
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
@@ -486,6 +496,7 @@ func (c *CpdailySleepCheckTask) ParseFormJson(ctx context.Context, rawJson map[s
|
||||
IsOtherItems: false,
|
||||
},
|
||||
},
|
||||
Tip: "一般在学校就是选否,如果在外实习、请假之类的才选是",
|
||||
}
|
||||
list = append(list, dto)
|
||||
|
||||
@@ -514,6 +525,12 @@ func (c *CpdailySleepCheckTask) FillCustomForm(ctx context.Context, form map[str
|
||||
lon = v.Content
|
||||
case "address":
|
||||
address = v.Content
|
||||
case "latAndLon":
|
||||
{
|
||||
res := strings.Split(v.Content, ",")
|
||||
lat, lon = res[1], res[0]
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,8 +540,8 @@ func (c *CpdailySleepCheckTask) FillCustomForm(ctx context.Context, form map[str
|
||||
resultForm["uaIsCpadaily"] = gvar.New(true)
|
||||
|
||||
// 处理验证码
|
||||
//submitCaptchaResolver := submitcaptcha.NewRuoliResolver(c.client, c.host, deviceId, types.TaskTypeSleepCheck)
|
||||
submitCaptchaResolver := submitcaptcha.NewAIResolver(c.client, c.host, deviceId, types.TaskTypeSleepCheck)
|
||||
submitCaptchaResolver := submitcaptcha.NewNormalResolver(c.client, c.host, deviceId, types.TaskTypeSleepCheck)
|
||||
//submitCaptchaResolver := submitcaptcha.NewAIResolver(c.client, c.host, deviceId, types.TaskTypeSleepCheck)
|
||||
captchaInfo := submitCaptchaResolver.GetValidationInfo(ctx)
|
||||
|
||||
if captchaInfo.Validation {
|
||||
@@ -534,7 +551,7 @@ func (c *CpdailySleepCheckTask) FillCustomForm(ctx context.Context, form map[str
|
||||
return utils.Catch(func() {
|
||||
ticket = submitCaptchaResolver.GetCaptchaTicket(ctx, captchaInfo)
|
||||
})
|
||||
}, retry.Delay(15*time.Second), retry.Attempts(5), retry.Context(ctx))
|
||||
}, retry.Delay(10*time.Second), retry.Attempts(5), retry.Context(ctx))
|
||||
if e != nil {
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, "提交验证码识别失败").WithInnerError(e), oops.WithContext(ctx).Wrap)
|
||||
}
|
||||
@@ -676,3 +693,18 @@ func (c *CpdailySleepCheckTask) Submit(ctx context.Context, form map[string]*gva
|
||||
utils.OkOrPanic(errors.NewBusinessError(503, responseJSON.Get("message").String()), oops.WithContext(ctx).Wrap)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CpdailySleepCheckTask) GetYearAndMonth(ctx context.Context) (string, string) {
|
||||
// Get current time in Shanghai timezone
|
||||
timeNow := time.Now().In(cst.TimeZoneShangHai)
|
||||
|
||||
// Check if current day is within first 2 days of the month
|
||||
if timeNow.Day() <= 2 {
|
||||
// Return previous month
|
||||
prevTime := timeNow.AddDate(0, -1, 0)
|
||||
return strconv.Itoa(prevTime.Year()), strconv.Itoa(int(prevTime.Month()))
|
||||
} else {
|
||||
// Return current month
|
||||
return strconv.Itoa(timeNow.Year()), strconv.Itoa(int(timeNow.Month()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"likedream-goframe/internal/testutil"
|
||||
"testing"
|
||||
|
||||
"github.com/joomcode/errorx"
|
||||
)
|
||||
|
||||
func TestCpdailySleepCheckTask_QueryFormByTitle(t *testing.T) {
|
||||
loginClient, schoolDetail := testutil.LoginTestUser()
|
||||
|
||||
task := NewSleepCheckTask(loginClient, schoolDetail.WecloudUrl)
|
||||
tasks := task.QueryFormByTitle(context.Background(), "查寝")
|
||||
|
||||
if len(tasks) == 0 {
|
||||
t.Error("未查询到查寝任务")
|
||||
} else {
|
||||
t.Logf("查询到查寝任务: %v", tasks)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCpdailySleepCheckTask_GetRecentTaskTitle(t *testing.T) {
|
||||
loginClient, schoolDetail := testutil.LoginTestUser()
|
||||
|
||||
task := NewSleepCheckTask(loginClient, schoolDetail.WecloudUrl)
|
||||
|
||||
titles := task.GetRecentTaskTitle(context.Background())
|
||||
|
||||
if len(titles) == 0 {
|
||||
t.Error("未查询到查寝任务标题")
|
||||
} else {
|
||||
t.Logf("查询到查寝任务标题: %v", titles)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCpdailySleepCheckTask_QueryFormByYearMonth(t *testing.T) {
|
||||
loginClient, schoolDetail := testutil.LoginTestUser()
|
||||
|
||||
task := NewSleepCheckTask(loginClient, schoolDetail.WecloudUrl)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
titleGlob string
|
||||
year string
|
||||
month string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "查询当前月份查寝任务",
|
||||
titleGlob: "查寝",
|
||||
year: "2025",
|
||||
month: "6",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "查询单数字月份查寝任务",
|
||||
titleGlob: "查寝",
|
||||
year: "2025",
|
||||
month: "6", // 将会被格式化为 "06"
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "使用通配符模式匹配",
|
||||
titleGlob: "*查寝*",
|
||||
year: "2025",
|
||||
month: "6",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "查询不存在的任务",
|
||||
titleGlob: "不存在的任务",
|
||||
year: "2025",
|
||||
month: "6",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
oopsError, _ := errorx.ErrorFromPanic(r)
|
||||
if !tt.wantErr {
|
||||
t.Errorf("QueryFormByYearMonth() 意外的panic: %+v", oopsError)
|
||||
} else {
|
||||
t.Logf("预期的错误: %+v", oopsError)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
form := task.QueryFormByYearMonth(context.Background(), tt.titleGlob, tt.year, tt.month)
|
||||
|
||||
if tt.wantErr {
|
||||
t.Error("预期应该出现错误,但没有出现")
|
||||
return
|
||||
}
|
||||
|
||||
if form == nil {
|
||||
t.Error("未查询到查寝任务表单")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证返回结果的结构
|
||||
if realTitle := form["realTitle"].String(); realTitle == "" {
|
||||
t.Error("返回结果中缺少 realTitle 或 realTitle 为空")
|
||||
} else {
|
||||
t.Logf("任务真实标题: %s", realTitle)
|
||||
}
|
||||
|
||||
if taskInfo := form["taskInfo"].Map(); taskInfo == nil {
|
||||
t.Error("返回结果中缺少 taskInfo 或 taskInfo 为空")
|
||||
} else {
|
||||
t.Logf("任务信息包含字段: %d", len(taskInfo))
|
||||
|
||||
// 验证关键字段是否存在
|
||||
requiredFields := []string{"taskName", "signWid", "signInstanceWid"}
|
||||
for _, field := range requiredFields {
|
||||
if _, exists := taskInfo[field]; !exists {
|
||||
t.Errorf("taskInfo 中缺少必要字段: %s", field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if rows := form["rows"].Map(); rows == nil {
|
||||
t.Error("返回结果中缺少 rows 或 rows 为空")
|
||||
} else {
|
||||
t.Logf("表单数据包含字段: %d", len(rows))
|
||||
}
|
||||
|
||||
t.Logf("查询到查寝任务表单,标题: %v", form["realTitle"])
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"likedream-goframe/internal/testutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
)
|
||||
|
||||
func TestGetHistoryForm(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
loginClient, schoolDetail := testutil.LoginTestUser()
|
||||
task := NewSleepCheckTask(loginClient, schoolDetail.WecloudUrl)
|
||||
y, m := task.GetYearAndMonth(ctx)
|
||||
month := task.QueryFormByYearMonth(ctx, "晚查寝", y, m)
|
||||
marshal, _ := sonic.Marshal(month)
|
||||
t.Log(string(marshal))
|
||||
}
|
||||
@@ -3,11 +3,25 @@ package httpclient
|
||||
import (
|
||||
"crypto/tls"
|
||||
"likedream-goframe/internal/utils"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
var transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
MinVersion: tls.VersionTLS10,
|
||||
},
|
||||
TLSHandshakeTimeout: 15 * time.Second,
|
||||
}
|
||||
|
||||
func init() {
|
||||
_ = os.Setenv("GODEBUG", "tlsrsakex=1")
|
||||
}
|
||||
|
||||
var Cpdaily = resty.New().
|
||||
SetCookieJar(nil).
|
||||
SetTimeout(30*time.Second).
|
||||
@@ -32,9 +46,7 @@ func NewCpdailyClient() *resty.Client {
|
||||
SetCookieJar(nil).
|
||||
SetTimeout(30*time.Second).
|
||||
SetDoNotParseResponse(true).
|
||||
SetTLSClientConfig(&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}).
|
||||
SetTransport(transport).
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36")
|
||||
|
||||
// 根据调试模式设置代理和调试选项
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"likedream-goframe/internal/utils"
|
||||
"time"
|
||||
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
func NewMogudingClient() *resty.Client {
|
||||
client := resty.New().
|
||||
SetCookieJar(nil).
|
||||
SetTimeout(30*time.Second).
|
||||
SetDoNotParseResponse(false).
|
||||
SetTLSClientConfig(&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}).
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36")
|
||||
|
||||
// 根据调试模式设置代理和调试选项
|
||||
if !utils.IsDebug() {
|
||||
client.SetDebug(false)
|
||||
} else {
|
||||
client.SetProxy("http://127.0.0.1:9000")
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
@@ -24,3 +24,25 @@ func init() {
|
||||
Xuexitong.SetProxy("http://127.0.0.1:9000")
|
||||
}
|
||||
}
|
||||
|
||||
// NewXuexitongClient 创建一个全新的独立 client 实例,避免 Clone 可能的浅拷贝问题
|
||||
// 每个实例都是完全独立的,适用于并发场景,不会共享状态
|
||||
func NewXuexitongClient() *resty.Client {
|
||||
client := resty.New().
|
||||
SetCookieJar(nil).
|
||||
SetTimeout(30*time.Second).
|
||||
SetDoNotParseResponse(false).
|
||||
SetTLSClientConfig(&tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}).
|
||||
SetHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36")
|
||||
|
||||
// 根据调试模式设置代理和调试选项
|
||||
if !utils.IsDebug() {
|
||||
client.SetDebug(false)
|
||||
} else {
|
||||
client.SetProxy("http://127.0.0.1:9000")
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package cryptoutil
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
const (
|
||||
// AES 密钥
|
||||
Secret = "23DbtQHR2UMbH6mJ"
|
||||
// MD5 签名后缀
|
||||
SignSuffix = "3478cbbc33f84bd00d75d7dfa69e0daa"
|
||||
)
|
||||
|
||||
// Encrypt 使用 AES ECB PKCS7 加密并返回十六进制字符串
|
||||
func Encrypt(plaintext string) (string, error) {
|
||||
key := []byte(Secret)
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// PKCS7 填充
|
||||
plainBytes := []byte(plaintext)
|
||||
padding := aes.BlockSize - len(plainBytes)%aes.BlockSize
|
||||
padText := make([]byte, len(plainBytes)+padding)
|
||||
copy(padText, plainBytes)
|
||||
for i := len(plainBytes); i < len(padText); i++ {
|
||||
padText[i] = byte(padding)
|
||||
}
|
||||
|
||||
// ECB 模式加密
|
||||
encrypted := make([]byte, len(padText))
|
||||
for i := 0; i < len(padText); i += aes.BlockSize {
|
||||
block.Encrypt(encrypted[i:i+aes.BlockSize], padText[i:i+aes.BlockSize])
|
||||
}
|
||||
|
||||
return hex.EncodeToString(encrypted), nil
|
||||
}
|
||||
|
||||
// Sign2 MD5 签名
|
||||
func Sign2(str string) string {
|
||||
str += SignSuffix
|
||||
hash := md5.Sum([]byte(str))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package entity
|
||||
|
||||
// MogudingUser 蘑菇钉用户实体
|
||||
type MogudingUser struct {
|
||||
Username string `json:"username"` // 账号
|
||||
Password string `json:"password"` // 密码
|
||||
UserId string `json:"userId"`
|
||||
Token string `json:"token"`
|
||||
UserType string `json:"userType"`
|
||||
PlanId string `json:"planId"`
|
||||
PlanName string `json:"planName"`
|
||||
}
|
||||
|
||||
// LoginDto 登录请求 DTO
|
||||
type LoginDto struct {
|
||||
Phone string `json:"phone"`
|
||||
Password string `json:"password"`
|
||||
Captcha string `json:"captcha"`
|
||||
LoginType string `json:"loginType"`
|
||||
Uuid string `json:"uuid"`
|
||||
Device string `json:"device"`
|
||||
Version string `json:"version"`
|
||||
T string `json:"t"`
|
||||
}
|
||||
|
||||
// LoginResponse 登录响应
|
||||
type LoginResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
UserId string `json:"userId"`
|
||||
Token string `json:"token"`
|
||||
UserType string `json:"userType"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// PlanResponse 获取 PlanId 响应
|
||||
type PlanResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data []struct {
|
||||
PlanId string `json:"planId"`
|
||||
PlanName string `json:"planName"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// SignRequest 签到请求
|
||||
type SignRequest struct {
|
||||
Country string `json:"country"`
|
||||
Address string `json:"address"`
|
||||
Province string `json:"province"`
|
||||
City string `json:"city"`
|
||||
State string `json:"state"`
|
||||
Area string `json:"area"`
|
||||
Latitude string `json:"latitude"`
|
||||
Longitude string `json:"longitude"`
|
||||
Description string `json:"description"`
|
||||
PlanId string `json:"planId"`
|
||||
Type string `json:"type"` // START 或 END
|
||||
Device string `json:"device"`
|
||||
}
|
||||
|
||||
// SignResponse 签到响应
|
||||
type SignResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data any `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
package moguding
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/application/moguding/cryptoutil"
|
||||
"likedream-goframe/internal/application/moguding/entity"
|
||||
"likedream-goframe/internal/framework/logger"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
// API 基础地址
|
||||
ApiBase = "https://api.moguding.net:9000"
|
||||
// 登录接口
|
||||
ApiLogin = ApiBase + "/session/user/v6/login"
|
||||
// 获取实习计划接口
|
||||
ApiGetPlan = ApiBase + "/practice/plan/v3/getPlanByStu"
|
||||
// 打卡签到接口
|
||||
ApiSign = ApiBase + "/attendence/clock/v4/save"
|
||||
)
|
||||
|
||||
type MogudingClient struct {
|
||||
client *resty.Client
|
||||
user *entity.MogudingUser
|
||||
}
|
||||
|
||||
// NewMogudingClient 创建蘑菇钉客户端
|
||||
func NewMogudingClient(ctx context.Context) *MogudingClient {
|
||||
client := httpclient.NewMogudingClient()
|
||||
|
||||
return &MogudingClient{
|
||||
client: client,
|
||||
user: &entity.MogudingUser{},
|
||||
}
|
||||
}
|
||||
|
||||
// Login 登录
|
||||
func (c *MogudingClient) Login(ctx context.Context, username, password string) error {
|
||||
if username == "" || password == "" {
|
||||
return fmt.Errorf("账号或密码不能为空")
|
||||
}
|
||||
|
||||
// 加密账号密码
|
||||
encryptedPhone, err := cryptoutil.Encrypt(username)
|
||||
if err != nil {
|
||||
logger.Logger.Error("加密账号失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
encryptedPassword, err := cryptoutil.Encrypt(password)
|
||||
if err != nil {
|
||||
logger.Logger.Error("加密密码失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 加密时间戳
|
||||
timestamp := fmt.Sprintf("%d", time.Now().UnixMilli())
|
||||
encryptedTime, err := cryptoutil.Encrypt(timestamp)
|
||||
if err != nil {
|
||||
logger.Logger.Error("加密时间戳失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 构造登录请求
|
||||
loginDto := entity.LoginDto{
|
||||
Phone: encryptedPhone,
|
||||
Password: encryptedPassword,
|
||||
T: encryptedTime,
|
||||
LoginType: "android",
|
||||
}
|
||||
|
||||
// 发送登录请求
|
||||
resp, err := c.client.R().
|
||||
SetBody(loginDto).
|
||||
Post(ApiLogin)
|
||||
|
||||
if err != nil {
|
||||
logger.Logger.Error("登录请求失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var loginResp entity.LoginResponse
|
||||
if err := json.Unmarshal(resp.Bytes(), &loginResp); err != nil {
|
||||
logger.Logger.Error("解析登录响应失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
if loginResp.Code != 200 {
|
||||
return fmt.Errorf("登录失败:%s", loginResp.Msg)
|
||||
}
|
||||
|
||||
// 保存用户信息
|
||||
c.user.Username = username
|
||||
c.user.Password = password
|
||||
c.user.UserId = loginResp.Data.UserId
|
||||
c.user.Token = loginResp.Data.Token
|
||||
c.user.UserType = loginResp.Data.UserType
|
||||
|
||||
logger.Logger.Info("登录成功",
|
||||
zap.String("userId", c.user.UserId),
|
||||
zap.String("userType", c.user.UserType))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPlanId 获取实习计划 ID
|
||||
func (c *MogudingClient) GetPlanId(ctx context.Context) error {
|
||||
if c.user.Token == "" {
|
||||
return fmt.Errorf("请先登录")
|
||||
}
|
||||
|
||||
// 计算签名
|
||||
signStr := c.user.UserId + c.user.UserType
|
||||
sign := cryptoutil.Sign2(signStr)
|
||||
|
||||
// 发送请求
|
||||
resp, err := c.client.R().
|
||||
SetHeaders(map[string]string{
|
||||
"roleKey": c.user.UserType,
|
||||
"sign": sign,
|
||||
"authorization": c.user.Token,
|
||||
}).
|
||||
SetBody(map[string]string{"state": ""}).
|
||||
Post(ApiGetPlan)
|
||||
|
||||
if err != nil {
|
||||
logger.Logger.Error("获取 PlanId 请求失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var planResp entity.PlanResponse
|
||||
if err := json.Unmarshal(resp.Bytes(), &planResp); err != nil {
|
||||
logger.Logger.Error("解析 PlanId 响应失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
if planResp.Code != 200 {
|
||||
return fmt.Errorf("获取 PlanId 失败:%s", planResp.Msg)
|
||||
}
|
||||
|
||||
if len(planResp.Data) == 0 {
|
||||
return fmt.Errorf("未找到实习计划")
|
||||
}
|
||||
|
||||
// 保存第一个计划信息
|
||||
c.user.PlanId = planResp.Data[0].PlanId
|
||||
c.user.PlanName = planResp.Data[0].PlanName
|
||||
|
||||
logger.Logger.Info("获取 PlanId 成功",
|
||||
zap.String("planId", c.user.PlanId),
|
||||
zap.String("planName", c.user.PlanName))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sign 打卡签到
|
||||
func (c *MogudingClient) Sign(ctx context.Context, signReq *entity.SignRequest) error {
|
||||
if c.user.Token == "" {
|
||||
return fmt.Errorf("请先登录")
|
||||
}
|
||||
|
||||
if c.user.PlanId == "" {
|
||||
return fmt.Errorf("请先获取实习计划")
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if signReq.PlanId == "" {
|
||||
signReq.PlanId = c.user.PlanId
|
||||
}
|
||||
if signReq.Device == "" {
|
||||
signReq.Device = "Android"
|
||||
}
|
||||
if signReq.Type == "" {
|
||||
signReq.Type = "START"
|
||||
}
|
||||
|
||||
// 计算签名
|
||||
signStr := signReq.Device + signReq.Type + signReq.PlanId + c.user.UserId + signReq.Address
|
||||
sign := cryptoutil.Sign2(signStr)
|
||||
|
||||
// 发送请求
|
||||
resp, err := c.client.R().
|
||||
SetHeaders(map[string]string{
|
||||
"roleKey": c.user.UserType,
|
||||
"sign": sign,
|
||||
"authorization": c.user.Token,
|
||||
}).
|
||||
SetBody(signReq).
|
||||
Post(ApiSign)
|
||||
|
||||
if err != nil {
|
||||
logger.Logger.Error("签到请求失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var signResp entity.SignResponse
|
||||
if err := json.Unmarshal(resp.Bytes(), &signResp); err != nil {
|
||||
logger.Logger.Error("解析签到响应失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
if signResp.Code != 200 {
|
||||
return fmt.Errorf("签到失败:%s", signResp.Msg)
|
||||
}
|
||||
|
||||
logger.Logger.Info("签到成功",
|
||||
zap.String("type", signReq.Type),
|
||||
zap.String("address", signReq.Address))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUser 获取用户信息
|
||||
func (c *MogudingClient) GetUser() *entity.MogudingUser {
|
||||
return c.user
|
||||
}
|
||||
|
||||
// SetUser 设置用户信息(用于恢复登录状态)
|
||||
func (c *MogudingClient) SetUser(user *entity.MogudingUser) {
|
||||
c.user = user
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package moguding
|
||||
|
||||
import (
|
||||
"context"
|
||||
"likedream-goframe/internal/application/moguding/entity"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMogudingLogin(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := NewMogudingClient(ctx)
|
||||
|
||||
// 替换为实际的测试账号
|
||||
username := "13307425047"
|
||||
password := "wgz2021322L"
|
||||
|
||||
err := client.Login(ctx, username, password)
|
||||
if err != nil {
|
||||
t.Fatalf("登录失败: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("登录成功,UserId: %s, Token: %s", client.user.UserId, client.user.Token)
|
||||
}
|
||||
|
||||
func TestMogudingGetPlanId(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := NewMogudingClient(ctx)
|
||||
|
||||
// 先登录
|
||||
username := "your_username"
|
||||
password := "your_password"
|
||||
|
||||
err := client.Login(ctx, username, password)
|
||||
if err != nil {
|
||||
t.Fatalf("登录失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取 PlanId
|
||||
err = client.GetPlanId(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("获取 PlanId 失败: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("获取 PlanId 成功,PlanId: %s, PlanName: %s", client.user.PlanId, client.user.PlanName)
|
||||
}
|
||||
|
||||
func TestMogudingSign(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := NewMogudingClient(ctx)
|
||||
|
||||
// 先登录
|
||||
username := "your_username"
|
||||
password := "your_password"
|
||||
|
||||
err := client.Login(ctx, username, password)
|
||||
if err != nil {
|
||||
t.Fatalf("登录失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取 PlanId
|
||||
err = client.GetPlanId(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("获取 PlanId 失败: %v", err)
|
||||
}
|
||||
|
||||
// 打卡签到
|
||||
signReq := &entity.SignRequest{
|
||||
Country: "中国",
|
||||
Address: "四川省 · 成都市 · 武侯区 · 咕噜咕噜",
|
||||
Province: "四川省",
|
||||
City: "成都市",
|
||||
State: "1",
|
||||
Area: "武侯区",
|
||||
Latitude: "33.100039",
|
||||
Longitude: "101.987848",
|
||||
Description: "测试打卡",
|
||||
Type: "START", // START 表示上班打卡,END 表示下班打卡
|
||||
Device: "Android",
|
||||
}
|
||||
|
||||
err = client.Sign(ctx, signReq)
|
||||
if err != nil {
|
||||
t.Fatalf("打卡失败: %v", err)
|
||||
}
|
||||
|
||||
t.Logf("打卡成功")
|
||||
}
|
||||
|
||||
func TestMogudingFullProcess(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := NewMogudingClient(ctx)
|
||||
|
||||
// 1. 登录
|
||||
username := "your_username"
|
||||
password := "your_password"
|
||||
|
||||
t.Log("步骤1: 登录")
|
||||
err := client.Login(ctx, username, password)
|
||||
if err != nil {
|
||||
t.Fatalf("登录失败: %v", err)
|
||||
}
|
||||
t.Logf("登录成功,UserId: %s", client.user.UserId)
|
||||
|
||||
// 2. 获取 PlanId
|
||||
t.Log("步骤2: 获取实习计划")
|
||||
err = client.GetPlanId(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("获取 PlanId 失败: %v", err)
|
||||
}
|
||||
t.Logf("获取 PlanId 成功,PlanId: %s, PlanName: %s", client.user.PlanId, client.user.PlanName)
|
||||
|
||||
// 3. 上班打卡
|
||||
t.Log("步骤3: 上班打卡")
|
||||
signInReq := &entity.SignRequest{
|
||||
Country: "中国",
|
||||
Address: "四川省 · 成都市 · 武侯区 · 咕噜咕噜",
|
||||
Province: "四川省",
|
||||
City: "成都市",
|
||||
State: "1",
|
||||
Area: "武侯区",
|
||||
Latitude: "33.100039",
|
||||
Longitude: "101.987848",
|
||||
Description: "上班打卡",
|
||||
Type: "START",
|
||||
Device: "Android",
|
||||
}
|
||||
|
||||
err = client.Sign(ctx, signInReq)
|
||||
if err != nil {
|
||||
t.Fatalf("上班打卡失败: %v", err)
|
||||
}
|
||||
t.Log("上班打卡成功")
|
||||
|
||||
// 4. 下班打卡(可选)
|
||||
t.Log("步骤4: 下班打卡")
|
||||
signOutReq := &entity.SignRequest{
|
||||
Country: "中国",
|
||||
Address: "四川省 · 成都市 · 武侯区 · 咕噜咕噜",
|
||||
Province: "四川省",
|
||||
City: "成都市",
|
||||
State: "1",
|
||||
Area: "武侯区",
|
||||
Latitude: "33.100039",
|
||||
Longitude: "101.987848",
|
||||
Description: "下班打卡",
|
||||
Type: "END",
|
||||
Device: "Android",
|
||||
}
|
||||
|
||||
err = client.Sign(ctx, signOutReq)
|
||||
if err != nil {
|
||||
t.Fatalf("下班打卡失败: %v", err)
|
||||
}
|
||||
t.Log("下班打卡成功")
|
||||
|
||||
t.Log("完整流程测试通过!")
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
package classifier
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"os"
|
||||
|
||||
ort "github.com/yalue/onnxruntime_go"
|
||||
)
|
||||
|
||||
type ImageClassifier struct {
|
||||
session *ort.AdvancedSession
|
||||
inputShape []int64
|
||||
classes []string
|
||||
inputTensor *ort.Tensor[float32]
|
||||
outputTensor *ort.Tensor[float32]
|
||||
}
|
||||
|
||||
// NewImageClassifier 创建新的图片分类器
|
||||
func NewImageClassifier(modelPath, classesPath string) (*ImageClassifier, error) {
|
||||
// 加载类别名称
|
||||
classes, err := loadClasses(classesPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("加载类别失败: %v", err)
|
||||
}
|
||||
|
||||
// 创建session选项
|
||||
options, err := ort.NewSessionOptions()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建session选项失败: %v", err)
|
||||
}
|
||||
defer options.Destroy()
|
||||
|
||||
// 创建输入输出tensor
|
||||
inputShape := ort.NewShape(1, 3, 224, 224)
|
||||
outputShape := ort.NewShape(1, int64(len(classes)))
|
||||
|
||||
inputTensor, err := ort.NewEmptyTensor[float32](inputShape)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("创建输入tensor失败: %v", err)
|
||||
}
|
||||
|
||||
outputTensor, err := ort.NewEmptyTensor[float32](outputShape)
|
||||
if err != nil {
|
||||
inputTensor.Destroy()
|
||||
return nil, fmt.Errorf("创建输出tensor失败: %v", err)
|
||||
}
|
||||
|
||||
// 加载模型
|
||||
session, err := ort.NewAdvancedSession(modelPath,
|
||||
[]string{"input"}, []string{"output"},
|
||||
[]ort.ArbitraryTensor{inputTensor}, []ort.ArbitraryTensor{outputTensor},
|
||||
options)
|
||||
if err != nil {
|
||||
inputTensor.Destroy()
|
||||
outputTensor.Destroy()
|
||||
return nil, fmt.Errorf("加载模型失败: %v", err)
|
||||
}
|
||||
|
||||
return &ImageClassifier{
|
||||
session: session,
|
||||
inputShape: []int64{1, 3, 224, 224},
|
||||
classes: classes,
|
||||
inputTensor: inputTensor,
|
||||
outputTensor: outputTensor,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// loadClasses 从文件加载类别名称
|
||||
func loadClasses(path string) ([]string, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var classes []string
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
classes = append(classes, scanner.Text())
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return classes, nil
|
||||
}
|
||||
|
||||
// Predict 预测图片类别
|
||||
func (ic *ImageClassifier) Predict(imgPath string) (string, float32, error) {
|
||||
// 加载并预处理图片
|
||||
inputData, err := ic.preprocessImage(imgPath)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("预处理图片失败: %v", err)
|
||||
}
|
||||
|
||||
// 设置输入数据
|
||||
copy(ic.inputTensor.GetData(), inputData)
|
||||
|
||||
// 运行推理
|
||||
err = ic.session.Run()
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("推理失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取输出数据
|
||||
outputData := ic.outputTensor.GetData()
|
||||
|
||||
// 找到最大概率的类别
|
||||
maxIdx := 0
|
||||
maxProb := outputData[0]
|
||||
for i, prob := range outputData {
|
||||
if prob > maxProb {
|
||||
maxProb = prob
|
||||
maxIdx = i
|
||||
}
|
||||
}
|
||||
|
||||
// 应用softmax获取概率
|
||||
expSum := float32(0)
|
||||
for _, v := range outputData {
|
||||
expSum += exp(v)
|
||||
}
|
||||
probability := exp(outputData[maxIdx]) / expSum
|
||||
|
||||
return ic.classes[maxIdx], probability, nil
|
||||
}
|
||||
|
||||
// PredictFromBytes 从字节数据预测图片类别
|
||||
func (ic *ImageClassifier) PredictFromBytes(imgData []byte) (string, float32, error) {
|
||||
// 预处理图片
|
||||
inputData, err := ic.preprocessImageBytes(imgData)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("预处理图片失败: %v", err)
|
||||
}
|
||||
|
||||
// 设置输入数据
|
||||
copy(ic.inputTensor.GetData(), inputData)
|
||||
|
||||
// 运行推理
|
||||
err = ic.session.Run()
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("推理失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取输出数据
|
||||
outputData := ic.outputTensor.GetData()
|
||||
|
||||
// 找到最大概率的类别
|
||||
maxIdx := 0
|
||||
maxProb := outputData[0]
|
||||
for i, prob := range outputData {
|
||||
if prob > maxProb {
|
||||
maxProb = prob
|
||||
maxIdx = i
|
||||
}
|
||||
}
|
||||
|
||||
// 应用softmax获取概率
|
||||
expSum := float32(0)
|
||||
for _, v := range outputData {
|
||||
expSum += exp(v)
|
||||
}
|
||||
probability := exp(outputData[maxIdx]) / expSum
|
||||
|
||||
return ic.classes[maxIdx], probability, nil
|
||||
}
|
||||
|
||||
// Close 关闭分类器
|
||||
func (ic *ImageClassifier) Close() error {
|
||||
if ic.inputTensor != nil {
|
||||
ic.inputTensor.Destroy()
|
||||
}
|
||||
if ic.outputTensor != nil {
|
||||
ic.outputTensor.Destroy()
|
||||
}
|
||||
if ic.session != nil {
|
||||
ic.session.Destroy()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// exp 计算e的x次方(简单实现)
|
||||
func exp(x float32) float32 {
|
||||
// 使用泰勒级数近似
|
||||
result := float32(1.0)
|
||||
term := float32(1.0)
|
||||
for i := 1; i < 20; i++ {
|
||||
term *= x / float32(i)
|
||||
result += term
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package classifier
|
||||
|
||||
// ClassifyImage 图片数据 & 类别名称
|
||||
// return 是否匹配
|
||||
func ClassifyImage(imgData []byte, className string) bool {
|
||||
name, _, _ := imageClassifier.PredictFromBytes(imgData)
|
||||
return className == name
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package classifier
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"likedream-goframe/internal/application/recognizer"
|
||||
"likedream-goframe/internal/framework/logger"
|
||||
"likedream-goframe/internal/utils"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
//go:embed static/*
|
||||
var fs embed.FS
|
||||
var imageClassifier *ImageClassifier
|
||||
|
||||
func init() {
|
||||
if !recognizer.OnnxIsInit {
|
||||
recognizer.InitOnnx()
|
||||
}
|
||||
modelPath, classesPath := initModel()
|
||||
classifier, err := NewImageClassifier(modelPath, classesPath)
|
||||
if err != nil {
|
||||
logger.Logger.Panic("初始化ai模型失败", zap.Error(err))
|
||||
}
|
||||
imageClassifier = classifier
|
||||
}
|
||||
func initModel() (modelPath, classesPath string) {
|
||||
// 检测文件是否存在
|
||||
exePath := strings.ToLower(os.Args[0])
|
||||
// 获取绝对路径
|
||||
absPath, _ := filepath.Abs(exePath)
|
||||
staticPath := filepath.Join(filepath.Dir(absPath), "static")
|
||||
if _, err := os.Stat(staticPath); os.IsNotExist(err) {
|
||||
os.Mkdir(staticPath, 0755)
|
||||
}
|
||||
modelPath = filepath.Join(staticPath, "model.onnx")
|
||||
modelBytes, err := fs.ReadFile("static/model.onnx")
|
||||
utils.OkOrPanic(err)
|
||||
if _, err := os.Stat(modelPath); os.IsNotExist(err) {
|
||||
os.WriteFile(modelPath, modelBytes, 0644)
|
||||
}
|
||||
classesPath = filepath.Join(staticPath, "classes.txt")
|
||||
classesBytes, err := fs.ReadFile("static/classes.txt")
|
||||
utils.OkOrPanic(err)
|
||||
if _, err := os.Stat(classesPath); os.IsNotExist(err) {
|
||||
os.WriteFile(classesPath, classesBytes, 0644)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package classifier
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"os"
|
||||
)
|
||||
|
||||
// preprocessImage 预处理图片文件
|
||||
func (ic *ImageClassifier) preprocessImage(imgPath string) ([]float32, error) {
|
||||
file, err := os.Open(imgPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
img, _, err := image.Decode(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ic.processImage(img)
|
||||
}
|
||||
|
||||
// preprocessImageBytes 预处理图片字节数据
|
||||
func (ic *ImageClassifier) preprocessImageBytes(imgData []byte) ([]float32, error) {
|
||||
img, _, err := image.Decode(bytes.NewReader(imgData))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ic.processImage(img)
|
||||
}
|
||||
|
||||
// processImage 处理图片为模型输入格式
|
||||
func (ic *ImageClassifier) processImage(img image.Image) ([]float32, error) {
|
||||
// 调整图片大小到224x224
|
||||
resized := resizeImage(img, 224, 224)
|
||||
|
||||
// 转换为float32数组,并进行归一化
|
||||
// ImageNet的均值和标准差
|
||||
mean := []float32{0.485, 0.456, 0.406}
|
||||
std := []float32{0.229, 0.224, 0.225}
|
||||
|
||||
data := make([]float32, 3*224*224)
|
||||
|
||||
for y := 0; y < 224; y++ {
|
||||
for x := 0; x < 224; x++ {
|
||||
r, g, b, _ := resized.At(x, y).RGBA()
|
||||
|
||||
// 转换为0-1范围
|
||||
rNorm := float32(r) / 65535.0
|
||||
gNorm := float32(g) / 65535.0
|
||||
bNorm := float32(b) / 65535.0
|
||||
|
||||
// 应用归一化
|
||||
idx := y*224 + x
|
||||
data[idx] = (rNorm - mean[0]) / std[0] // R通道
|
||||
data[224*224+idx] = (gNorm - mean[1]) / std[1] // G通道
|
||||
data[2*224*224+idx] = (bNorm - mean[2]) / std[2] // B通道
|
||||
}
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// resizeImage 调整图片大小
|
||||
func resizeImage(img image.Image, width, height int) image.Image {
|
||||
bounds := img.Bounds()
|
||||
srcW := bounds.Dx()
|
||||
srcH := bounds.Dy()
|
||||
|
||||
dst := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
// 简单的最近邻插值
|
||||
srcX := x * srcW / width
|
||||
srcY := y * srcH / height
|
||||
|
||||
if srcX >= srcW {
|
||||
srcX = srcW - 1
|
||||
}
|
||||
if srcY >= srcH {
|
||||
srcY = srcH - 1
|
||||
}
|
||||
|
||||
dst.Set(x, y, img.At(srcX, srcY))
|
||||
}
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// centerCrop 中心裁剪图片
|
||||
func centerCrop(img image.Image, size int) image.Image {
|
||||
bounds := img.Bounds()
|
||||
width := bounds.Dx()
|
||||
height := bounds.Dy()
|
||||
|
||||
var x0, y0 int
|
||||
if width > height {
|
||||
x0 = (width - height) / 2
|
||||
y0 = 0
|
||||
width = height
|
||||
} else {
|
||||
x0 = 0
|
||||
y0 = (height - width) / 2
|
||||
height = width
|
||||
}
|
||||
|
||||
cropped := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
cropped.Set(x, y, img.At(x0+x, y0+y))
|
||||
}
|
||||
}
|
||||
|
||||
return resizeImage(cropped, size, size)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
公交车
|
||||
向日葵
|
||||
多肉
|
||||
摩托车
|
||||
樱桃
|
||||
汽车
|
||||
满天星
|
||||
狗
|
||||
狮子
|
||||
猫
|
||||
老虎
|
||||
自行车
|
||||
芒果
|
||||
苹果
|
||||
荷花
|
||||
葡萄
|
||||
西瓜
|
||||
豹子
|
||||
长颈鹿
|
||||
青桔
|
||||
飞机
|
||||
香蕉
|
||||
高铁
|
||||
Binary file not shown.
@@ -1,109 +0,0 @@
|
||||
package ddddocr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/thedevsaddam/gojsonq"
|
||||
ort "github.com/yalue/onnxruntime_go"
|
||||
"image"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// SemiOCRVerification 半自动验证码识别(要自己传入outputShape值)
|
||||
func SemiOCRVerification(img image.Image, outputShape ort.Shape) string {
|
||||
img1 := ResizeImage(img, uint(64*img.Bounds().Dx()/img.Bounds().Dy()), 64)
|
||||
imgGray := ConvertToGray(img1)
|
||||
|
||||
inputData := ImageToGrayFloatArray(imgGray)
|
||||
inputShape := ort.NewShape(1, 1, 64, int64(imgGray.Bounds().Dx()))
|
||||
inputTensor, err := ort.NewTensor[float32](inputShape, inputData)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer inputTensor.Destroy()
|
||||
// This hypothetical network maps a 2x5 input -> 2x3x4 output.
|
||||
outputTensor, err := ort.NewEmptyTensor[int64](outputShape)
|
||||
defer outputTensor.Destroy()
|
||||
onnxPath := initModel()
|
||||
session, err := ort.NewAdvancedSession(onnxPath,
|
||||
[]string{"input1"}, []string{"output"},
|
||||
[]ort.Value{inputTensor}, []ort.Value{outputTensor}, nil)
|
||||
defer session.Destroy()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = session.Run()
|
||||
if err != nil {
|
||||
fmt.Errorf(err.Error())
|
||||
}
|
||||
|
||||
outputData := outputTensor.GetData()
|
||||
codeResult := ""
|
||||
for i := 0; i < len(outputData); i++ {
|
||||
if outputData[i] != 0 {
|
||||
codeResult += gojsonq.New().JSONString(getCharCode()).Find("[" + strconv.Itoa(int(outputData[i])) + "]").(string)
|
||||
}
|
||||
}
|
||||
return codeResult
|
||||
}
|
||||
|
||||
// AutoOCRVerification 全自动
|
||||
func AutoOCRVerification(img image.Image) string {
|
||||
img1 := ResizeImage(img, uint(64*img.Bounds().Dx()/img.Bounds().Dy()), 64)
|
||||
imgGray := ConvertToGray(img1)
|
||||
inputData := ImageToGrayFloatArray(imgGray)
|
||||
inputShape := ort.NewShape(1, 1, 64, int64(imgGray.Bounds().Dx()))
|
||||
inputTensor, err := ort.NewTensor[float32](inputShape, inputData)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer inputTensor.Destroy()
|
||||
var outputShape = ort.NewShape(1, 16)
|
||||
codeResult := ""
|
||||
//失败一次获取输出纬度
|
||||
for {
|
||||
outputTensor, err := ort.NewEmptyTensor[int64](outputShape)
|
||||
defer outputTensor.Destroy()
|
||||
onnxPath := initModel()
|
||||
session, err := ort.NewAdvancedSession(onnxPath,
|
||||
[]string{"input1"}, []string{"output"},
|
||||
[]ort.Value{inputTensor}, []ort.Value{outputTensor}, nil)
|
||||
defer session.Destroy()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err1 := session.Run()
|
||||
if err1 != nil {
|
||||
if strings.Contains(err1.Error(), "OrtValue shape verification failed. Current shape:") {
|
||||
regex := regexp.MustCompile(`Requested shape:{(\d+),(\d+)}`)
|
||||
matches := regex.FindStringSubmatch(err1.Error())
|
||||
if len(matches) == 3 {
|
||||
c1, _ := strconv.Atoi(matches[1])
|
||||
c2, _ := strconv.Atoi(matches[2])
|
||||
outputShape = ort.NewShape(int64(c1), int64(c2))
|
||||
continue
|
||||
}
|
||||
}
|
||||
fmt.Errorf(err1.Error())
|
||||
return codeResult
|
||||
}
|
||||
|
||||
outputData := outputTensor.GetData()
|
||||
|
||||
for i := 0; i < len(outputData); i++ {
|
||||
if outputData[i] != 0 {
|
||||
codeResult += gojsonq.New().JSONString(getCharCode()).Find("[" + strconv.Itoa(int(outputData[i])) + "]").(string)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
return codeResult
|
||||
}
|
||||
@@ -1,870 +0,0 @@
|
||||
package ddddocr
|
||||
|
||||
// 获取映射字符串
|
||||
func getCharCode() string {
|
||||
return `["", "掀", "袜", "顧", "徕", "榱", "荪", "浡", "其", "炎", "玉", "恩", "劣", "徽", "廉", "桂", "拂",
|
||||
"鳊", "撤",
|
||||
"赏", "哮", "侄", "蓮", "И", "进", "饭", "饱", "优", "楸", "礻", "蜉", "營", "伙", "杌", "修", "榜",
|
||||
"准", "铒",
|
||||
"戏", "赭", "襟", "彘", "彩", "雁", "闽", "坎", "聂", "氡", "辜", "苁", "潆", "摁", "月", "稇", "而",
|
||||
"醴", "簉",
|
||||
"卑", "妖", "埽", "嘡", "醛", "見", "煎", "汪", "秽", "迄", "噭", "焉", "钌", "瑕", "玻", "仙", "蹑",
|
||||
"钀", "翦",
|
||||
"丰", "矗", "2", "胚", "镊", "镡", "鍊", "帖", "僰", "淀", "吒", "冲", "挡", "粼", "螈", "缵", "孺",
|
||||
"侦", "曷",
|
||||
"渐", "敷", "投", "宸", "祉", "柳", "尖", "梃", "淘", "臁", "躇", "撖", "惭", "狄", "聢", "官", "狴",
|
||||
"诬", "骄",
|
||||
"跻", "場", "姻", "钎", "藥", "綉", "驾", "舻", "黢", "鲦", "蜣", "渖", "绹", "佰", "怜", "三", "痪",
|
||||
"眍", "养",
|
||||
"角", "薜", "濑", "劳", "戟", "傎", "纫", "徉", "收", "稍", "虫", "螋", "鬲", "捌", "陡", "蓟", "邳",
|
||||
"蹢", "涉",
|
||||
"煋", "端", "懷", "椤", "埶", "廊", "免", "秫", "猢", "睐", "臺", "擀", "布", "麃", "彗", "汊", "芄",
|
||||
"遣", "胙",
|
||||
"另", "癯", "徭", "疢", "茆", "忡", "'", "烃", "笕", "薤", "肆", "熛", "過", "盖", "跷", "呷", "痿",
|
||||
"沖", "魍",
|
||||
"讣", "庤", "弑", "诩", "庵", "履", "暮", "始", "滟", "矅", "蛹", "鸿", "啃", "铋", "沿", "鐾", "酆",
|
||||
"團", "恙",
|
||||
"閥", "聒", "讵", "颠", "沾", "堅", "踣", "陴", "覃", "滙", "浐", "钇", "脆", "炙", "亮", "觌", "産",
|
||||
"汩", "鸭",
|
||||
"斄", "堆", "掭", "揞", "鹂", "郫", "瘅", "蚂", "揩", "学", "组", "浸", "腙", "耀", "嗛", "局", "蠓",
|
||||
"肠", "昏",
|
||||
"I", "岑", "镯", "憧", "油", "泸", "鸟", "潇", "蕻", "褒", "瞧", "旸", "昭", "庐", "鞒", "内", "痈",
|
||||
"己", "曙",
|
||||
"怠", "锟", "晞", "耢", "鲢", "醦", "糕", "療", "寇", "梵", "黾", "呻", "苒", "ü", "校", "嘏", "昃",
|
||||
"Ⅰ", "蕰",
|
||||
"凖", "嵛", "裨", "筏", "匜", "咋", "乏", "婵", "镂", "珰", "感", "蔗", "蚵", "庞", "弢", "槟", "口",
|
||||
"漉", "﹒",
|
||||
"咂", "俩", "增", "硐", "襙", "绉", "卿", "距", "璱", "猖", "铚", "郚", "嬖", "缒", "阃", "扞", "V",
|
||||
"望", "最",
|
||||
"浔", "骜", "赃", "闻", "砍", "奸", "灶", "以", "获", "鳎", "浦", "罐", "孓", "纭", "瘀", "普", "氰",
|
||||
"塮", "症",
|
||||
"顷", "们", "螓", "蛸", "鵰", "册", "美", "萨", "沘", "犰", "嫌", "名", ")", "懦", "滇", "F", "垡",
|
||||
"声", "毅",
|
||||
"隅", "鲎", "煨", "萦", "宜", "唇", "鯨", "邛", "杲", "赜", "长", "魂", "桠", "锇", "搓", "俘", "仰",
|
||||
"膘", "宦",
|
||||
"歹", "遁", "猃", "噉", "幂", "糜", "嗤", "周", "剂", "曦", "暧", "焖", "髻", "釐", "泰", "窟", "檎",
|
||||
"旧", "犀",
|
||||
"镄", "百", "取", "岍", "逗", "叽", "呃", "鲪", "萬", "陈", "7", "習", "区", "逄", "宏", "罡", "漭",
|
||||
"盗", "郿",
|
||||
"般", "谢", "倪", "纵", "婶", "砧", "揖", "扪", "濒", "愤", "茓", "浞", "子", "揄", "旌", "趄", "樊",
|
||||
"醑", "遄",
|
||||
"婚", "汶", "矩", "裈", "弊", "呱", "铳", "勿", "蚴", "忿", "褓", "缚", "酱", "璞", "庆", "除", "礌",
|
||||
"珩", "榨",
|
||||
"鼢", "逞", "容", "圯", "猛", "陌", "-", "嚯", "镘", "鱾", "睚", "猬", "杜", "鳓", "燈", "計", "咣",
|
||||
"炜", "睁",
|
||||
"箱", "邮", "略", "馇", "逐", "雀", "僬", "髯", "奖", "俱", "-", "绗", "犏", "辱", "忑", "挽", "康",
|
||||
"蝼", "栏",
|
||||
"模", "辒", "•", "儋", "罱", "墈", "会", "秀", "栈", "缔", "醜", "蚣", "阮", "鼗", "眼", "湧", "沁",
|
||||
"夥", "毕",
|
||||
"媚", "瘳", "痣", "搴", "闿", "遍", "焰", "岣", "舱", "埌", "麿", "嘿", "靽", "体", "想", "霓", "钛",
|
||||
"摽", "苑",
|
||||
"芳", "技", "綮", "钅", "燠", "栾", "年", "悱", "腹", "员", "呕", "闇", "嗫", "檩", "荒", "溱", "舨",
|
||||
"峙", "卒",
|
||||
"洑", "预", "弯", "蔷", "叵", "锯", "慈", "牧", "患", "贇", "偷", "鲜", "锓", "躔", "嚬", "烈", "娌",
|
||||
"嘲", "详",
|
||||
"麺", "舒", "厨", "徵", "葹", "只", "篦", "鹀", "剕", "驳", "聍", "黧", "砾", "暅", "褫", "呈", "森",
|
||||
"结", "龛",
|
||||
"钲", "轧", "扔", "蕹", "赵", "涒", "冯", "渲", "缭", "坚", "趼", "鲑", "倫", "门", "班", "垚", "鞍",
|
||||
"菘", "畐",
|
||||
"僇", "侉", "禢", "轳", "饦", "兽", "呯", "捂", "樨", "卧", "栝", "豭", "冶", "鉰", "申", "蜈", "印",
|
||||
"缨", "镫",
|
||||
"蕾", "圜", "扑", "娉", "烦", "缳", "广", "峄", "獒", "铔", "奁", "醚", "倥", "蹇", "阚", "镆", "煺",
|
||||
"德", "颉",
|
||||
"嗅", "绷", "蒯", "祺", "崧", "往", "枨", "涡", "鲲", "瓅", "岌", "肘", "飔", "缘", "千", "棱", "溶",
|
||||
"窣", "篼",
|
||||
"代", "捡", "送", "咡", "术", "滑", "茜", "晾", "挤", "曳", "糈", "G", "翊", "殴", "妹", "溥", "璆",
|
||||
"烩", "拙",
|
||||
"襄", "几", "嘴", "D", "驮", "淙", "蹐", "合", "環", "剑", "怪", "褂", "畑", "燏", "订", "珪", "≥",
|
||||
"瘟", "耷",
|
||||
"槑", "衷", "猕", "迁", "霎", "槜", "﹖", "鋈", "苹", "嫣", "祜", "李", "鄒", "噢", "萄", "仝", "纨",
|
||||
"直", "悛",
|
||||
"拣", "远", "诏", "圧", "躬", "蝟", "總", "眆", "筻", "硇", "鳁", "眠", "钆", "泞", "猱", "宾", "酞",
|
||||
"募", "螳",
|
||||
"腴", "念", "宠", "唯", "怊", "勃", "M", "兿", "蟑", "妁", "掸", "拌", "铸", "讼", "诟", "锺", "Ω",
|
||||
"竟", "羚",
|
||||
"剽", "C", "苦", "煳", "罢", "跨", "~", "豸", "±", "俬", "捺", "彦", "钣", "鋆", "用", "缤", "搁",
|
||||
"徼", "谦",
|
||||
"筘", "嗨", "扮", "旇", "折", "咯", "昆", "叟", "垂", "箐", "捻", "燕", "島", "瞀", "鮮", "屡", "點",
|
||||
"瘭", "恚",
|
||||
"旚", "丟", "捽", "菁", "瀑", "炕", "蹩", "芒", "r", "是", "媾", "鹝", "囵", "萤", "拷", "频", "埴",
|
||||
"课", "癍",
|
||||
"袱", "螯", "谘", "榛", "Y", "缣", "裔", "憩", "相", "觀", "晗", "坳", "炔", "勉", "汆", "钡", "舐",
|
||||
"衫", "疫",
|
||||
"鲙", "蘩", "穈", "殁", "九", "泻", "咤", "構", "谆", "陕", "装", "蔡", "画", "介", "苋", "務", "敝",
|
||||
"俟", "帇",
|
||||
"鸺", "贸", "茗", "肃", "滪", "输", "瘗", "菽", "饹", "诉", "遐", "浑", "扎", "卟", "铀", "邗", "觋",
|
||||
"嘎", "塑",
|
||||
"潏", "金", "姘", "潋", "逵", "鲻", "逯", "炮", "甄", "髡", "剩", "嗬", "芴", "屋", "改", "骣", "芪",
|
||||
"邠", "痋",
|
||||
"珑", "帆", "狙", "八", "奔", "族", "轵", "氖", "雕", "痧", "眊", "胛", "酉", "鲼", "砣", "猸", "餮",
|
||||
"郇", "沫",
|
||||
"跖", "蝉", "屑", "辘", "閣", "涑", "邡", "篃", "交", "笼", "颇", "贻", "魄", "黡", "劂", "糠", "炅",
|
||||
"帨", "苍",
|
||||
"瓴", "粤", "莎", "朿", "埔", "绸", "齁", "鱿", "惨", "腢", "郡", "棠", "猫", "脑", "風", "蚱", "捐",
|
||||
"嵌", "胱",
|
||||
"馗", "竽", "泥", "辍", "怖", "雾", "絮", "淼", "筝", "碲", "悼", "龀", "の", "珥", "忐", "溲", "昕",
|
||||
"荔", "掂",
|
||||
"瘦", "僭", "蔌", "抺", "椅", "誉", "扯", "僜", "停", "衉", "汇", "赔", "眄", "呙", "咙", "剿", "次",
|
||||
"蛟", "嗓",
|
||||
"』", "汕", "詈", "帘", "踧", "姁", "血", "堪", "喜", "滩", "璎", "胄", "俨", "眚", "凌", "拽", "滔",
|
||||
"⑿", "嬃",
|
||||
"―", "汐", "潭", "阡", "呓", "婷", "执", "妊", "恂", "妥", "鳘", "蔫", "设", "睒", "笪", "謇", "鞋",
|
||||
"谍", "黯",
|
||||
"虍", "馬", "蚧", "骑", "峤", "舾", "儀", "駡", "β", "蓑", "柏", "痒", "蒇", "痕", "妍", "熠", "僻",
|
||||
"爬", "迭",
|
||||
"畫", "绰", "湯", "凭", "菼", "懈", "顒", "午", "箪", "糙", "址", "钼", "堵", "佘", "侍", "卤", "(",
|
||||
"榚", "泽",
|
||||
"溘", "蟹", "b", "燁", "颂", "菠", "榉", "鲡", "埸", "荛", "歘", "断", "邸", "贡", "礞", "蔼", "脸",
|
||||
"爪", "帜",
|
||||
"翡", "仟", "皎", "辆", "滫", "昔", "™", "柬", "弓", "遇", "杪", "侨", "娓", "镪", "觑", "一", "踌",
|
||||
"牟", "褡",
|
||||
"厩", "晌", "每", "娘", "渤", "c", "咫", "成", "颏", "孩", "鼓", "瞌", "槁", "捒", "阉", "伉", "癣",
|
||||
"胞", "鲟",
|
||||
"瓤", "杅", "紡", "喂", "掠", "镜", "镧", "侞", "赦", "貝", "丕", "臧", "L", "池", "彷", "棓", "锽",
|
||||
"渊", "食",
|
||||
"饨", "堡", "玥", "氣", "讽", "敬", "闺", "帡", "携", "哫", "珈", "魆", "哄", "旁", "喻", "泄", "畎",
|
||||
"郁", "唅",
|
||||
"葜", "繪", "飐", "谶", "聆", "斝", "谥", "辉", "髅", "進", "吧", "蹀", "铛", "笛", "睥", "楼", "凝",
|
||||
"況", "鸷",
|
||||
"苠", "饺", "沙", "缴", "块", "梢", "慝", "珐", "鄏", "霰", "迸", "氆", "趵", "棣", "鳔", "祆", "☆",
|
||||
"苯", "恁",
|
||||
"螨", "庭", "缠", "槠", "津", "髋", "诔", "葶", "蜾", "坻", "蒹", "摔", "向", "垩", "蹭", "淇", "筛",
|
||||
"滬", "玡",
|
||||
"铺", "逼", "劵", "绲", "团", "鳀", "常", "玖", "擢", "株", "铵", "樽", "弭", "醇", "糨", "璈", "曩",
|
||||
"潔", "祘",
|
||||
"磨", "希", "鲅", "擂", "谗", "唳", "欷", "欧", "绋", "庙", "琬", "稳", "糊", "拥", "霪", "浼", "翎",
|
||||
"俜", "摸",
|
||||
"筚", "巯", "墼", "苫", "缩", "镚", "婪", "圹", "咚", "儿", "蒽", "婆", "鲐", "雹", "霞", "嶪", "濠",
|
||||
"琉", "澌",
|
||||
"媢", "禤", "摺", "掏", "矢", "艄", "围", "呸", "寺", "拤", "氐", "柝", "跎", "僖", "挢", "茨", "涮",
|
||||
"缫", "撸",
|
||||
"荨", "嶷", "廋", "魋", "付", "喋", "蜗", "邙", "棹", "璪", "倡", "鞭", "游", "錦", "眬", "抒", "眈",
|
||||
"培", "夏",
|
||||
"黔", "獐", "皋", "戛", "鲀", "垒", "耽", "纤", "漩", "铈", "握", "窝", "芋", "濞", "截", "零", "敖",
|
||||
"眸", "怦",
|
||||
"噎", "簋", "掳", "妣", "湃", "璠", "殄", "觞", "桅", "笋", "鲞", "踯", "傀", "犨", "抵", "疰", "暌",
|
||||
"耖", "供",
|
||||
"枳", "怂", "娶", "鸩", "捣", "庸", "逡", "懋", "颃", "長", "鼫", "姮", "蹈", "耵", "乂", "骐", "殇",
|
||||
"膏", "仳",
|
||||
"冥", "梭", "洵", "碣", "昝", "仉", "軒", "隍", "更", "な", "嵕", "拜", "粑", "鲴", "吇", "秃", "尕",
|
||||
"魃", "狨",
|
||||
"臛", "蟥", "胨", "注", "谁", "张", "才", "尸", "派", "矮", "洳", "舟", "溺", "锴", "寓", "籴", "夕",
|
||||
"叭", "荠",
|
||||
"澼", "劃", "久", "私", "炉", "娟", "麤", "稂", "河", "纴", "夺", "亏", "焙", "。", "塗", "蜩", "栌",
|
||||
"渡", "薰",
|
||||
"崋", "揿", "漤", "啾", "郏", "舣", "卉", "爱", "牚", "撵", "钺", "再", "企", "笺", "疾", "承", "俾",
|
||||
"瞈", "邰",
|
||||
"汾", "瘛", "檫", "蒎", "觅", "绀", "掎", "U", "赓", "匳", "聘", "蛤", "跤", "嗜", "洼", "歔", "弟",
|
||||
"飕", "莼",
|
||||
"嫉", "那", "滈", "践", "僦", "偎", "扢", "绚", "乕", "旳", "招", "饯", "®", "攸", "鞁", "囫", "铨",
|
||||
"陒", "鷄",
|
||||
"畀", "韨", "經", "纾", "萸", "肴", "→", "宗", "迳", "鳞", "亚", "搂", "喀", "狮", "坦", "瞥", "采",
|
||||
"姝", "钳",
|
||||
"□", "剌", "維", "葸", "鼩", "公", "刀", "沩", "喔", "泺", "哉", "徨", "篝", "掊", "沕", "运", "偆",
|
||||
"浒", "语",
|
||||
"乇", "仪", "萝", "疍", "踽", "碡", "熰", "荞", "嚓", "天", "饰", "泵", "械", "孑", "蛰", "荟", "源",
|
||||
"峡", "矜",
|
||||
"睬", "噬", "腆", "婉", "‘", "等", "誓", "辀", "岖", "琖", "碜", "霍", "怼", "唛", "弈", "淑", "疆",
|
||||
"晴", "镴",
|
||||
"鸡", "埚", "焕", "芦", "唻", "踅", "吴", "殡", "唏", "吨", "寡", "鹉", "絲", "坉", "會", "埭", "Ⅲ",
|
||||
"捏", "墅",
|
||||
"卓", "叙", "徇", "柜", "各", "荭", "J", "恝", "囐", "蓉", "犋", "叡", "莺", "颌", "蒸", "饸", "疋",
|
||||
"玊", "兢",
|
||||
"鱽", "藍", "杳", "辂", "獘", "拔", "侪", "湍", "膂", "渔", "瘊", "雉", "稁", "職", "僤", "鄳", "祁",
|
||||
"稱", "I",
|
||||
"裴", "锉", "曹", "鲶", "挨", "哑", "鷪", "鏠", "煞", "师", "蛲", "牁", "琅", "告", "媒", "祭", "确",
|
||||
"荚", "亰",
|
||||
"蝗", "阗", "歩", "疲", "f", "唣", "愛", "郾", "棍", "山", "狲", "纽", "蚡", "栂", "馓", "诊", "猴",
|
||||
"喤", "来",
|
||||
"继", "桎", "嬛", "骞", "邴", "暄", "贼", "昴", "廿", "克", "耔", "彤", "鹭", "葓", "骢", "龁", "鏡",
|
||||
"瀚", "赅",
|
||||
"韩", "譄", "榷", "殚", "膛", "须", "、", "砖", "唶", "番", "蛘", "畴", "铠", "亢", "氓", "铰", "炻",
|
||||
"筫", "迢",
|
||||
"兰", "玺", "砻", "积", "莜", "吸", "监", "膦", "迪", "迷", "冷", "哀", "贳", "瞄", "器", "鹡", "惺",
|
||||
"徐", "酢",
|
||||
"寒", "Ⓡ", "倾", "飞", "楽", "涢", "队", "舆", "赤", "璩", "戳", "殳", "掮", "舴", "蜷", "宄", "拴",
|
||||
"癌", "舛",
|
||||
"婀", "抟", "靡", "骍", "揸", "思", "慧", "平", "橘", "臭", "硖", "卬", "畈", "兠", "茸", "脂", "魚",
|
||||
"晩", "御",
|
||||
"龋", "涣", "罨", "爍", "糌", "汧", "缐", "贽", "要", "祀", "鲊", "爼", "獯", "瀣", "棋", "肈", "佣",
|
||||
"娣", "柩",
|
||||
"枸", "偃", "v", "唷", "劍", "榴", "槐", "漫", "洽", "蒡", "籼", "魔", "峋", "第", "歙", "萧", "谮",
|
||||
"埯", "撮",
|
||||
"马", "绡", "裘", "鹋", "蓬", "显", "噶", "倒", "镳", "艽", "窬", "拳", "樯", "跋", "詹", "钥", "心",
|
||||
"嶽", "嚋",
|
||||
"戎", "吕", "涂", "悃", "麦", "骋", "推", "箩", "硚", "匆", "村", "五", "杨", "凑", "鞫", "镰", "伥",
|
||||
"诒", "纣",
|
||||
"崃", "鸻", "翰", "辌", "廛", "證", "舢", "盼", "腿", "圳", "贱", "皿", "隆", "屈", "龏", "瓒", "顏",
|
||||
"↓", "赈",
|
||||
"煙", "窍", "韧", "壁", "莰", "箬", "蹋", "褰", "峥", "悚", "坜", "环", "回", "疼", "渍", "蝄", "东",
|
||||
"臂", "坩",
|
||||
"走", "痍", "或", "蜀", "熳", "蜻", "佐", "懿", "嚅", "紗", "螭", "忖", "顶", "狡", "吲", "洣", "帛",
|
||||
"呶", "柞",
|
||||
"柫", "酿", "粥", "琢", "呵", "踝", "榀", "呲", "價", "鼋", "欺", "此", "背", "猎", "昱", "濡", "稚",
|
||||
"欠", "暇",
|
||||
"茬", "牙", "迹", "尼", "氛", "膠", "缯", "娼", "骚", "姒", "鬟", "霁", "鲔", "者", "驰", "倩", "馉",
|
||||
"工", "芬",
|
||||
"烙", "卦", "C", "裂", "垲", "摆", "珮", "缏", "杞", "绘", "司", "如", "姞", "荆", "挖", "跗", "伍",
|
||||
"氚", "钘",
|
||||
"郢", "轱", "篆", "吭", "夡", "鹫", "讷", "轺", "!", "匈", "待", "聱", "黏", "海", "蹶", "趋", "鎮",
|
||||
"觊", "江",
|
||||
"咸", "富", "艴", "稗", "钜", "搏", "壶", "鲮", "薪", "猞", "轰", "踪", "赣", "循", "序", "噻", "若",
|
||||
"裾", "许",
|
||||
"癞", "吓", "判", "踔", "查", "蚀", "[", "樓", "坌", "岳", "榄", "役", "倜", "⒂", "旭", "溆", "惯",
|
||||
"咀", "跫",
|
||||
"选", "囱", "污", "镶", "⒁", "淠", "氮", "酯", "寅", "芼", "炊", "夯", "郪", "农", "褲", "嘬", "蹻",
|
||||
"烔", "罄",
|
||||
"开", "靴", "镇", "杯", "羰", "硪", "籍", "摘", "馀", "餐", "眯", "⑴", "呗", "巫", "幤", "蒤", "蒗",
|
||||
"镥", "檵",
|
||||
"盛", "純", "娃", "●", "耿", "巡", "婴", "槔", "i", "颊", "Ⅳ", "栅", "绅", "邘", "冉", "碧", "使",
|
||||
"熨", "羞",
|
||||
"扼", "漳", "觯", "楊", "励", "逑", "咄", "之", "斤", "嘣", "鹰", "媸", "鲂", "褚", "磚", "琨", "聪",
|
||||
"牖", "太",
|
||||
"蓍", "涫", "≤", "虽", "鸽", "燧", "褊", "聿", "壬", "然", "疚", "莲", "悴", "簃", "颓", "坠", "瞬",
|
||||
"汳", "l",
|
||||
"登", "瘼", "窳", "桤", "縯", "匣", "坡", "↑", "愦", "攘", "渭", "嬢", "鲰", "性", "楚", "澈", "赪",
|
||||
"達", "鄯",
|
||||
"罅", "帽", "茠", "底", "嫜", "奏", "浅", "荽", "楹", "鼍", "枵", "嗔", "滍", "椴", "嵩", "氤", "搠",
|
||||
"两", "榔",
|
||||
"树", "吝", "基", "峂", "栎", "侮", "舸", "遂", "颡", "锷", "杼", "酔", "幄", "哽", "睢", "陔", "※",
|
||||
"嚆", "宬",
|
||||
"宽", "髦", "笾", "保", "蹊", "榕", "咏", "椋", "丧", "裤", "骛", "逧", "弇", "崆", "樘", "疤", "鸤",
|
||||
"伞", "抚",
|
||||
"诎", "诵", "豢", "佳", "差", "埝", "极", "黍", "煜", "曰", "阱", "悞", "叹", "垤", "藁", "嗵", "崔",
|
||||
"卫", "珂",
|
||||
"憯", "蔬", "菜", "碑", "扈", "铆", "夹", "衡", "弱", "挈", "徜", "疠", "丶", "遠", "提", "斧", "炟",
|
||||
"肺", "B",
|
||||
"她", "晟", "谎", "邱", "粳", "酽", "爨", "鬼", "伧", "兹", "嶓", "谤", "饕", "揶", "谱", "歡", "髪",
|
||||
"餍", "泳",
|
||||
"郞", "谣", "汉", "褐", "非", "刽", "缅", "饴", "齐", "兴", "涯", "芫", "凡", "褶", "晡", "努", "蚶",
|
||||
"彥", "皤",
|
||||
"砌", "黼", "吹", "指", "㙟", "蓁", "鹜", "話", "拊", "辨", "盎", "肌", "旘", "软", "颍", "甏", "滚",
|
||||
"旦", "滨",
|
||||
"间", "尴", "对", "鄘", "称", "镗", "咅", "璐", "怔", "垛", "洎", "瓮", "绨", "脚", "遒", "吊", "纸",
|
||||
"蹅", "经",
|
||||
"泉", "武", "汀", "歪", "败", "拾", "铪", "吼", "邹", "磊", "论", "岛", "厍", "锛", "芎", "芭", "音",
|
||||
"澧", "镕",
|
||||
"锒", "宙", "牵", "忱", "嫔", "麯", "澉", "擐", "砥", "撞", "痴", "盹", "畿", "厾", "酸", "俑", "脽",
|
||||
"鸈", "枷",
|
||||
"咨", "蔹", "诂", "胰", "董", "脶", "黩", "髓", "鉵", "澎", "鲽", "梧", "樱", "诜", "鲯", "跂", "盂",
|
||||
"浴", "苻",
|
||||
"锅", "實", "碁", "嘛", "氕", "艮", "涟", "绢", "姿", "茝", "砘", "簿", "穷", "镃", "∈", "抽", "事",
|
||||
"誜", "窅",
|
||||
"瀘", "鲹", "兖", "嵎", "陧", "榍", "轶", "柿", "藤", "薏", "娆", "骷", "梅", "摒", "睪", "剪", "羸",
|
||||
"忧", "邝",
|
||||
"跺", "旆", "堕", "伫", "绍", "疵", "樟", "–", "绾", "蜴", "靸", "侃", "瘘", "珧", "遨", "縠", "信",
|
||||
"充", "桔",
|
||||
"黇", "劬", "脒", "良", "俵", "颙", "轹", "犿", "屐", "牾", "4", "兮", "澝", "汗", "沼", "铲", "濋",
|
||||
"鹬", "丝",
|
||||
"妫", "重", "蒺", "磲", "曚", "尔", "国", "桐", "俣", "剐", "哼", "恹", "哧", "藔", "谓", "轨", "眩",
|
||||
"痞", "添",
|
||||
"鬯", "库", "梱", "婕", "蜢", "贿", "敕", "泯", "羟", "龇", "垸", "左", "肖", "辎", "鞣", "谄", "可",
|
||||
"腺", "末",
|
||||
"狞", "贷", "嗌", "仕", "楞", "膻", "臻", "欻", "洲", "所", "檀", "抔", "罹", "牒", "仫", "芨", "柄",
|
||||
"嫩", "酒",
|
||||
"祙", "渠", "的", "笨", "鳐", "楡", "过", "苡", "核", "拖", "阢", "莒", "凤", "锋", "` + "`" + `", "硎", "弁",
|
||||
"鬶", "朐",
|
||||
"忏", "於", "昊", "剟", "咳", "湘", "日", "满", "哨", "螵", "餪", "放", "佶", "葵", "硷", "c", "抱",
|
||||
"锥", "芮",
|
||||
"啻", "惊", "峁", "琊", "嶲", "撺", "煅", "屏", "袗", "鄞", "梓", "鹌", "宅", "赂", "鱼", "洱", "騳",
|
||||
"E", "物",
|
||||
"觏", "雙", "瑀", "上", "淩", "愀", "❋", "鄙", "憝", "沛", "硫", "产", "垯", "亁", "枭", "堰", "赑",
|
||||
"趾", "庹",
|
||||
"腭", "迨", "拚", "晒", "蜇", "扣", "纰", "闵", "窭", "椽", "菏", "嘁", "伛", "郸", "素", "殷", "表",
|
||||
"躞", "笸",
|
||||
"耻", "荧", "辛", "篑", "馈", "壮", "耩", "宛", "慰", "盡", "塆", "铯", "苏", "王", "桕", "⑧", "°",
|
||||
"浚", "栉",
|
||||
"朘", "虚", "骆", "坂", "秤", "鲋", "蕊", "渝", "呦", "潼", "驱", "诼", "峇", "盤", "趴", "肄", "笑",
|
||||
"讹", "貋",
|
||||
"穂", "啼", "趟", "暽", "傣", "蜎", "挎", "陳", "勖", "戴", "旃", "瞎", "舌", "幻", "喾", "赁", "E",
|
||||
"播", "诀",
|
||||
"蟛", "鹛", "骶", "輸", "連", "醳", "逅", "奉", "崖", "娩", "幔", "佃", "扅", "阔", "生", "贬", "疯",
|
||||
"珀", "苶",
|
||||
"屯", "裣", "蹯", "蝮", "解", "陂", "疝", "茈", "帑", "议", "仲", "埙", "竺", "峰", "遮", "涎", "穸",
|
||||
"阂", "潵",
|
||||
"镱", "例", "荑", "u", "脎", "衍", "轲", "⑵", "虾", "颚", "钞", "²", "伴", "根", "沣", "腌", "户",
|
||||
"~", "辙",
|
||||
"愧", "噤", "觥", "波", "铗", "纂", "鲺", "僚", "毐", "〇", "桼", "祗", "慢", "啵", "坏", "吗", "嗞",
|
||||
"甬", "曈",
|
||||
"徹", "灏", "混", "渌", "括", "脖", "汝", "現", "訇", "紅", "飘", "虢", "腱", "旄", "嬴", "昨", "孀",
|
||||
"蚁", "呛",
|
||||
"讳", "病", ",", "喈", "蒋", "镭", "葩", "耲", "鳈", "锄", "喘", "返", "傕", "咆", "享", "枥", "瓠",
|
||||
"茳", "铱",
|
||||
"脘", "暹", "廒", "爝", "橹", "瞑", "铎", "岢", "叁", "翏", "捭", "賀", "悉", "帝", "芥", "牀", "闌",
|
||||
"毯", "亍",
|
||||
"弧", "锆", "币", "祊", "纔", "齑", "肟", "绤", "獨", "翚", "颢", "係", "鍪", "粉", "统", "诗", "娜",
|
||||
"褥", "鈺",
|
||||
"湔", "呤", "犸", "湨", "泣", "蟾", "犾", "烛", "斐", "朦", "室", "诨", "榭", "煦", "醺", "敞", "燮",
|
||||
"糅", "衽",
|
||||
"孔", "猄", "疭", "辰", "钽", "胁", "釆", "钉", "胤", "涧", "弼", "濯", "汨", "颖", "茫", "皑", "遏",
|
||||
"捃", "坭",
|
||||
"燴", "肩", "滞", "玢", "巽", "砺", "蜿", "毁", "億", "骥", "本", "忽", "肚", "搽", "靰", "郴", "跆",
|
||||
"客", "酣",
|
||||
"α", "屎", "辩", "殂", "垝", "紫", "秦", "喇", "凶", "傧", "铐", "蘊", "補", "贤", "竿", "途", "慗",
|
||||
"榖", "券",
|
||||
"莠", "逆", "鳇", "误", "崟", "妇", "磷", "捧", "莸", "⇋", "绺", "稻", "填", "逋", "侈", "隶", "侵",
|
||||
"翥", "惘",
|
||||
"惧", "鸥", "赠", "壳", "芯", "巩", "獗", "硅", "搎", "鲛", "9", "夸", "穆", "缜", "诓", "观", "薛",
|
||||
"咎", "杧",
|
||||
"页", "饫", "瑟", "率", "礤", "悭", "畔", "匯", "匮", "鼠", "犒", "芡", "傍", "嫂", "啸", "鄉", "哭",
|
||||
"鄱", "捷",
|
||||
"靺", "嚒", "嘀", "哒", "#", "拼", "钚", "魁", "霣", "眶", "郊", "死", "愁", "箭", "鼙", "签", "害",
|
||||
"斛", "睑",
|
||||
"蟜", "余", "墨", "様", "读", "養", "貉", "较", "浆", "翩", "徂", "冕", "铧", "列", "诈", "穝", "缑",
|
||||
"纲", "志",
|
||||
"舀", "甾", "举", "馁", "ä", "畹", "榼", "垢", "襁", "麟", "灭", "佴", "镩", "酝", "柒", "梯", "傈",
|
||||
"萭", "悫",
|
||||
"莨", "搞", "+", "兄", "偲", "攀", "曝", "嵝", "喳", "从", "遶", "撴", ".", "鄄", "欲", "挺", "娡",
|
||||
"发", "速",
|
||||
"胲", "褀", "态", "行", "蚓", "坼", "适", "厦", "寐", "带", "緃", "醤", "珽", "‧", "溍", "斋", "鐀",
|
||||
"朝", "欢",
|
||||
"传", "築", "咪", "据", "蹜", "医", "妄", "肇", "囝", "怡", "镎", "桩", "轩", "岔", "腐", "矽", "媵",
|
||||
"搒", "菔",
|
||||
"拘", "D", "欃", "唧", "瞒", "郈", "绦", "吟", "撝", "醉", "镣", "匝", "拎", "砒", "顸", "袁", "驼",
|
||||
"愔", "实",
|
||||
"國", "奧", "胩", "府", "逾", "愕", "廷", "碌", "锖", "狩", "褴", "镢", "芷", "娥", "唤", "┌", "云",
|
||||
"О", "檔",
|
||||
"驴", "躯", "驺", "洃", "檑", "窴", "(", "腕", "立", "楯", "齮", "〔", "漆", "k", "芍", "蹽", "鬓",
|
||||
"概", "楣",
|
||||
"唐", "闲", "糗", "旱", "幸", "腽", "嗄", "迂", "镠", "顿", "扥", "圃", "烜", "馍", "佝", "岷", "童",
|
||||
"悦", "┐",
|
||||
"铌", "袈", "靓", "骸", "和", "乔", "灸", "泓", "临", "睿", "掖", "偿", "鐘", "犁", "祓", "鈴", "搌",
|
||||
"授", "鹳",
|
||||
"赢", "怅", "絪", "硬", "芙", "螅", "”", "傢", "避", "裕", "歁", "全", "衰", "仃", "媛", "鬻", "跽",
|
||||
"沌", "急",
|
||||
"猷", "激", "巉", "哝", "渣", "笫", "跳", "螫", "熜", "Z", "筷", "佩", "啶", "萃", "頫", "荙", "出",
|
||||
"孽", "钟",
|
||||
"戡", "釉", "咬", "滦", "鹇", "贯", "鹮", "具", "翁", "机", "濱", "谳", "釣", "懑", "葛", "袯", "谭",
|
||||
"质", "胴",
|
||||
"誊", "侗", "⑩", "静", "蚜", "溋", "嫪", "嗲", "瑭", "座", "舫", "靶", "棘", "泊", "嵖", "摧", "勋",
|
||||
"僡", "藉",
|
||||
"疖", "巂", "随", "罾", "崚", "猹", "憨", "苘", "斓", "鼷", "利", "谲", "剔", "艺", "箓", "蛀", "鲚",
|
||||
"搐", "裟",
|
||||
"捶", "绌", "揪", "帮", "缥", "匍", "冀", "杻", "逛", "邑", "禾", "郰", "黜", "丘", "樂", "滌", "緣",
|
||||
"胃", "苄",
|
||||
"巾", "瑜", "元", "蝶", "层", "烧", "级", "岭", "蘭", "繇", "蝓", "洞", "奢", "则", "政", "矾", "啭",
|
||||
"瘠", "碴",
|
||||
"忤", "身", "匠", "警", "饩", "犬", "皲", "箔", "豕", "虑", "草", "喟", "芤", "逭", "艳", "幡", "姚",
|
||||
"賓", "饪",
|
||||
"卯", "敌", "烽", "嫚", "黝", "豺", "㭗", "教", "偕", "板", "茹", "孤", "人", "狻", "寰", "厕", "玲",
|
||||
"璨", "锵",
|
||||
"搛", "勍", "匾", "聃", "奘", "垃", "焓", "喽", "嫫", "貌", "瘐", "嚰", "孟", "衔", "郎", "账", "础",
|
||||
"电", "黑",
|
||||
"骁", "拨", "濆", "圉", "刮", "闭", "竣", "铅", "羔", "硌", "筑", "难", "管", "苕", "眺", "嫄", "竖",
|
||||
"榟", "崴",
|
||||
"摭", "狐", "娑", "②", "罽", "谊", "←", "狳", "铫", "凯", "狉", "9", "肪", "崤", "莊", "妨", "缶",
|
||||
"滃", "瀦",
|
||||
"揉", "肫", "恧", "糯", "嵬", "5", "裆", "嚷", "稣", "隐", "仂", "て", "驹", "籽", "肢", "尘", "苈",
|
||||
"撷", "镲",
|
||||
"趹", "晤", "唱", "鉏", "篌", "驩", "雍", "闳", "拄", "藜", "朴", "伺", "诳", "房", "吱", "Й", "鳄",
|
||||
"罿", "祧",
|
||||
"酩", "郅", "耎", "尜", "绝", "禅", "揠", "鎏", "慕", "麥", "呜", "鸫", "党", "尝", "砑", "牌", "踉",
|
||||
"刨", "襻",
|
||||
"㾄", "螽", "谌", "止", "抑", "爻", "磬", "铄", "蓠", "委", "汲", "鹑", "╱", "嚣", "彝", "穄", "穹",
|
||||
"態", "醋",
|
||||
"⒀", "叼", "婳", "簌", "渥", "很", "甸", "帅", "锏", "与", "樾", "泷", "棼", "湲", "越", "祥", "短",
|
||||
"顼", "阘",
|
||||
"宋", "馘", "鈉", "未", "囍", "浏", "叻", "箜", "鑽", "法", "曲", "淤", "僮", "做", "强", "析", "磕",
|
||||
"谠", "染",
|
||||
"促", "朊", "隼", "铉", "莆", "蝣", "孛", "薮", "s", "惴", "秘", "妩", "訄", "蔓", "喷", "诡", "犷",
|
||||
"酐", "酇",
|
||||
"刹", "壅", "甫", "史", "孃", "髌", "螬", "擤", "漏", "寞", "奡", "悢", "颔", "岁", "耄", ";", "又",
|
||||
"锭", "鲤",
|
||||
"癔", "杰", "孥", "酲", "蓐", "耋", "捆", "庖", "面", "鹈", "殊", "剡", "峪", "识", "锨", "归", "茴",
|
||||
"—", "菤",
|
||||
"汁", "攝", "液", "鼐", "示", "讠", "男", "凍", "ò", "明", "莓", "砜", "崎", "蜂", "斡", "榫", "娅",
|
||||
"钪", "昙",
|
||||
"胜", "欣", "怨", "◆", "粗", "秷", "节", "市", "贩", "祟", "弍", "蒟", "烁", "糧", "蠃", "編", "黙",
|
||||
"壕", "戚",
|
||||
"犊", "桥", "仺", "孳", "怯", "皓", "倆", "垮", "扩", "诮", "钝", "脯", "晏", "帔", "葫", "瑾", "運",
|
||||
"孬", "跄",
|
||||
"掣", "癜", "掌", "墀", "禇", "耸", "蜓", "鹆", "鄢", "攰", "瘢", "暝", "鸣", "峧", "遵", "笃", "畚",
|
||||
"帧", "晨",
|
||||
"镔", "搜", "靠", "咐", "韓", "绮", "觉", "拦", "斲", "疽", "掐", "尽", "許", "矶", "镉", "豹", "粞",
|
||||
"袋", "酵",
|
||||
"蛙", "戕", "劉", "髀", "彭", "玎", "囿", "郐", "善", "睃", "結", "拧", "邯", "讧", "召", "椭", "瑪",
|
||||
"痼", "庼",
|
||||
"反", "疱", "屠", "荣", "君", "胍", "乙", "臬", "头", "诰", "讪", "席", "晁", ":", "理", "槿", "璘",
|
||||
"禧", "呢",
|
||||
"蹙", "擒", "鸲", "丐", "苓", "壑", "滥", "⑾", "炗", "礴", "耕", "卅", "唿", "苛", "寵", "窖", "麻",
|
||||
"蕨", "沤",
|
||||
"氢", "虔", "癃", "及", "崛", "爽", "蛔", "颤", "膲", "桢", "坐", "蟞", "儇", "葚", "骤", "誤", "寝",
|
||||
"嘭", "灰",
|
||||
"汹", "韂", "铮", "慒", "寶", "肽", "摅", "紧", "亞", "潸", "悯", "橛", "檗", "闹", "愿", "担", "袄",
|
||||
"棚", "垟",
|
||||
"塄", "婞", "麈", "麸", "暗", "咦", "跞", "谡", "盈", "磐", "慎", "瘰", "掼", "憔", "研", "被", "贮",
|
||||
"莛", "至",
|
||||
"呀", "庑", "矫", "摛", "怃", "缙", "磺", "即", "驻", "瘤", "偏", "℃", "嫘", "癫", "汈", "鹟", "搅",
|
||||
"辅", "璀",
|
||||
"阊", "绻", "瑙", "蓂", "棺", "孢", "铊", "鼒", "果", "砮", "飾", "凰", "Я", "遗", "祛", "纮", "劲",
|
||||
"霹", "骃",
|
||||
"绔", "薅", "瀵", "垅", "?", "轻", "惇", "怕", "啥", "哙", "燎", "缆", "匡", "怫", "卞", "朋", "酏",
|
||||
"阑", "爾",
|
||||
"伏", "敏", "埼", "罩", "菹", "艋", "肭", "鯭", "杋", "裀", "撬", "蕺", "惠", "大", "爇", "笈", "絷",
|
||||
"琳", "谫",
|
||||
"诛", "糇", "袢", "倓", "髃", "觽", "埏", "寖", "個", "筴", "外", "漯", "樭", "喁", "杀", "臑", "缇",
|
||||
"裸", "巅",
|
||||
"毹", "茅", "忆", "琼", "唑", "烷", "项", "隋", "约", "排", "吮", "谂", "宝", "牲", "瘫", "娄", "沂",
|
||||
"醫", "拭",
|
||||
"纺", "蹰", "哞", "风", "霆", "值", "酺", "侠", "螾", "埂", "育", "夷", "鮼", "怍", "鸠", "Θ", "瞳",
|
||||
"阇", "耥",
|
||||
"羝", "伽", "洴", "記", "楔", "颼", "沪", "邢", "冰", "昀", "阙", "洌", "嫦", "杂", "仔", "芑", "潴",
|
||||
"痄", "桨",
|
||||
"连", "碓", "塈", "F", "昇", "何", "桦", "晥", "驵", "旋", "药", "银", "奋", "灣", "俐", "絡", "嫁",
|
||||
"浮", "为",
|
||||
"鞅", "科", "颦", "潽", "镍", "鸨", "粵", "骂", "拱", "韫", "盆", "赎", "尿", "钿", "坍", "唁", "秧",
|
||||
"昌", "曆",
|
||||
"颋", "遭", "秭", "褔", "腋", "〉", "吉", "漓", "臆", "焘", "已", "制", "钹", "鴨", "咖", "莘", "P",
|
||||
"碥", "互",
|
||||
"治", "标", "膝", "伪", "浿", "纛", "郗", "看", "佧", "糖", "篓", "亡", "´", "骙", "澡", "影", "窂",
|
||||
"紬", "镅",
|
||||
"慌", "框", "晋", "説", "丢", "凹", "卖", "巧", "蹉", "乾", "莫", "Z", "谔", "矧", "铑", "暴", "庄",
|
||||
"湿", "活",
|
||||
"穿", "腩", "筣", "水", "6", "琦", "迈", "伯", "洄", "抡", "▪", "酋", "荤", "雒", "粕", "簠", "菰",
|
||||
"髁", "枇",
|
||||
"陲", "多", "仗", "央", "滁", "胸", "梏", "痉", "姑", "襞", "﹑", "齿", "弩", "花", "吆", "赫", "岵",
|
||||
"佪", "谑",
|
||||
"锤", "轴", "盐", "馄", "臜", "戢", "涠", "鸸", "糟", "孪", "禁", "蒲", "化", "疏", "痰", "脾", "刈",
|
||||
"應", "珍",
|
||||
"膺", "扌", "廙", "汜", "牍", "虐", "婿", "啕", "彻", "赝", "陶", "蠲", ">", "位", "屁", "醍", "粢",
|
||||
"挪", "臌",
|
||||
"滹", "遴", "馨", "n", "稼", "徊", "酌", "轸", "债", "朰", "程", "辞", "痊", "插", "鹩", "郄", "铝",
|
||||
"狱", "叱",
|
||||
"同", "寄", "搪", "蚯", "魭", "舍", "旷", "闰", "涝", "民", "嗡", "苌", "馕", "姥", "屉", "啧", "枢",
|
||||
"❤", "窕",
|
||||
"钊", "矬", "菂", "佑", "≠", "獬", "桁", "墟", "皖", "鼻", "它", "歇", "独", "好", "晕", "蚝", "锞",
|
||||
"颈", "豚",
|
||||
"聖", "裉", "扫", "岿", "悒", "佥", "苗", "妞", "晚", "圭", "茼", "脲", "摊", "窠", "狸", "抻", "场",
|
||||
"呼", "囟",
|
||||
"噗", "狺", "困", "瀹", "削", "衬", "谰", "蛆", "訓", "鉄", "痃", "炱", "蝻", "我", "暨", "骓", "馋",
|
||||
"埤", "脞",
|
||||
"晃", "螟", "洮", "泛", "掾", "穑", "米", "蕲", "玦", "讙", "逢", "劐", "袭", "凫", "僳", "畛", "晷",
|
||||
"鳕", "Ë",
|
||||
"愬", "坫", "鳡", "鞯", "叔", "胂", "囚", "筋", "青", "度", "涕", "琰", "﹔", "径", "陇", "睛", "链",
|
||||
"状", "逶",
|
||||
"蘅", "“", "庇", "邽", "纥", "踶", "爺", "狭", "钫", "桃", "弛", "淳", "办", "茕", "砸", "喱", "仅",
|
||||
"潞", "杈",
|
||||
"得", "咕", "俞", "检", "借", "恋", "驿", "倌", "钢", "琐", "哆", "撙", "箫", "川", "猥", "牢", "蹁",
|
||||
"城", "馏",
|
||||
"锡", "楝", "蛱", "奈", "瑶", "桺", "耆", "翟", "阒", "稲", "橐", "萱", "惹", "蘼", "主", "擦", "蟒",
|
||||
"台", "佬",
|
||||
"荫", "廖", "笏", "铕", "衣", "洇", "炒", "瀍", "崭", "圻", "洚", "契", "嫱", "倏", "晶", "了", "堠",
|
||||
"勰", "椎",
|
||||
"询", "梗", "飒", "锰", "览", "溇", "寻", "蓅", "【", "碇", "井", "露", "顔", "堌", "庳", "踩", "i",
|
||||
"饷", "俊",
|
||||
"楫", "條", "搭", "奍", "羽", "憋", "岘", "毡", "曜", "乃", "′", "针", "羲", "菓", "吩", "咩", "鞘",
|
||||
"尊", "宫",
|
||||
"舜", "啖", "惗", "北", "懊", "骇", "阄", "躅", "权", "缲", "肥", "铜", "《", "录", "也", "棬", "煮",
|
||||
"舄", "厮",
|
||||
"'", "順", "受", "霜", "新", "售", "牞", "圣", "妗", "犴", "宥", "哦", "陀", "卺", "冚", "蹒", "亸",
|
||||
"禮", "骰",
|
||||
"瑢", "弒", "抛", "谷", "嫰", "動", "嘌", "惩", "枣", "忌", "茡", "爵", "嘚", "郧", "丨", "敲", "帚",
|
||||
"沭", "槊",
|
||||
"⑶", "專", "毶", "圄", "磅", "蛭", "由", "蠹", "剜", "诫", "秆", "愠", "藓", "母", "请", "衩", "忸",
|
||||
"蜕", "饽",
|
||||
"晦", "倔", "腠", "痛", "品", "簧", "父", "锐", "描", "蓰", "蛴", "箍", "兕", "苜", "饼", "奚", "泗",
|
||||
"裥", "皂",
|
||||
"嵚", ",", "澶", "蠖", "沅", "馎", "籀", "菝", "眵", "糥", "铽", "痤", "颟", "淄", "作", "抉", "俄",
|
||||
"么", "郑",
|
||||
"耒", "佛", "1", "纡", "鸢", "④", "鎚", "壖", "遢", "鬈", "拢", "托", "哈", "節", "橦", "冼", "六",
|
||||
"耗", "樵",
|
||||
"涔", "舳", "龌", "衿", "婧", "栓", "椹", "嘘", "膊", "茁", "丹", "螃", "剖", "洧", "珞", "潺", "孱",
|
||||
"呐", "萩",
|
||||
"刷", "引", "说", "熟", "/", "靖", "酷", "耠", "饬", "菌", "洙", "荃", "饲", "酾", "阁", "陬", "铿",
|
||||
"倻", "牮",
|
||||
"鞡", "撕", "倘", "盒", "曺", "襦", "辄", "算", "塬", "潢", "羖", "湾", "续", "△", "疙", "谖", "嘅",
|
||||
"遑", "篚",
|
||||
"筮", "氍", "递", "尧", "G", "{", "分", "埒", "@", "蜍", "荼", "襆", "槭", "檠", "縢", "濉", "梆",
|
||||
"隔", "镛",
|
||||
"倞", "润", "瓯", "瓢", "蟊", "沐", "啷", "砚", "皱", "剅", "儙", "错", "幌", "滓", "砗", "郤", "喧",
|
||||
"峣", "簸",
|
||||
"毖", "踏", "锕", "…", "悖", "谧", "醵", "加", "镐", "泐", "傫", "胪", "缄", "卩", "蓼", "丸", "垌",
|
||||
"汞", "宴",
|
||||
"膙", "圊", "矻", "嚏", "漾", "幕", "駕", "葒", "绪", "袪", "镋", "杭", "澴", "鬃", "粟", "偻", "饳",
|
||||
"抨", "亟",
|
||||
"温", "韶", "轿", "罟", "际", "诖", "复", "坯", "骗", "*", "副", "裢", "憬", "邾", "崇", "蕈", "疮",
|
||||
"粽", "炝",
|
||||
"珲", "莅", "衾", "爲", "枯", "汛", "仁", "熏", "馥", "㎡", "檐", "锦", "竭", "颁", "遽", "瘙", "样",
|
||||
"遛", "殍",
|
||||
"湄", "消", "鳌", "痫", "鳏", "瓶", "窈", "谚", "麒", "鸹", "蟋", "横", "唠", "瘪", "媪", "侔", "鐵",
|
||||
"系", "杖",
|
||||
"m", "叉", "沟", "衢", "寘", "■", "弗", "建", "疣", "珣", "綦", "劈", "道", "嘈", "先", "芝", "降",
|
||||
"滕", "邵",
|
||||
"邺", "給", ")", "廨", "郛", "势", "氇", "坤", "昂", "焼", "奕", "闱", "朓", "毽", "还", "坨", "銭",
|
||||
"龂", "銎",
|
||||
"壽", "矸", "窒", "①", "玷", "蝽", "泃", "烀", "魈", "★", "慶", "K", "嘶", "酶", "呖", "殿", "乡",
|
||||
"䄂", "阳",
|
||||
"轪", "碱", "譬", "摩", "鳖", "刳", "地", "包", "貊", "悝", "圩", "今", "嚭", "凳", "谕", "馃", "捎",
|
||||
"佯", "侬",
|
||||
"愆", "微", "涤", "舔", "蛇", "筲", "助", "锾", "剧", "缧", "簪", "惚", "柢", "庾", "虹", "雪", "猡",
|
||||
"脔", "亶",
|
||||
"烨", "T", "锗", "芈", "女", "动", "偬", "琥", "县", "诣", "精", "嬗", "栀", "艨", "智", "冗", "闼",
|
||||
"嗝", "z",
|
||||
"夢", "拿", "鹲", "尤", "啮", "﹐", "ɔ", "钓", "施", "萼", "邻", "竞", "碶", "艰", "》", "翻", "馆",
|
||||
"橪", "逝",
|
||||
"臀", "淫", "枉", "羿", "拇", "溷", "徒", "涓", "關", "聋", "嵊", "殖", "叛", "敫", "舵", "亊", "诽",
|
||||
"菱", "苎",
|
||||
"破", "腚", "A", "嵋", "扊", "挂", "篷", "棂", "碟", "復", "劾", "韪", "疔", "粒", "鲵", "毙", "店",
|
||||
"锻", "衮",
|
||||
"寳", "◎", "斯", "倦", "醢", "曾", "茚", "荐", "隗", "芊", "豪", "亻", "哂", "堃", "宇", "桑", "匋",
|
||||
"植", "亥",
|
||||
"撂", "棒", "蟠", "W", "迟", "蚋", "溊", "缌", "鞚", "蚤", "適", "赌", "卣", "厚", "鲾", "匙", "槃",
|
||||
"郎", "鬏",
|
||||
"玳", "龄", "丈", "圮", "冑", "院", "葬", "嵐", "瓦", "孵", "漶", "星", "吐", "獍", "藠", "萍", "振",
|
||||
"潜", "龉",
|
||||
"匦", "粹", "諾", "畵", "峦", "&", "埕", "朵", "戒", "炳", "酪", "绂", "篁", "测", "殆", "涌", "业",
|
||||
"盏", "醊",
|
||||
"笆", "孰", "骊", "湛", "踰", "汎", "哲", "澙", "鲷", "√", "鄣", "亿", "螺", "吠", "伟", "凛", "骡",
|
||||
"恻", "巨",
|
||||
"扶", "泡", "峯", "韵", "腎", "睦", "栖", "}", "笙", "疌", "绶", "忒", "哥", "价", "纻", "薨", "漂",
|
||||
"濮", "缮",
|
||||
"勐", "妮", "傩", "陛", "陷", "柆", "瞭", "鲳", "烬", "喉", "固", "桡", "聊", "逦", "猊", "梻", "涵",
|
||||
"栒", "逍",
|
||||
"饥", "凼", "早", "姣", "蕤", "塌", "桀", "亳", "虻", "鹨", "典", "情", "怄", "商", "钍", "赚", "塥",
|
||||
"煽", "垱",
|
||||
"蝴", "乓", "籁", "帷", "锢", "圪", "快", "赘", "杵", "漠", "滴", "斩", "拈", "蚕", "陽", "篡", "郦",
|
||||
"瞻", "郯",
|
||||
"鳍", "幽", "旅", "乖", "鹖", "斫", "痂", "肸", "右", "锂", "永", "泾", "茎", "觱", "彼", "擎", "䨱",
|
||||
"翱", "徝",
|
||||
"醅", "求", "湫", "転", "溴", "師", "瓣", "蝠", "铭", "社", "苞", "仇", "噌", "你", "嗾", "雳", "榧",
|
||||
"駹", "雯",
|
||||
"叨", "遫", "氏", "航", "辗", "溢", "历", "楷", "诱", "雏", "梳", "藕", "屺", "槎", "钐", "燘", "棽",
|
||||
"驸", "褪",
|
||||
"清", "十", "廰", "移", "筌", "揾", "瞠", "姽", "馑", "恢", "逸", "p", "瑚", "茄", "鹧", "俗", "璟",
|
||||
"栊", "买",
|
||||
"瀛", "镒", "球", "氲", "缛", "講", "胀", "焒", "悲", "翕", "拗", "T", "桌", "脓", "闪", "稀", "狎",
|
||||
"火", "柁",
|
||||
"琴", "澍", "嗟", "龚", "楮", "噼", "隽", "栩", "焻", "哩", "藻", "瘸", "含", "偶", "界", "嘃", "昶",
|
||||
"澄", "頤",
|
||||
"绒", "鲁", "麝", "决", "撒", "岙", "季", "刿", "肝", "蒉", "蓇", "财", "完", "蠔", "脉", "肱", "谙",
|
||||
"蜮", "郭",
|
||||
"慨", "晔", "髂", "蛏", "眨", "钗", "葺", "惆", "娈", "瞵", "踞", "棁", "蝢", "嚎", "猝", "必", "剞",
|
||||
"关", "咛",
|
||||
"劫", "闸", "肯", "№", "莩", "哇", "蛑", "镬", "羡", "驊", "茂", "塍", "沓", "筱", "杉", "战", "茧",
|
||||
"耙", "击",
|
||||
"需", "腊", "酎", "畦", "葙", "鹘", "韭", "嚚", "争", "域", "伢", "鞲", "哳", "栲", "某", "翌", "哗",
|
||||
"焚", "螗",
|
||||
"懲", "躲", "約", "镖", "凿", "饶", "够", "剁", "铥", "应", "署", "杮", "蒂", " ", "坷", "礅", "款",
|
||||
"梁", "鄜",
|
||||
"髹", "選", "伤", "路", "З", "亲", "野", "啦", "捯", "憷", "鲩", "札", "怏", "塘", "绊", "愍", "簦",
|
||||
"牦", "黥",
|
||||
"鳜", "唉", "W", "沱", "蚺", "甪", "摉", "协", "耨", "娱", "桄", "仆", "类", "搡", "滤", "岗", "休",
|
||||
"坶", "谒",
|
||||
"忭", "飨", "闷", "菟", "鲣", "驷", "湜", "疡", "蚩", "萊", "䝉", "硒", "贺", "弃", "徘", "陨", "否",
|
||||
"遥", "妒",
|
||||
"X", "間", "觜", "跬", "夬", "羮", "喙", "赇", "鹗", "『", "砀", "残", "绿", "小", "勘", "瀌", "扉",
|
||||
"耧", "衅",
|
||||
"挟", "乐", "鹏", "墁", "澜", "噍", "坊", "術", "嗖", "知", "盉", "圆", "嗈", "蘖", "资", "爭", "=",
|
||||
"刑", "裒",
|
||||
"〈", "淸", "定", "袒", "戗", "钤", "吵", "旯", "蓝", "裎", "溅", "贰", "荏", "甥", "悌", "勤", "炽",
|
||||
"换", "躜",
|
||||
"!", "薄", "痱", "双", "匕", "肷", "挥", "茑", "船", "砝", "煤", "荜", "弘", "▏", "陆", "稔", "朽",
|
||||
"冤", "頉",
|
||||
"遊", "砰", "迎", "碎", "唪", "醪", "稆", "练", "锸", "阵", "皇", "香", "镀", "嫡", "持", "桶", "垄",
|
||||
"阍", "戥",
|
||||
"臣", "琛", "涘", "惶", "赙", "葆", "住", "舊", "枝", "媲", "蓣", "龅", "搦", "_", "图", "力", "纪",
|
||||
"悍", "麗",
|
||||
"戽", "腧", "绣", "跟", "哕", "打", "蝰", "Φ", "吞", "功", "夀", "劓", "沇", "熔", "占", "隰", "命",
|
||||
"佻", "豁",
|
||||
"苣", "楦", "掇", "蛛", "唢", "郜", "霉", "鲏", "予", "沸", "殻", "俯", "探", "篪", "荇", "邈", "烯",
|
||||
"忮", "伸",
|
||||
"岬", "×", "锧", "窸", "毪", "纩", "蛋", "讯", "骼", "叶", "楂", "犟", "站", "盘", "隈", "喝", "儣",
|
||||
"兵", "尚",
|
||||
"孙", "爿", "芜", "羁", "旖", "溽", "迩", "京", "7", "龃", "狝", "缦", "缁", "鲃", "怒", "故", "據",
|
||||
"枫", "髙",
|
||||
"亭", "耳", "飚", "O", "编", "箸", "幼", "氘", "鞮", "匐", "祯", "臃", "辫", "磋", "溝", "墙", "诚",
|
||||
"阻", "档",
|
||||
"歆", "璃", "悻", "婤", "映", "瑞", "牂", "话", "忠", "潘", "惋", "冬", "氦", "腔", "胬", "盔", "\"",
|
||||
"饮", "贶",
|
||||
"嚄", "儆", "溜", "砷", "樇", "跏", "泩", "馌", "埃", "莙", "革", "珙", "乌", "鍋", "穴", "石", "珺",
|
||||
"熹", "诞",
|
||||
"<", "腉", "姊", "钧", "罪", "拆", "赊", "殒", "堇", "仑", "掺", "塃", "獴", "迥", "盦", "檬", "益",
|
||||
"居", "鼑",
|
||||
"异", "嘻", "悔", "旮", "况", "時", "阋", "洛", "線", "#", "型", "迕", "睇", "橱", "笊", "蛞", "愚",
|
||||
"茉", "镈",
|
||||
"镞", "垭", "扁", "泫", "搬", "古", "书", "疸", "痨", "黟", "墉", "料", "并", "ㆍ", "裳", "鞑", "湮",
|
||||
"柠", "颐",
|
||||
"形", "━", "逹", "硁", "置", "韦", "瓞", "象", "殽", "均", "浓", "瞓", "椐", "洨", "乱", "襜", "终",
|
||||
"優", "睹",
|
||||
"敦", "鼬", "唆", "佼", "財", "瘃", "H", "痳", "勺", "依", "虎", "蕖", "玄", "缓", "滢", "^", "骅",
|
||||
"诘", "弋",
|
||||
":", "∩", "廪", "缈", "造", "蕉", "孖", "嫒", "寨", "意", "岽", "庶", "罗", "瞢", "酹", "蔟", "赴",
|
||||
"烂", "栋",
|
||||
"格", "矛", "驯", "词", "嗦", "剀", "蓓", "期", "鏢", "羑", "奴", "椱", "A", "狗", "烟", "蹬", "案",
|
||||
"记", "讴",
|
||||
"鳑", "侯", "霏", "焜", "沬", "份", "酦", "芗", "庚", "瑗", "鹎", "穗", "鲠", "肛", "厄", "蜔", "學",
|
||||
"伊", "⑥",
|
||||
"琪", "邒", "少", "霖", "蓖", "猜", "塾", "肾", "罃", "伐", "钩", "骈", "溟", "饵", "莉", "é", "刖",
|
||||
"洯", "堉",
|
||||
"锝", "趔", "七", "萁", "竹", "憾", "蚨", "离", "柔", "替", "侑", "飙", "气", "震", "厥", "备", "刻",
|
||||
"顽", "瞽",
|
||||
"腄", "雄", "燃", "旬", "简", "翠", "熥", "◇", "吃", "囡", "玙", "铷", "暖", "配", "傻", "窄", "皈",
|
||||
"夼", "舂",
|
||||
"乜", "苩", "攉", "雠", "茇", "锈", "酰", "粮", "祝", "考", "堍", "鳅", "彬", "▲", "孝", "蠊", "顇",
|
||||
"娲", "腥",
|
||||
"$", "珠", "厂", "诠", "蹓", "轼", "嵫", "捩", "硗", "胺", "证", "膀", "」", "胯", "钷", "毂", "柙",
|
||||
"深", "沄",
|
||||
"匹", "8", "爷", "礳", "秏", "窜", "魑", "d", "转", "烆", "屿", "眙", "極", "袤", "護", "V", "狂",
|
||||
"柑", "玠",
|
||||
"氩", "’", "馊", "玛", "坢", "%", "燔", "颗", "舅", "暂", "艾", "芹", "溏", "晰", "件", "琚", "仿",
|
||||
"祾", "酤",
|
||||
"騠", "揳", "鲫", "蜥", "仨", "牺", "步", "讓", "港", "煲", "铴", "腦", "鳝", "危", "鋪", "冠", "正",
|
||||
"柽", "抍",
|
||||
"掘", "控", "娴", "娀", "離", "手", "臾", "酗", "筼", "煸", "弹", "照", "哎", "毒", "颀", "诙", "刚",
|
||||
"搢", "䧳",
|
||||
"峒", "滋", "\\", "匀", "黉", "毓", "娠", "床", "浪", "祐", "铟", "4", "?", "凄", "飗", "蚍", "葑",
|
||||
"抗", "鹞",
|
||||
"糸", "红", "英", "违", "橡", "眷", "防", "缬", "龠", "察", "仍", "辇", "减", "闫", "箴", "龍", "館",
|
||||
"屙", "翙",
|
||||
"媽", "涴", "到", "旻", "删", "瞾", "鏖", "咭", "豨", "荘", "炭", "畼", "构", "锘", "鉫", "候", "扇",
|
||||
"繄", "猩",
|
||||
"瘵", "恺", "贵", "榦", "息", "恽", "胎", "狰", "雜", "辋", "璜", "硈", "泠", "呔", "蹿", "踹", "摄",
|
||||
"炀", "坞",
|
||||
"蹄", "裝", "赛", "蝥", "塔", "靳", "荬", "找", "仡", "淮", "比", "淆", "义", "淝", "卢", "辟", "寂",
|
||||
"庒", "鳯",
|
||||
"暲", "景", "邪", "腻", "赍", "甍", "讲", "哌", "嶝", "鎌", "总", "缱", "问", "磛", "谅", "拉", "靈",
|
||||
"奭", "沆",
|
||||
"茔", "羅", "鄠", "網", "吏", "懵", "鑫", "歌", "黹", "嵘", "涞", "碳", "崂", "婥", "赞", "镑", "購",
|
||||
"幺", "鸰",
|
||||
"饟", "蝌", "忝", "懒", "禺", "梽", "齉", "恳", "拯", "弥", "荡", "芾", "幪", "厌", "馒", "蜘", "欸",
|
||||
"吣", "1",
|
||||
"却", "榻", "碾", "袂", "錎", "钬", "無", "嬉", "笞", "蹴", "视", "雇", "创", "椟", "6", "瘁", "斜",
|
||||
"傥", "喃",
|
||||
"炷", "秾", "嘱", "茀", "犄", "窑", "庀", "潍", "伦", "䀲", "凉", "Р", "撻", "萜", "二", "倨", "蔑",
|
||||
"捕", "勚",
|
||||
"士", "鈇", "踺", "啤", "彧", "缪", "述", "傅", "颅", "畸", "畜", "滗", "慭", "琎", "斌", "参", "胳",
|
||||
"骖", "稠",
|
||||
"汰", "铻", "闯", "留", "蘘", "沏", "亦", "择", "華", "禽", "砟", "祼", "狃", "噫", "狼", "寤", "跪",
|
||||
"浠", "·",
|
||||
"费", "瓘", "鼹", "锪", "箢", "垣", "慊", "虏", "秩", "偉", "镏", "钯", "恐", "鹃", "菇", "炸", "潮",
|
||||
"蟀", "硂",
|
||||
"偌", "哏", "验", "桉", "阴", "初", "掴", "鹺", "峨", "赋", "舉", "裹", "赶", "土", "淋", "瘌", "沔",
|
||||
"r", "赀",
|
||||
"淖", "茯", "怛", "谜", "洗", "似", "舡", "纳", "晓", "R", "诐", "痹", "漪", "顺", "挛", "阎", "贝",
|
||||
"钰", "惬",
|
||||
"疬", "菀", "埘", "怙", "部", "译", "鲭", "窋", "敢", "夜", "撰", "珅", "特", "襕", "癖", "胡", "⒃",
|
||||
"附", "擘",
|
||||
"痢", "尬", "鉴", "瞋", "膨", "阽", "挲", "⒄", "骎", "帕", "缕", "计", "障", "鳆", "隹", "朔", "碹",
|
||||
"当", "迦",
|
||||
"氙", "蘑", "妓", "炬", "苊", "萎", "浈", "沥", "绯", "壤", "噱", "蹾", "驶", "葱", "孕", "羹", "钻",
|
||||
"農", "勝",
|
||||
"膈", "灿", "赆", "靿", "耱", "陪", "忙", "缰", "奶", "儒", "个", "朱", "燹", "琮", "轷", "錾", "箅",
|
||||
"澳", "嗥",
|
||||
"攥", "没", "匿", "鲆", "|", "矣", "他", "鸶", "芸", "B", "髑", "街", "巿", "廣", "盯", "監", "鲸",
|
||||
"胭", "凬",
|
||||
"寿", "挝", "绽", "+", "劝", "究", "眢", "集", "衙", "卷", "j", "跶", "牡", "畯", "貅", "销", "發",
|
||||
"咱", "蓊",
|
||||
"揣", "咝", "琶", "荦", "阌", "盅", "嘹", "苟", "醮", "洪", "鲧", "钒", "柱", "氨", "旰", "冽", "茭",
|
||||
"嵇", "粲",
|
||||
"蛾", "訾", "辔", "N", "尹", "趿", "蹲", "疟", "祠", "段", "車", "网", "⒉", "舷", "廐", "侣", "棵",
|
||||
"粜", "觐",
|
||||
"铼", "锁", "兒", "舁", "时", "垦", "版", "摈", "扳", "见", "腮", "嫖", "痭", "呆", "簖", "伋", "鳙",
|
||||
"珊", "麂",
|
||||
"既", "谴", "热", "超", "蠕", "铞", "e", "殓", "因", "锿", "文", "禊", "皙", "鑙", "爹", "鋼", "忻",
|
||||
"秣", "镁",
|
||||
"奠", "橉", "畺", "笮", "疹", "湝", "龟", "殃", "毵", "溃", "勢", "索", "砉", "阼", "堞", "酥", "冁",
|
||||
"喊", "¥",
|
||||
"幛", "娇", "锲", "蕃", "铘", "铍", "鴿", "响", "傲", "脏", "杓", "罕", "笥", "弦", "但", "缃", "扬",
|
||||
"盲", "碚",
|
||||
"幢", "鎖", "缺", "钋", "麽", "禳", "浃", "啄", "昧", "蒴", "帙", "琏", "咧", "舰", "亵", "浊", "豳",
|
||||
"衲", "俏",
|
||||
"镵", "浩", "勾", "槛", "榈", "徙", "鹤", "洹", "铂", "揎", "棕", "挦", "挫", "阆", "衹", "甚", "近",
|
||||
"】", "簏",
|
||||
"汽", "踮", "淌", "檇", "痔", "谝", "钙", "蕞", "蔯", "兆", "蔽", "后", "蚬", "谸", "芟", "枞", "叫",
|
||||
"栗", "餘",
|
||||
"营", "郝", "氯", "㺃", "狍", "冏", "庛", "纱", "泼", "碍", "认", "邓", "茵", "饧", "闟", "惝", "裙",
|
||||
"噙", "忘",
|
||||
"虬", "群", "S", "佗", "恼", "坟", "肮", "皮", "玃", "在", "赧", "孚", "偾", "镨", "恨", "葡", "西",
|
||||
"缞", "挠",
|
||||
"逃", "吾", "膪", "焦", "翘", "桧", "变", "渗", "繁", "際", "痘", "撼", "筅", "坑", "前", "玑", "数",
|
||||
"融", "鲌",
|
||||
"讦", "窃", "鄌", "伾", "众", "攻", "彪", "锎", "焐", "殛", "锊", "嗉", "枓", "抢", "鞠", "掩", "贾",
|
||||
"搔", "皁",
|
||||
"拶", "朗", "渺", "跛", "㛃", "鏾", "慥", "杆", "沈", "戍", "豫", "楠", "爆", "汤", "昉", "耘", "缡",
|
||||
".", "允",
|
||||
"揜", "责", "艟", "裁", "喬", "砹", "鹣", "裼", "啉", "蛳", "酮", "听", "维", "阪", "獾", "浣", "訂",
|
||||
"瘿", "蜡",
|
||||
"泖", "蔚", "貔", "致", "禨", "尓", "糺", "绐", "遯", "笄", "邦", "圈", "洟", "缟", "槲", "桹", "镓",
|
||||
"骒", "髫",
|
||||
"暾", "像", "縻", "戊", "飧", "驽", "干", "万", "绕", "披", "雅", "桊", "卡", "贲", "吡", "沧", "鳟",
|
||||
"堂", "扺",
|
||||
"岱", "封", "鄭", "螣", "瞩", "幞", "邕", "睫", "涩", "自", "趱", "愣", "威", "酊", "罂", "慑", "袴",
|
||||
"架", "烘",
|
||||
"现", "灞", "钔", "股", "興", "乍", "噜", "济", "碛", "兀", "诅", "柴", "瓿", "[", "怿", "竦", "白",
|
||||
"黄", "阶",
|
||||
"务", "榮", "澹", "谏", "垓", "跸", "繻", "窿", "紊", "陟", "劁", "嗑", "牯", "厉", "敛", "鮕", "嘉",
|
||||
"蔻", "鼎",
|
||||
"恒", "硝", "溉", "骘", "窘", "任", "裱", "处", "旨", "舶", "缸", "囹", "笠", "讥", "泜", "脊", "煊",
|
||||
"淦", "牝",
|
||||
"硕", "胧", "泚", "溪", "贪", "牛", "答", "瘴", "Q", "炯", "⑤", "篾", "銀", "乩", "杶", "垆", "蛐",
|
||||
"苔", "啪",
|
||||
"y", "玮", "琫", "寮", "邂", "後", "僵", "贴", "硭", "枚", "姆", "乎", "讶", "醭", "橥", "脱", "蒈",
|
||||
"擞", "忪",
|
||||
"顾", "柚", "褿", "忲", "辖", "铡", "螠", "殉", "喆", "爡", "轮", "棰", "鲉", "跃", "韬", "睡", "嘧",
|
||||
"袅", "圗",
|
||||
"檄", "踊", "阀", "题", "桫", "林", "沉", "禚", "散", "麇", "沦", "秋", "导", "斑", "宰", "嘞", "暑",
|
||||
"笱", "搋",
|
||||
"擅", "镤", "锶", "L", "厣", "有", "猗", "袆", "绞", "甭", "歧", "跣", "潦", "専", "绑", "飱", "廓",
|
||||
"磔", "接",
|
||||
"腓", "窎", "瑁", "飓", "蟪", "俎", "П", "缉", "䘵", "夙", "潟", "桷", "淡", "虺", "恶", "|", "驭",
|
||||
"怀", "邋",
|
||||
"辢", "逻", "晖", "蜃", "蜊", "溻", "冢", "尻", "礼", "厝", "亘", "酴", "饔", "悸", "戆", "什", "玚",
|
||||
"馔", "哔",
|
||||
"沃", "竑", "葭", "垞", "鏂", "抃", "弄", "去", "焊", "焌", "x", "苇", "與", "炼", "蛄", "莴", "阏",
|
||||
"薷", "禀",
|
||||
"鸯", "栽", "冒", "姓", "0", "尃", "蜞", "毗", "骟", "秸", "荸", "柈", "恬", "赡", "侏", "兑", "蝤",
|
||||
"荷", "徳",
|
||||
"押", "挣", "腰", "宣", "鸵", "葳", "遘", "讨", "狒", "涿", "囤", "邃", "蒜", "疑", "脍", "嘟", "鹠",
|
||||
"吻", "鄹",
|
||||
"耦", "华", "霸", "侥", "勒", "挞", "臊", "尺", "让", "榆", "阝", "鳚", "灾", "鲬", "艿", "Ⅱ", "锩",
|
||||
"攮", "蚊",
|
||||
"蔁", "唝", "涅", "挹", "淏", "鏊", "氵", "鹕", "律", "對", "粱", "恫", "挻", "滏", "叮", "‰", "鼯",
|
||||
"绫", "秉",
|
||||
"怩", "質", "岐", "菊", "佤", "帏", "骺", "爰", "珉", "耪", "乞", "郕", "鲱", "雷", "蒿", "不", "啐",
|
||||
"侓", "郓",
|
||||
"歼", "拒", "胗", "寕", "旒", "勁", "婢", "诌", "蹂", "姐", "媳", "歃", "拐", "辐", "拟", "醯", "雌",
|
||||
"点", "玟",
|
||||
"您", "鲨", "载", "藩", "罔", "噀", "抹", "萏", "补", "蝎", "辈", "劢", "乚", "唔", "瓜", "恿", "蟭",
|
||||
"涸", "纬",
|
||||
"睽", "樣", "帻", "蓥", "谯", "柯", "渴", "脁", "诲", "福", "③", "熊", "羌", "疴", "袖", "虿", "杏",
|
||||
"覌", "易",
|
||||
"醾", "筒", "肤", "苷", "柃", "榇", "酬", "癸", "啰", "眛", "稷", "展", "鸾", "祢", "蝾", "敵", "毛",
|
||||
"痦", "老",
|
||||
"赐", "单", "淹", "畋", "符", "奎", "绥", "轾", "鄺", "濩", "眦", "觎", "忾", "璋", "刘", "翳", "菪",
|
||||
"簟", "胼",
|
||||
"孫", "機", "獻", "低", "o", "捅", "鳥", "⑨", "卸", "废", "启", "呋", "窥", "巢", "揭", "咴", "趺",
|
||||
"鲥", "空",
|
||||
"膄", "崮", "锜", "络", "納", "恤", "刭", "批", "霭", "氧", "钮", "甑", "祲", "粘", "辏", "∶", "臨",
|
||||
"│", "粪",
|
||||
"惰", "肼", "浉", "橄", "5", "東", "8", "漁", "浜", "忍", "奂", "遹", "扃", "扦", "入", "欤", "豆",
|
||||
"悠", "蕴",
|
||||
"萑", "媄", "龈", "÷", "磙", "鸬", "缎", "嗯", "浕", "木", "陋", "柰", "瘩", "箨", "松", "躁", "鲇",
|
||||
"彰", "恕",
|
||||
"楗", "姨", "撅", "诹", "戮", "桓", "棉", "束", "嗍", "庋", "瞿", "郂", "哪", "町", "a", "铁", "洫",
|
||||
"失", "栳",
|
||||
"篇", "鳗", "眇", "椿", "義", "就", "都", "镌", "阖", "夭", "拃", "跚", "業", "圬", "演", "篥", "3",
|
||||
"昼", "從",
|
||||
"瞍", "蓦", "鼾", "坪", "觫", "鲍", "馿", "妾", "密", "奥", "耰", "佟", "嘤", "貘", "薯", "稽", "届",
|
||||
"褛", "钠",
|
||||
"猿", "佈", "倍", "铩", "铙", "踵", "o", "捱", "鹐", "當", "狷", "写", "遆", "钱", "姗", "寸", "综",
|
||||
"挑", "礶",
|
||||
"靼", "溯", "湟", "漱", "碰", "职", "味", "Λ", "璁", "壴", "给", "碘", "恭", "苴", "酚", "套", "宕",
|
||||
"辽", "窀",
|
||||
"催", "踢", "惟", "璧", "翔", "稿", "癀", "霈", "光", "膑", "妆", "庡", "圾", "躺", "惮", "切", "目",
|
||||
"梦", "岫",
|
||||
"飑", "叠", "累", "鴻", "透", "量", "妻", "沨", "俪", "屣", "挚", "w", "厅", "货", "箧", "漦", "隙",
|
||||
"瘥", "妃",
|
||||
"門", "鹦", "隳", "龆", "瞪", "跑", "帼", "刺", "起", "鞴", "岸", "渫", "莽", "髭", "耜", "瑛", "葉",
|
||||
"宵", "绠",
|
||||
"眭", "畅", "茱", "卜", "濂", "浍", "冈", "脬", "厘", "夔", "纟", "槚", "哐", "萋", "曼", "膳", "潲",
|
||||
"啜", "啊",
|
||||
"猾", "捉", "箕", "㐂", "藝", "艘", "園", "妲", "灵", "蚌", "范", "&", "疥", "陑", "洒", "唾", "a",
|
||||
"婄", "谋",
|
||||
"t", "唬", "宓", "瓷", "︰", "焗", "默", "噔", "菡", "恃", "亩", "边", "啟", "颞", "啬", "盟", "墩",
|
||||
"汭", "缝",
|
||||
"魇", "酡", "疗", "梾", "尾", "鹿", "锔", "溦", "酃", "囊", "掉", "罥", "报", "诤", "喹", "蕙", "割",
|
||||
"蠢", "兼",
|
||||
"俺", "升", "屦", "獠", "辣", "跹", "颧", "宪", "抬", "咿", "沲", "旗", "荩", "傒", "鳳", "變", "偈",
|
||||
"薹", "钭",
|
||||
"垧", "谪", "躐", "谀", "R", "字", "怆", "陵", "追", "迓", "舞", "卲", "捲", "麾", "税", "方", "竴",
|
||||
"壹", "射",
|
||||
"轫", "塞", "僧", "椠", "突", "阕", "惫", "U", "佞", "秒", "友", "視", "莹", "攒", "荻", "俅", "筐",
|
||||
"能", "刓",
|
||||
"拍", "浥", "揽", "谨", "军", "巷", "怵", "额", "恪", "荀", "糍", "湎", "褙", "觇", "效", "估", "噩",
|
||||
"恍", "聚",
|
||||
"涛", "式", "兜", "汔", "祃", "銘", "烺", "瑄", "枘", "丁", "樗", "堙", "窗", "號", "鬣", "阈", "乳",
|
||||
"簇", "绳",
|
||||
"淞", "]", "征", "聩", "凸", "礓", "柘", "懂", "㧎", "纷", "里", "爸", "靥", "莞", "馅", "仞", "芏",
|
||||
"莳", "殪",
|
||||
"煌", "落", "佚", "帱", "诶", "家", "将", "浯", "抿", "讫", "趸", "筢", "绩", "原", "专", "滂", "嗳",
|
||||
"踬", "泱",
|
||||
"體", "蜱", "绵", "伻", "埗", "妤", "蔺", "赳", "嘢", "梨", "鹪", "烤", "镦", "赉", "崞", "蚰", "骝",
|
||||
"幅", "汴",
|
||||
"丽", "访", "叩", "羼", "亓", "恸", "燥", "笤", "丑", "枰", "守", "蜚", "戈", "高", "q", "瓻", "隘",
|
||||
"H", "南",
|
||||
"剎", "扭", "骠", "孜", "园", "锬", "审", "¥", "罚", "购", "裰", "泔", "醌", "醒", "绎", "莪", "掬",
|
||||
"睾", "鹁",
|
||||
"蛊", "票", "剃", "释", "调", "黛", "撩", "篱", "茌", "敓", "蜜", "魉", "鳤", "昽", "俳", "辁", "键",
|
||||
"犯", "嶙",
|
||||
"狈", "邬", "枋", "婊", "憎", "督", "救", "措", "足", "码", "栟", "虼", "棻", "阅", "肊", "坛", "鸱",
|
||||
"侩", "烫",
|
||||
"湉", "脐", "戾", "旎", "膚", "椒", "境", "绛", "濛", "蓄", "章", "压", "窦", "彖", "阜", "咻", "神",
|
||||
"存", "诺",
|
||||
"課", "覺", "鲈", "渚", "「", "缢", "仓", "氅", "筇", "桴", "荥", "些", "纯", "肋", "退", "妪", "别",
|
||||
"書", "租",
|
||||
"嚼", "芘", "笳", "涰", "馐", "熵", "犹", "朕", "猪", "蔸", "參", "觳", "舖", "蝙", "骏", "织", "躏",
|
||||
"纹", "锹",
|
||||
"蛉", "撑", "氽", "茶", "俛", "誠", "胖", "崽", "炫", "乘", "把", "趑", "谵", "骧", "犍", "鸮", "灌",
|
||||
"焯", "倭",
|
||||
"狁", "盱", "踱", "滠", "儡", "诸", "芽", "駆", "蹼", "虱", "祇", " ", "蠡", "衄", "谬", "蒍", "婺",
|
||||
"蘧", "博",
|
||||
"捍", "磁", "慷", "釂", "蛩", "钕", "祎", "呑", "贫", "斗", "菅", "操", "规", "硼", "惕", "丫", "俭",
|
||||
"肿", "骀",
|
||||
"砼", "句", "茛", "闶", "钏", "饻", "圠", "萌", "魏", "铃", "摞", "┅", "伎", "獭", "田", "钴", "峭",
|
||||
"魅", "捋",
|
||||
"唼", "鹅", "祚", "嬷", "圖", "抄", "嶂", "鸳", "溧", "钵", "嗽", "墠", "锌", "愈", "併", "踟", "羯",
|
||||
"翅", "纠",
|
||||
"勻", "岚", "菖", "便", "祈", "毳", "屹", "掰", "倬", "扛", "巴", "拮", "绁", "跌", "飯", "嵯", "翮",
|
||||
"堤", "诃",
|
||||
"腑", "皆", "鄂", "胾", "片", "这", "浙", "雨", "鼱", "袼", "鹊", "厢", "蛣", "摇", "蛮", "揍", "⒅",
|
||||
"啱", "薇",
|
||||
"岈", "兔", "谇", "纶", "肉", "崩", "甩", "涪", "馼", "铣", "锚", "丙", "雲", "烹", "钦", "撄", "铬",
|
||||
"令", "虮",
|
||||
"湊", "禹", "抖", "喏", "旺", "畲", "戬", "嗷", "釜", "车", "缀", "玕", "谐", "啁", "怎", "下", "惑",
|
||||
"恅", "藿",
|
||||
"筰", "帐", "祸", "镝", "喵", "刁", "习", "藏", "墓", "护", "聲", "箦", "严", "按", "谛", "睨", "艚",
|
||||
"歉", "蟮",
|
||||
"胶", "盍", "鳃", "狯", "垫", "杠", "线", "3", "葖", "t", "熬", "虞", "嶶", "篮", "黻", "墒", "氟",
|
||||
"嫠", "漕",
|
||||
"腾", "哟", "玫", "撇", "垍", "靛", "翼", "淅", "省", "斥", "稞", "蠼", "谩", "埠", "蘸", "刊", "烝",
|
||||
"宁", "鹚",
|
||||
"龊", "苪", "袷", "诧", "细", "蒌", "焅", "2", "筹", "扒", "卮", "捞", "净", "菲", "逮", "槍", "蛎",
|
||||
"莱", "黠",
|
||||
"逖", "辚", "剥", "啴", "诿", "楱", "氪", "领", "嗒", "藐", "惜", "甘", "佾", "嵴", "胫", ";", "晳",
|
||||
"锣", "瞅",
|
||||
"缷", "耶", "搤", "策", "咽", "邀", "霾", "悟", "属", "鸪", "牴", "贞", "趁", "丞", "瘆", "豌", "著",
|
||||
"饿", "筠",
|
||||
"划", "璇", "损", "卵", "腒", "畏", "盥", "耐", "圏", "拓", "蒙", "鋫", "劙", "蹦", "熘", "烊", "匏",
|
||||
"咔", "轘",
|
||||
"沽", "菩", "罴", "磉", "炖", "假", "枪", "龙", "俸", "焱", "四", "─", "毫", "涨", "浇", "椰", "賣",
|
||||
"蘇", "真",
|
||||
"安", "坝", "枕", "鸼", "昵", "亨", "苤", "祷", "枧", "赟", "菑", "鳂", "戌", "悄", "種", "鳢", "嗣",
|
||||
"電", "颥",
|
||||
"妯", "谟", "蜒", "训", "泍", "洁", "勇", "哿", "扰", "蟆", "螂", "刃", "絜", "曪", "乒", "湖", "鞨",
|
||||
"懜", "夤",
|
||||
"哓", "胥", "桞", "俇", "肣", "半", "于", "橼", "锑", "熙", "甜", "槌", "盾", "屃", "缗", "共", "碗",
|
||||
"凇", "笔",
|
||||
"阿", "擗", "袍", "敉", "钾", "俶", "蚪", "琤", "凱", "辕", "à", "恣", "皴", "創", "寥", "妳", "腈",
|
||||
"畤", "迤",
|
||||
"垠", "触", "趙", "铤", "逊", "羊", "碉", "锱", "骨", "仄", "斟", "俚", "啡", "芩", "迫", "杷", "种",
|
||||
"鹄", "牗",
|
||||
"耑", "艇", "芰", "整", "慙", "飛", "甓", "岩", "鸦", "黎", "僊", "糁", "谈", "洋", "椑", "健", "〕",
|
||||
"內", "言",
|
||||
"掷", "倚", "姬", "矿", "灯", "阐", "凋", "銮", "豇", "瑰", "抓", "噪", "堋", "吁", "妈", "庥", "彳",
|
||||
"鄗", "闩",
|
||||
"夫", "0", "庠", "悬", "妙", "琵", "着", "首", "熣", "瞰", "揆", "燚", "条", "姜", "滘", "麓", "鳉",
|
||||
"椀", "蓿",
|
||||
"廠", "泌", "蝈", "倕", "丛", "耍", "且", "蝇", "凉", "豐", "泪", "臼", "服", "刍", "織", "渎", "尥",
|
||||
"甙", "埋",
|
||||
"珏", "援", "祖", "彊", "臱", "惦", "葴", "礁", "达", "橋", "钨", "崦", "醐", "巳", "中", "颜", "溠",
|
||||
"铹", "负",
|
||||
"抠", "愎", "罘", "雩", "胝", "冱", "筵", "篙", "材", "肓", "○", "迅", "腼", "橙", "仵", "茏", "慵",
|
||||
"齌", "琯",
|
||||
"疃", "貢", "豉", "瞟", "忉", "禄", "通", "咒", "愫", "秕", "筜", "觖", "州", "渑", "胆", "喑", "張",
|
||||
"衖", "洺",
|
||||
"眉", "榞", "色", "邶", "攫", "堑", "淬", "嗪", "肐", "殣", "辊", "隧", "献", "潤", "蓺", "函", "鹱",
|
||||
"轭", "劭",
|
||||
"椁", "膜", "亹", "侧", "貂", "哚", "磴", "蠋", "囔", "险", "伶", "世", "菥", "莶", "瘾", "燫", "延",
|
||||
"∵", "毋",
|
||||
"羧", "无", "雎", "曛", "沚", "巍", "g", "熄", "恰", "伷", "開", "冻", "颛", "支", "⑦", "鞥", "赖",
|
||||
"试", "泮",
|
||||
"联", "沮", "穰", "è", "峻", "滿", "豊", "刎", "鴈", "覆", "串", "锃", "春", "储", "矍", "哺", "评",
|
||||
"猁", "愉",
|
||||
"疳", "閃", "奄", "甲", "墦", "頭", "锫", "俦", "玩", "搀", "砭", "流", "橇", "泅", "琇", "趣", "∧",
|
||||
"辑", "灊",
|
||||
"貴", "迮", "摹", "霄", "濟", "限", "彀", "匪", "缂", "觚", "奇", "诋", "灼", "萘", "狠", "澥", "岂",
|
||||
"悺", "闾",
|
||||
"麋", "号", "槽", "姹", "陉", "瑯", "尉", "h", "绖", "宿", "戋", "粝", "砂", "该", "鞧", "翯", "釘",
|
||||
"铢", "窨",
|
||||
"設", "⒆"]`
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,33 +0,0 @@
|
||||
package ddddocr
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"likedream-goframe/internal/application/recognizer"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed static/*
|
||||
var fs embed.FS
|
||||
|
||||
func initModel() string {
|
||||
if !recognizer.OnnxIsInit {
|
||||
recognizer.InitOnnx()
|
||||
}
|
||||
// 检测文件是否存在
|
||||
exePath := strings.ToLower(os.Args[0])
|
||||
// 获取绝对路径
|
||||
absPath, _ := filepath.Abs(exePath)
|
||||
staticPath := filepath.Join(filepath.Dir(absPath), "static")
|
||||
if _, err := os.Stat(staticPath); os.IsNotExist(err) {
|
||||
os.Mkdir(staticPath, 0755)
|
||||
}
|
||||
modelPath := filepath.Join(staticPath, "common_old.onnx")
|
||||
modelBytes, _ := fs.ReadFile("static/common_old.onnx")
|
||||
if _, err := os.Stat(modelPath); os.IsNotExist(err) {
|
||||
os.WriteFile(modelPath, modelBytes, 0644)
|
||||
}
|
||||
return modelPath
|
||||
}
|
||||
Binary file not shown.
@@ -1,59 +0,0 @@
|
||||
package recognizer
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"likedream-goframe/internal/framework/logger"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
ort "github.com/yalue/onnxruntime_go"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
//go:embed static/*
|
||||
var fs embed.FS
|
||||
|
||||
// OnnxIsInit 初始化onnx配置
|
||||
var OnnxIsInit = false
|
||||
|
||||
func InitOnnx() {
|
||||
name, bytes := getOnnxRuntimeName()
|
||||
// 检测文件是否存在
|
||||
exePath := strings.ToLower(os.Args[0])
|
||||
// 获取绝对路径
|
||||
absPath, _ := filepath.Abs(exePath)
|
||||
filePath := filepath.Join(filepath.Dir(absPath), name)
|
||||
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
||||
os.WriteFile(filePath, bytes, 0644)
|
||||
}
|
||||
ort.SetSharedLibraryPath(filePath)
|
||||
err := ort.InitializeEnvironment()
|
||||
if err != nil {
|
||||
logger.Logger.Panic("初始化onnx:", zap.String("绝对路径", filePath))
|
||||
return
|
||||
}
|
||||
OnnxIsInit = true
|
||||
}
|
||||
|
||||
func getOnnxRuntimeName() (onnxRuntimeFileName string, onnxRuntimeFileBytes []byte) {
|
||||
systemOS := runtime.GOOS
|
||||
switch systemOS {
|
||||
case "windows":
|
||||
onnxRuntimeFileName = "onnxruntime.dll"
|
||||
onnxRuntimeFileBytes, _ = fs.ReadFile("static/onnxruntime.dll")
|
||||
return
|
||||
case "darwin":
|
||||
onnxRuntimeFileName = "onnxruntime.dylib"
|
||||
onnxRuntimeFileBytes, _ = fs.ReadFile("static/libonnxruntime.1.23.2.dylib")
|
||||
return
|
||||
case "linux":
|
||||
onnxRuntimeFileName = "onnxruntime.so"
|
||||
onnxRuntimeFileBytes, _ = fs.ReadFile("static/libonnxruntime.so.1.23.2")
|
||||
return
|
||||
}
|
||||
logger.Logger.Panic("暂不支持的操作系统:", zap.String("系统名称", systemOS))
|
||||
return "", nil
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,192 +0,0 @@
|
||||
package slider
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"os"
|
||||
|
||||
"gocv.io/x/gocv"
|
||||
)
|
||||
|
||||
func VerifySliderWidth(bgImgPath, sliderImgPath string) int {
|
||||
// 检查背景图片文件是否存在
|
||||
if _, err := os.Stat(bgImgPath); os.IsNotExist(err) {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 检查滑块图片文件是否存在
|
||||
if _, err := os.Stat(sliderImgPath); os.IsNotExist(err) {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 读取背景图片
|
||||
bgImg := gocv.IMRead(bgImgPath, gocv.IMReadColor)
|
||||
if bgImg.Empty() {
|
||||
return -1
|
||||
}
|
||||
defer bgImg.Close()
|
||||
|
||||
// 读取滑块图片(包含 alpha 通道)
|
||||
sliderImgWithAlpha := gocv.IMRead(sliderImgPath, gocv.IMReadUnchanged)
|
||||
if sliderImgWithAlpha.Empty() {
|
||||
return -1
|
||||
}
|
||||
defer sliderImgWithAlpha.Close()
|
||||
|
||||
// 分离滑块图片的通道
|
||||
channels := gocv.Split(sliderImgWithAlpha)
|
||||
defer func() {
|
||||
for i := range channels {
|
||||
channels[i].Close()
|
||||
}
|
||||
}()
|
||||
|
||||
var sliderImg gocv.Mat
|
||||
var mask gocv.Mat
|
||||
|
||||
// 如果有 alpha 通道(4通道),提取 mask
|
||||
if len(channels) == 4 {
|
||||
// 前3个通道是 BGR
|
||||
sliderImg = gocv.NewMat()
|
||||
defer sliderImg.Close()
|
||||
gocv.Merge(channels[:3], &sliderImg)
|
||||
|
||||
// 使用 alpha 通道作为 mask
|
||||
mask = channels[3].Clone()
|
||||
defer mask.Close()
|
||||
} else if len(channels) == 3 {
|
||||
// 没有透明通道,直接使用原图
|
||||
sliderImg = sliderImgWithAlpha.Clone()
|
||||
defer sliderImg.Close()
|
||||
mask = gocv.NewMat() // 空 mask
|
||||
defer mask.Close()
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 创建结果矩阵用于存储匹配结果
|
||||
result := gocv.NewMat()
|
||||
defer result.Close()
|
||||
|
||||
// 直接在原图上使用模板匹配找到滑块位置
|
||||
if mask.Empty() {
|
||||
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, gocv.NewMat())
|
||||
} else {
|
||||
// 带 mask 的模板匹配
|
||||
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, mask)
|
||||
}
|
||||
|
||||
// 找到最佳匹配位置
|
||||
_, maxVal, _, maxLoc := gocv.MinMaxLoc(result)
|
||||
|
||||
// 如果匹配度太低,返回 -1 表示失败
|
||||
if maxVal < 0.6 {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 获取原图上的 x 坐标,然后按比例缩放到目标尺寸
|
||||
originalWidth := bgImg.Cols()
|
||||
targetWidth := 280
|
||||
scale := float64(targetWidth) / float64(originalWidth)
|
||||
scaledX := int(float64(maxLoc.X) * scale)
|
||||
|
||||
// 返回缩放后的 x 坐标(滑块需要移动的距离)
|
||||
return scaledX
|
||||
}
|
||||
|
||||
// VerifySliderWidthByBase64 通过 base64 编码的图片计算滑块验证码需要移动的距离
|
||||
// bgImgBase64: 背景图片的 base64 编码
|
||||
// sliderImgBase64: 滑块图片的 base64 编码
|
||||
// 返回: 滑块需要移动的 x 距离(已缩放到 280 宽度),失败返回 -1
|
||||
func VerifySliderWidthByBase64(bgImgBase64, sliderImgBase64 string) int {
|
||||
// 解码背景图片的 base64
|
||||
bgImgData, err := base64.StdEncoding.DecodeString(bgImgBase64)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 解码滑块图片的 base64
|
||||
sliderImgData, err := base64.StdEncoding.DecodeString(sliderImgBase64)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 从内存中读取背景图片
|
||||
bgImg, err := gocv.IMDecode(bgImgData, gocv.IMReadColor)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
if bgImg.Empty() {
|
||||
return -1
|
||||
}
|
||||
defer bgImg.Close()
|
||||
|
||||
// 从内存中读取滑块图片(包含 alpha 通道)
|
||||
sliderImgWithAlpha, err := gocv.IMDecode(sliderImgData, gocv.IMReadUnchanged)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
if sliderImgWithAlpha.Empty() {
|
||||
return -1
|
||||
}
|
||||
defer sliderImgWithAlpha.Close()
|
||||
|
||||
// 分离滑块图片的通道
|
||||
channels := gocv.Split(sliderImgWithAlpha)
|
||||
defer func() {
|
||||
for i := range channels {
|
||||
channels[i].Close()
|
||||
}
|
||||
}()
|
||||
|
||||
var sliderImg gocv.Mat
|
||||
var mask gocv.Mat
|
||||
|
||||
// 如果有 alpha 通道(4通道),提取 mask
|
||||
if len(channels) == 4 {
|
||||
// 前3个通道是 BGR
|
||||
sliderImg = gocv.NewMat()
|
||||
defer sliderImg.Close()
|
||||
gocv.Merge(channels[:3], &sliderImg)
|
||||
|
||||
// 使用 alpha 通道作为 mask
|
||||
mask = channels[3].Clone()
|
||||
defer mask.Close()
|
||||
} else if len(channels) == 3 {
|
||||
// 没有透明通道,直接使用原图
|
||||
sliderImg = sliderImgWithAlpha.Clone()
|
||||
defer sliderImg.Close()
|
||||
mask = gocv.NewMat() // 空 mask
|
||||
defer mask.Close()
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 创建结果矩阵用于存储匹配结果
|
||||
result := gocv.NewMat()
|
||||
defer result.Close()
|
||||
|
||||
// 直接在原图上使用模板匹配找到滑块位置
|
||||
if mask.Empty() {
|
||||
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, gocv.NewMat())
|
||||
} else {
|
||||
// 带 mask 的模板匹配
|
||||
gocv.MatchTemplate(bgImg, sliderImg, &result, gocv.TmCcoeffNormed, mask)
|
||||
}
|
||||
|
||||
// 找到最佳匹配位置
|
||||
_, maxVal, _, maxLoc := gocv.MinMaxLoc(result)
|
||||
|
||||
// 如果匹配度太低,返回 -1 表示失败
|
||||
if maxVal < 0.6 {
|
||||
return -1
|
||||
}
|
||||
|
||||
// 获取原图上的 x 坐标,然后按比例缩放到目标尺寸
|
||||
originalWidth := bgImg.Cols()
|
||||
targetWidth := 280
|
||||
scale := float64(targetWidth) / float64(originalWidth)
|
||||
scaledX := int(float64(maxLoc.X) * scale)
|
||||
|
||||
// 返回缩放后的 x 坐标(滑块需要移动的距离)
|
||||
return scaledX
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -62,11 +62,86 @@ type XueXiTCourse struct {
|
||||
CourseID string `json:"courseId"` // 课程ID
|
||||
ChatID string `json:"chatId"`
|
||||
CourseTeacher string `json:"courseTeacher"` // 课程老师
|
||||
CourseName string `json:"courseName"` //课程名
|
||||
CourseName string `json:"courseName"` // 课程名
|
||||
CourseImage string `json:"courseImage"`
|
||||
// 两个标识 暂时不知道有什么用
|
||||
CourseDataID int `json:"courseDataId"`
|
||||
ContentID int `json:"ContentID"`
|
||||
IsStart bool `json:"isstart"` //是否开课了,开课了为true,没开课为false。一般来说开课才能刷,不然刷不了的
|
||||
State int `json:"state"` //课程状态,0为正常,1为课程已经结束
|
||||
IsStart bool `json:"isstart"` // 是否开课了,开课了为true,没开课为false
|
||||
State int `json:"state"` // 课程状态,0为正常,1为课程已经结束
|
||||
}
|
||||
|
||||
// XueXiTCourseChapter 课程章节信息
|
||||
type XueXiTCourseChapter struct {
|
||||
ID int `json:"id"` // 章节ID
|
||||
Name string `json:"name"` // 章节名称
|
||||
ParentNodeID int `json:"parentnodeid"` // 父节点ID
|
||||
Layer int `json:"layer"` // 层级
|
||||
Label string `json:"label"` // 标签
|
||||
IndexOrder int `json:"indexOrder"` // 排序索引
|
||||
JobCount int `json:"jobcount"` // 任务点数量
|
||||
Status string `json:"status"` // 状态
|
||||
IsReview int `json:"isReview"` // 是否复习
|
||||
BeginTime int64 `json:"begintime"` // 开始时间
|
||||
EndTime int64 `json:"endtime"` // 结束时间
|
||||
PointTotal int `json:"pointTotal"` // 总任务点
|
||||
PointFinish int `json:"pointFinish"` // 已完成任务点
|
||||
Knowledge []XueXiTCourseChapter `json:"knowledge"` // 子章节列表
|
||||
}
|
||||
|
||||
// ChapterData 章节数据响应
|
||||
type ChapterData struct {
|
||||
Data []struct {
|
||||
Hideclazz int `json:"hideclazz"`
|
||||
Allowdownload int `json:"allowdownload"`
|
||||
Chatid string `json:"chatid"`
|
||||
Isfiled int `json:"isfiled"`
|
||||
Forbidintoclazz int `json:"forbidintoclazz"`
|
||||
Coursesetting struct {
|
||||
Data []struct {
|
||||
Coursefacecheck int `json:"coursefacecheck"`
|
||||
Hiddencoursecover int `json:"hiddencoursecover"`
|
||||
ID int `json:"id"`
|
||||
Courseid int `json:"courseid"`
|
||||
} `json:"data"`
|
||||
} `json:"coursesetting"`
|
||||
Isstart bool `json:"isstart"`
|
||||
Visiblescore int `json:"visiblescore"`
|
||||
Name string `json:"name"`
|
||||
Course struct {
|
||||
Data []struct {
|
||||
App int `json:"app"`
|
||||
Teacherfactor string `json:"teacherfactor"`
|
||||
Jobcount int `json:"jobcount"`
|
||||
Infocontent string `json:"infocontent"`
|
||||
Bulletformat string `json:"bulletformat"`
|
||||
Mappingcourseid int `json:"mappingcourseid"`
|
||||
Imageurl string `json:"imageurl"`
|
||||
Name string `json:"name"`
|
||||
ID int `json:"id"`
|
||||
Belongschoolid string `json:"belongschoolid"`
|
||||
Objectid string `json:"objectid"`
|
||||
Knowledge struct {
|
||||
Data []KnowledgeData `json:"data"`
|
||||
} `json:"knowledge"`
|
||||
} `json:"data"`
|
||||
} `json:"course"`
|
||||
ID int `json:"id"`
|
||||
State int `json:"state"`
|
||||
Bbsid string `json:"bbsid"`
|
||||
Classscore int `json:"classscore"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// KnowledgeData 章节知识点数据
|
||||
type KnowledgeData struct {
|
||||
Jobcount int `json:"jobcount"`
|
||||
Isreview int `json:"isreview"`
|
||||
Indexorder int `json:"indexorder"`
|
||||
Name string `json:"name"`
|
||||
ID int `json:"id"`
|
||||
Label string `json:"label"`
|
||||
Layer int `json:"layer"`
|
||||
Parentnodeid int `json:"parentnodeid"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
package entity
|
||||
|
||||
// PointType 任务点类型
|
||||
type PointType string
|
||||
|
||||
const (
|
||||
PointTypeVideo PointType = "insertvideo"
|
||||
PointTypeDocument PointType = "insertdoc"
|
||||
PointTypeDocument2 PointType = "document"
|
||||
PointTypeBook PointType = "insertbook"
|
||||
PointTypeWork PointType = "insertwork"
|
||||
PointTypeHyperlink PointType = "insertlink"
|
||||
PointTypeLive PointType = "insertlive"
|
||||
)
|
||||
|
||||
// PointVideoDto 视频任务点
|
||||
type PointVideoDto struct {
|
||||
CardIndex int
|
||||
CourseID string
|
||||
ClassID string
|
||||
KnowledgeID int
|
||||
Cpi string
|
||||
ObjectID string
|
||||
// 从SSR视图中获取
|
||||
IsPassed bool
|
||||
FID int
|
||||
DToken string
|
||||
PlayTime int
|
||||
Duration int
|
||||
JobID string
|
||||
OtherInfo string
|
||||
Title string
|
||||
RT float64
|
||||
VideoFaceCaptureEnc string
|
||||
RandomCaptureTime string
|
||||
AttDurationEnc string
|
||||
Enc string
|
||||
Mid string
|
||||
}
|
||||
|
||||
// PointDocumentDto 文档查看任务点
|
||||
type PointDocumentDto struct {
|
||||
CardIndex int
|
||||
CourseID string
|
||||
ClassID string
|
||||
KnowledgeID int
|
||||
Cpi string
|
||||
ObjectID string
|
||||
Title string
|
||||
JobID string
|
||||
Jtoken string
|
||||
IsJob bool // 是否是任务点
|
||||
Type string // document / insertbook
|
||||
}
|
||||
|
||||
// PointWorkDto 测验/作业任务点
|
||||
type PointWorkDto struct {
|
||||
CardIndex int
|
||||
CourseID string
|
||||
ClassID string
|
||||
KnowledgeID int
|
||||
Cpi string
|
||||
WorkID string
|
||||
SchoolID string
|
||||
JobID string
|
||||
PUID string
|
||||
KToken string
|
||||
Enc string
|
||||
Title string
|
||||
IsPassed bool
|
||||
}
|
||||
|
||||
// PointHyperlinkDto 外链任务点
|
||||
type PointHyperlinkDto struct {
|
||||
CardIndex int
|
||||
CourseID string
|
||||
ClassID string
|
||||
KnowledgeID int
|
||||
Cpi string
|
||||
ObjectID string
|
||||
Title string
|
||||
JobID string
|
||||
Jtoken string
|
||||
LinkType int // 外链类型
|
||||
IsJob bool // 是否是任务点
|
||||
}
|
||||
|
||||
// PointLiveDto 直播任务点
|
||||
type PointLiveDto struct {
|
||||
CardIndex int
|
||||
CourseID string
|
||||
ClassID string
|
||||
KnowledgeID int
|
||||
Cpi string
|
||||
UserId string // 用户ID
|
||||
Live bool
|
||||
LiveId string // 直播ID
|
||||
Vdoid string
|
||||
Mid string
|
||||
Title string // 直播标题
|
||||
JobID string
|
||||
StreamName string // 直播流名称
|
||||
LiveStatusStr string // 直播状态文字
|
||||
LiveStatusCode int // 直播状态码 0=未开始
|
||||
VideoDuration int // 视频时长
|
||||
Aid string
|
||||
Module string // 类型
|
||||
IsJob bool // 是否为任务点
|
||||
AuthEnc string
|
||||
LiveDragEnc string
|
||||
LiveSetEnc string
|
||||
OtherInfo string
|
||||
Enc string
|
||||
LiveSwDsEnc string
|
||||
VideoCompletePercent float64 // 观看进度
|
||||
}
|
||||
|
||||
// Card 任务点卡片信息
|
||||
type Card struct {
|
||||
ID int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
CardOrder int `json:"cardorder"`
|
||||
KnowledgeID int `json:"knowledgeid"`
|
||||
}
|
||||
|
||||
// CardAPIResponse 卡片API响应
|
||||
type CardAPIResponse struct {
|
||||
Data []CardDataItem `json:"data"`
|
||||
}
|
||||
|
||||
// CardDataItem 卡片数据项
|
||||
type CardDataItem struct {
|
||||
ClickCount int `json:"clickcount"`
|
||||
Createtime int64 `json:"createtime"`
|
||||
OpenLock int `json:"openlock"`
|
||||
IndexOrder int `json:"indexorder"`
|
||||
Name string `json:"name"`
|
||||
LastModifyTime int64 `json:"lastmodifytime"`
|
||||
ID int `json:"id"`
|
||||
Label string `json:"label"`
|
||||
Layer int `json:"layer"`
|
||||
Card struct {
|
||||
Data []Card `json:"data"`
|
||||
} `json:"card"`
|
||||
ParentNodeID int `json:"parentnodeid"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// IframeAttributes iframe 的属性
|
||||
type IframeAttributes struct {
|
||||
Data map[string]interface{} `json:"data"`
|
||||
Other map[string]string
|
||||
HasData bool
|
||||
}
|
||||
|
||||
// ChapterPointStatus 章节任务点状态
|
||||
type ChapterPointStatus map[string]struct {
|
||||
ClickCount int `json:"clickcount"`
|
||||
FinishCount int `json:"finishcount"`
|
||||
TotalCount int `json:"totalcount"`
|
||||
OpenLock int `json:"openlock"`
|
||||
UnFinishCount int `json:"unfinishcount"`
|
||||
}
|
||||
|
||||
// AttachmentSetting 附件设置(从页面JS中解析)
|
||||
type AttachmentSetting struct {
|
||||
Attachments []map[string]interface{} `json:"attachments"`
|
||||
Defaults map[string]interface{} `json:"defaults"`
|
||||
}
|
||||
|
||||
// ChapterPoints 章节所有任务点集合
|
||||
type ChapterPoints struct {
|
||||
Videos []PointVideoDto
|
||||
Documents []PointDocumentDto
|
||||
Works []PointWorkDto
|
||||
Hyperlinks []PointHyperlinkDto
|
||||
Lives []PointLiveDto
|
||||
}
|
||||
|
||||
// QuestionType 题目类型
|
||||
type QuestionType int
|
||||
|
||||
const (
|
||||
QuestionTypeSingleChoice QuestionType = 0 // 单选题
|
||||
QuestionTypeMultipleChoice QuestionType = 1 // 多选题
|
||||
QuestionTypeFillBlank QuestionType = 2 // 填空题
|
||||
QuestionTypeTrueFalse QuestionType = 3 // 判断题
|
||||
QuestionTypeShortAnswer QuestionType = 4 // 简答题
|
||||
)
|
||||
|
||||
// WorkQuestion 作业题目
|
||||
type WorkQuestion struct {
|
||||
Qid string `json:"qid"` // 题目ID
|
||||
Type QuestionType `json:"type"` // 题目类型
|
||||
Text string `json:"text"` // 题目内容
|
||||
Options map[string]string `json:"options"` // 选项 (A: xxx, B: xxx)
|
||||
Answers []string `json:"answers"` // 答案
|
||||
BlankCount int `json:"blankCount"` // 填空题空格数量
|
||||
BlankAnswer map[string]string `json:"blankAnswer"` // 填空题答案 (第1空: xxx)
|
||||
}
|
||||
|
||||
// WorkDto 作业详情
|
||||
type WorkDto struct {
|
||||
Title string `json:"title"` // 作业标题
|
||||
Cpi string `json:"cpi"` // cpi
|
||||
JobId string `json:"jobId"` // 任务ID
|
||||
WorkId string `json:"workId"` // 作业ID
|
||||
ClassId string `json:"classId"` // 班级ID
|
||||
CourseId string `json:"courseId"` // 课程ID
|
||||
KnowledgeId string `json:"knowledgeId"` // 知识点ID
|
||||
UserId string `json:"userId"` // 用户ID
|
||||
FullScore string `json:"fullScore"` // 满分
|
||||
OldWorkId string `json:"oldWorkId"` // 原始作业ID
|
||||
OldSchoolId string `json:"oldSchoolId"` // 原始学校ID
|
||||
Api string `json:"api"` // API值
|
||||
WorkRelationId string `json:"workRelationId"` // 作业关联ID
|
||||
EncWork string `json:"encWork"` // 加密参数
|
||||
WorkAnswerId string `json:"workAnswerId"` // 作业答案ID
|
||||
AnswerId string `json:"answerId"` // 答案ID
|
||||
TotalQuestionNum string `json:"totalQuestionNum"` // 题目总数
|
||||
Questions []WorkQuestion `json:"questions"` // 题目列表
|
||||
}
|
||||
+8
-1
@@ -5,11 +5,13 @@ import (
|
||||
"likedream-goframe/internal/application/cookiejar"
|
||||
"likedream-goframe/internal/application/httpclient"
|
||||
"likedream-goframe/internal/application/xuexitong/cryptoutil"
|
||||
"likedream-goframe/internal/framework/errors"
|
||||
"likedream-goframe/internal/framework/logger"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"go.uber.org/zap"
|
||||
"resty.dev/v3"
|
||||
)
|
||||
@@ -24,10 +26,12 @@ type XuexitongLogin struct {
|
||||
|
||||
func NewXuexitongLogin(ctx context.Context) *XuexitongLogin {
|
||||
return &XuexitongLogin{
|
||||
client: httpclient.Xuexitong.Clone(ctx),
|
||||
client: httpclient.NewXuexitongClient(),
|
||||
}
|
||||
}
|
||||
func (c *XuexitongLogin) Login(ctx context.Context, username, password string, retry int) (err error) {
|
||||
jar := cookiejar.NewAllSavePersistCookieJar()
|
||||
c.client.SetCookieJar(jar)
|
||||
usernameEncrypted, err := cryptoutil.LoginEncrypt(username)
|
||||
if err != nil {
|
||||
logger.Logger.Error("LoginEncrypt err:", zap.Error(err))
|
||||
@@ -60,6 +64,9 @@ func (c *XuexitongLogin) Login(ctx context.Context, username, password string, r
|
||||
time.Sleep(time.Duration(retry*5) * time.Second)
|
||||
return c.Login(ctx, username, password, retry-1)
|
||||
}
|
||||
if !gjson.Get(body, "status").Bool() {
|
||||
return errors.NewBusinessErrorWithDetail(401, "登录失败", gjson.Get(body, "msg2").String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,22 +3,14 @@ package xuexitong
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"likedream-goframe/internal/utils"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"resty.dev/v3"
|
||||
)
|
||||
|
||||
var randChar []string = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "A", "B", "C", "D", "E", "F"}
|
||||
|
||||
func ApiVerifyCode(client *resty.Client, retry int) (string, error) {
|
||||
if retry < 0 {
|
||||
return "", fmt.Errorf("retry limit exceeded")
|
||||
}
|
||||
// ApiVerifyCodeBytes 获取学习通验证码图片
|
||||
func ApiVerifyCodeBytes(client *resty.Client) ([]byte, error) {
|
||||
urlStr := "https://mooc1-api.chaoxing.com/processVerifyPng.ac?t=" + fmt.Sprintf("%d", time.Now().UnixMilli())
|
||||
|
||||
req := client.R()
|
||||
@@ -28,44 +20,19 @@ func ApiVerifyCode(client *resty.Client, retry int) (string, error) {
|
||||
req.Header.Add("Connection", "keep-alive")
|
||||
res, err := req.Get(urlStr)
|
||||
if err != nil {
|
||||
if retry > 0 {
|
||||
return ApiVerifyCode(client, retry-1)
|
||||
} else {
|
||||
return res.String(), err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
codeFileName := "code" + randChar[rand.Intn(len(randChar))] //生成验证码文件名称
|
||||
for i := 0; i < 10; i++ {
|
||||
codeFileName += randChar[rand.Intn(len(randChar))]
|
||||
}
|
||||
codeFileName += ".png"
|
||||
utils.PathExistForCreate("./assets/code/") //检测是否存在路径,如果不存在则创建
|
||||
filepath := fmt.Sprintf("./assets/code/%s", codeFileName)
|
||||
file, err := os.Create(filepath)
|
||||
defer res.Body.Close()
|
||||
all, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
res.Body.Close() //立即释放
|
||||
log.Println(err)
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = io.Copy(file, res.Body)
|
||||
if err != nil {
|
||||
res.Body.Close() //立即释放
|
||||
log.Println(err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
if utils.IsBadImg(filepath) {
|
||||
res.Body.Close() //立即释放
|
||||
utils.DeleteFile(filepath) //删除坏的文件
|
||||
return ApiVerifyCode(client, retry-1)
|
||||
}
|
||||
return filepath, nil
|
||||
return all, nil
|
||||
}
|
||||
|
||||
func ApiPassVerifyCode(client *resty.Client, code string, retry int) bool {
|
||||
if retry < 0 {
|
||||
// ApiPassVerifyCode 提交学习通验证码
|
||||
func ApiPassVerifyCode(client *resty.Client, code string, retryCount int) bool {
|
||||
if retryCount < 0 {
|
||||
return false
|
||||
}
|
||||
urlStr := "https://mooc1-api.chaoxing.com/html/processVerify.ac"
|
||||
@@ -79,7 +46,7 @@ func ApiPassVerifyCode(client *resty.Client, code string, retry int) bool {
|
||||
req.Header.Add("Connection", "keep-alive")
|
||||
res, err := req.Post(urlStr)
|
||||
if err != nil {
|
||||
return ApiPassVerifyCode(client, code, retry-1)
|
||||
return ApiPassVerifyCode(client, code, retryCount-1)
|
||||
}
|
||||
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20))
|
||||
return res.StatusCode() == 302
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
package xuexitong
|
||||
|
||||
import (
|
||||
"context"
|
||||
"likedream-goframe/internal/utils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestXuexitongLogin(t *testing.T) {
|
||||
xuexitongLogin := NewXuexitongLogin(context.Background())
|
||||
err := xuexitongLogin.Login(context.Background(), "13551503012", "xiaozhi520", 5)
|
||||
utils.OkOrPanic(err)
|
||||
client := xuexitongLogin.GetClient()
|
||||
courseAction := NewXuexitongCourse(client)
|
||||
list, err := courseAction.PullCourseList(context.Background(), 5)
|
||||
utils.OkOrPanic(err)
|
||||
t.Log(list)
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package xuexitong
|
||||
|
||||
import (
|
||||
"context"
|
||||
"likedream-goframe/internal/framework/errors"
|
||||
"likedream-goframe/internal/utils"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSchedule(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
xuexitongLogin := NewXuexitongLogin(ctx)
|
||||
err := xuexitongLogin.Login(context.Background(), "13151832241", "yyz@083422", 5)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
client := xuexitongLogin.GetClient()
|
||||
courseService := NewXuexitongCourse(client)
|
||||
|
||||
// 人人必修的人工智能课
|
||||
err = courseService.AutoStudyByCourseID(ctx, "258109701")
|
||||
if err != nil {
|
||||
utils.OkOrPanic(errors.NewBusinessErrorWithDetail(503, "刷课失败", err))
|
||||
}
|
||||
}
|
||||
|
||||
func TestXuexitongLogin(t *testing.T) {
|
||||
xuexitongLogin := NewXuexitongLogin(context.Background())
|
||||
err := xuexitongLogin.Login(context.Background(), "13551503012", "xiaozhi520", 5)
|
||||
utils.OkOrPanic(err)
|
||||
}
|
||||
|
||||
func TestPullCourse(t *testing.T) {
|
||||
xuexitongLogin := NewXuexitongLogin(context.Background())
|
||||
err := xuexitongLogin.Login(context.Background(), "13551503012", "xiaozhi520", 5)
|
||||
utils.OkOrPanic(err)
|
||||
client := xuexitongLogin.GetClient()
|
||||
courseAction := NewXuexitongCourse(client)
|
||||
list := courseAction.PullCourseList(context.Background())
|
||||
utils.OkOrPanic(err)
|
||||
t.Log(list)
|
||||
}
|
||||
|
||||
func TestPullChapter(t *testing.T) {
|
||||
xuexitongLogin := NewXuexitongLogin(context.Background())
|
||||
err := xuexitongLogin.Login(context.Background(), "13551503012", "xiaozhi520", 5)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
client := xuexitongLogin.GetClient()
|
||||
courseAction := NewXuexitongCourse(client)
|
||||
|
||||
// 先获取课程列表
|
||||
courseList := courseAction.PullCourseList(context.Background())
|
||||
if len(courseList) == 0 {
|
||||
t.Fatal("没有找到课程")
|
||||
}
|
||||
|
||||
// 获取第一个课程的章节
|
||||
chapters := courseAction.PullCourseChapterList(context.Background(), courseList[0])
|
||||
t.Logf("课程 %s 的章节数量: %d", courseList[0].CourseName, len(chapters))
|
||||
|
||||
for _, chapter := range chapters {
|
||||
t.Logf("章节: %s, 任务点数量: %d", chapter.Name, chapter.JobCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchChapterCards(t *testing.T) {
|
||||
xuexitongLogin := NewXuexitongLogin(context.Background())
|
||||
err := xuexitongLogin.Login(context.Background(), "13551503012", "xiaozhi520", 5)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
client := xuexitongLogin.GetClient()
|
||||
courseAction := NewXuexitongCourse(client)
|
||||
|
||||
// 获取课程列表
|
||||
courseList := courseAction.PullCourseList(context.Background())
|
||||
if len(courseList) == 0 {
|
||||
t.Fatal("没有找到课程")
|
||||
}
|
||||
|
||||
course := courseList[0]
|
||||
|
||||
// 获取章节列表
|
||||
chapters := courseAction.PullCourseChapterList(context.Background(), course)
|
||||
if len(chapters) == 0 {
|
||||
t.Fatal("没有找到章节")
|
||||
}
|
||||
|
||||
// 找一个有任务点的章节
|
||||
var targetChapterID int
|
||||
for _, ch := range chapters {
|
||||
if ch.JobCount > 0 {
|
||||
targetChapterID = ch.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if targetChapterID == 0 {
|
||||
t.Fatal("没有找到有任务点的章节")
|
||||
}
|
||||
|
||||
// 获取任务点卡片
|
||||
cards, points, err := courseAction.FetchChapterCards(context.Background(), course, targetChapterID)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
t.Logf("卡片数量: %d", len(cards))
|
||||
if points != nil {
|
||||
t.Logf("视频数量: %d, 文档数量: %d, 作业数量: %d, 外链数量: %d, 直播数量: %d",
|
||||
len(points.Videos), len(points.Documents), len(points.Works),
|
||||
len(points.Hyperlinks), len(points.Lives))
|
||||
|
||||
for _, video := range points.Videos {
|
||||
t.Logf("视频任务点: JobID=%s, ObjectID=%s", video.JobID, video.ObjectID)
|
||||
}
|
||||
for _, doc := range points.Documents {
|
||||
t.Logf("文档任务点: JobID=%s, Type=%s", doc.JobID, doc.Type)
|
||||
}
|
||||
for _, work := range points.Works {
|
||||
t.Logf("作业任务点: JobID=%s, WorkID=%s", work.JobID, work.WorkID)
|
||||
}
|
||||
for _, link := range points.Hyperlinks {
|
||||
t.Logf("外链任务点: JobID=%s", link.JobID)
|
||||
}
|
||||
for _, live := range points.Lives {
|
||||
t.Logf("直播任务点: JobID=%s, LiveId=%s, Title=%s", live.JobID, live.LiveId, live.Title)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestAutoStudyByCourseID 测试通过课程ID刷课(定时任务使用)
|
||||
func TestAutoStudyByCourseID(t *testing.T) {
|
||||
// 登录
|
||||
xuexitongLogin := NewXuexitongLogin(context.Background())
|
||||
err := xuexitongLogin.Login(context.Background(), "13551503012", "xiaozhi520", 5)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
// 创建课程实例
|
||||
courseAction := NewXuexitongCourse(xuexitongLogin.GetClient())
|
||||
|
||||
// 先获取课程列表,拿到第一个课程的ID
|
||||
courseList := courseAction.PullCourseList(context.Background())
|
||||
if len(courseList) == 0 {
|
||||
t.Fatal("没有找到课程")
|
||||
}
|
||||
|
||||
courseID := courseList[0].CourseID
|
||||
t.Logf("准备刷课程ID: %s", courseID)
|
||||
|
||||
// 一键刷指定课程的所有任务(定时任务就调用这一个方法)
|
||||
err = courseAction.AutoStudyByCourseID(context.Background(), courseID)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
t.Log("指定课程刷课完成")
|
||||
}
|
||||
|
||||
// TestAutoStudyAllCourses 测试自动刷所有课程
|
||||
func TestAutoStudyAllCourses(t *testing.T) {
|
||||
// 登录
|
||||
xuexitongLogin := NewXuexitongLogin(context.Background())
|
||||
err := xuexitongLogin.Login(context.Background(), "13551503012", "xiaozhi520", 5)
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
// 创建课程实例
|
||||
courseAction := NewXuexitongCourse(xuexitongLogin.GetClient())
|
||||
|
||||
// 一键刷所有课程
|
||||
err = courseAction.AutoStudyAllCourses(context.Background())
|
||||
utils.OkOrPanic(err)
|
||||
|
||||
t.Log("所有课程刷课完成")
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package xuexitong
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
crand "crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -34,7 +34,7 @@ func GetUA(uaType string) string {
|
||||
|
||||
return strings.Join([]string{
|
||||
fmt.Sprintf("Mozilla/5.0 (Linux; %s; %s Build/OPM1.171019.019; wv)", ANDROID_VERSION, DEVICE_VENDOR),
|
||||
fmt.Sprintf("AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36"),
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36",
|
||||
fmt.Sprintf("(schild:%s)", MobileUASign(DEVICE_VENDOR, "zh_CN", APP_VERSION, BUILD, IMEI)),
|
||||
fmt.Sprintf("(device:%s)", DEVICE_VENDOR),
|
||||
"Language/zh_CN",
|
||||
@@ -48,15 +48,14 @@ func GetUA(uaType string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// 用于生成IMEI
|
||||
func TokenHex(len int) string {
|
||||
b := make([]byte, 16)
|
||||
_, err := rand.Read(b)
|
||||
// TokenHex 用于生成IMEI
|
||||
func TokenHex(length int) string {
|
||||
b := make([]byte, length)
|
||||
_, err := crand.Read(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
token := hex.EncodeToString(b)
|
||||
return token
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
func MobileUASign(model, locale, version, build, imei string) string {
|
||||
|
||||
@@ -8,13 +8,13 @@ const (
|
||||
ConfigDatabaseType = "database.type"
|
||||
ConfigDatabaseDsn = "database.dsn"
|
||||
ConfigDatabaseDsn2 = "database.dsn2"
|
||||
ConfigServerPort = "server.port"
|
||||
ConfigEmailConfirmBaseUrl = "server.emailConfirmBaseUrl"
|
||||
ConfigEmailResetPasswordUrl = "server.emailResetPasswordUrl"
|
||||
ConfigBalanceMigrateUrl = "server.balanceMigrateUrl"
|
||||
ConfigAuthorizationKey = "server.authorization"
|
||||
ConfigServerPort = "server.port"
|
||||
ConfigEmailConfirmBaseUrl = "server.emailConfirmBaseUrl"
|
||||
ConfigEmailResetPasswordUrl = "server.emailResetPasswordUrl"
|
||||
ConfigBalanceMigrateUrl = "server.balanceMigrateUrl"
|
||||
ConfigAuthorizationKey = "server.authorization"
|
||||
ConfigJwtKey = "server.jwt"
|
||||
ConfigRuoliCaptchaBaseUrl = "ruoliCaptcha.baseUrl"
|
||||
ConfigCaptchaBaseUrl = "captcha.baseUrl"
|
||||
ConfigS3AccessKey = "s3.accessKey"
|
||||
ConfigS3SecretKey = "s3.secretKey"
|
||||
ConfigS3BaseUrl = "s3.baseUrl"
|
||||
@@ -22,6 +22,7 @@ const (
|
||||
ConfigCpdailyAppVersion = "cpdaily.appVersion"
|
||||
ConfigCpdailySystemVersion = "cpdaily.systemVersion"
|
||||
ConfigCpdailyCalVersion = "cpdaily.calVersion"
|
||||
ConfigSliderSchoolIds = "cpdaily.sliderIds"
|
||||
|
||||
ConfigRedisUrl = "redis.url"
|
||||
|
||||
@@ -34,6 +35,11 @@ const (
|
||||
ConfigEmailSMTPPassword = "email.smtpPassword"
|
||||
ConfigEmailFromEmail = "email.fromEmail"
|
||||
ConfigEmailFromName = "email.fromName"
|
||||
|
||||
// 基础积分配置
|
||||
ConfigBasePointCpdailyTask = "basePoint.cpdailyTask"
|
||||
ConfigBasePointCpdailyLeave = "basePoint.cpdailyLeave"
|
||||
ConfigBasePointCpdailyPhone = "basePoint.cpdailyPhone"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -3,4 +3,8 @@ package cst
|
||||
const (
|
||||
CtxUserInfo = "ctx_user_info"
|
||||
CtxPermissionList = "ctx_permission_list"
|
||||
|
||||
CtxCpdailyDeviceID = "cpdaily_device_id"
|
||||
CtxCpdailySessionToken = "cpdaily_session_token"
|
||||
CtxCpdailyTenantID = "cpdaily_tenant_id"
|
||||
)
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package cst
|
||||
|
||||
const (
|
||||
TaskCpdaily = "task:cpdaily"
|
||||
TaskEmail = "task:email"
|
||||
TaskResetDaily = "task:reset:daily"
|
||||
TaskCpdaily = "task:cpdaily"
|
||||
TaskEmail = "task:email"
|
||||
TaskResetDaily = "task:reset:daily"
|
||||
TaskXuexitong = "task:xuexitong"
|
||||
TaskXuexitongVio = "task:xuexitong:violence"
|
||||
|
||||
TaskCpdailyId = "cpdaily:task:schedule:%d"
|
||||
|
||||
TaskQueueCpdaily = "queue:cpdaily"
|
||||
TaskQueueEmail = "queue:email"
|
||||
TaskQueueDefault = "default"
|
||||
TaskQueueCpdaily = "queue:cpdaily"
|
||||
TaskQueueEmail = "queue:email"
|
||||
TaskQueueXuexitong = "queue:xuexitong"
|
||||
TaskQueueXuexitongVio = "queue:xuexitong:violence"
|
||||
TaskQueueDefault = "default"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package balance
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type BalanceCtrlV1 struct {
|
||||
}
|
||||
|
||||
func NewBalanceCtrlV1() IBalanceCtrlV1 {
|
||||
return &BalanceCtrlV1{}
|
||||
}
|
||||
|
||||
func (b BalanceCtrlV1) List(ctx context.Context, req *v1.BalanceRecordListReq) (res *utils.Response[[]*ent.SysBalanceRecord], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Balance.List(ctx, req), nil
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package balance
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type IBalanceCtrlV1 interface {
|
||||
List(ctx context.Context, req *v1.BalanceRecordListReq) (res *utils.Response[[]*ent.SysBalanceRecord], err error)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type ConfigCtrlV1 struct {
|
||||
}
|
||||
|
||||
func (c ConfigCtrlV1) Get(ctx context.Context, req *v1.ConfigGetReq) (res *utils.Response[*ent.SysConfig], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Config.Get(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c ConfigCtrlV1) PublicGet(ctx context.Context, req *v1.ConfigPublicGetReq) (res *utils.Response[*ent.SysConfig], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Config.PublicGet(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c ConfigCtrlV1) List(ctx context.Context, req *v1.ConfigListReq) (res *utils.Response[[]*ent.SysConfig], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Config.List(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c ConfigCtrlV1) Update(ctx context.Context, req *v1.ConfigUpdateReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Config.Update(ctx, req), nil
|
||||
}
|
||||
|
||||
func NewConfigCtrlV1() IConfigCtrlV1 {
|
||||
return &ConfigCtrlV1{}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type IConfigCtrlV1 interface {
|
||||
Get(ctx context.Context, req *v1.ConfigGetReq) (*utils.Response[*ent.SysConfig], error)
|
||||
PublicGet(ctx context.Context, req *v1.ConfigPublicGetReq) (*utils.Response[*ent.SysConfig], error)
|
||||
List(ctx context.Context, req *v1.ConfigListReq) (*utils.Response[[]*ent.SysConfig], error)
|
||||
Update(ctx context.Context, req *v1.ConfigUpdateReq) (*utils.Response[any], error)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package course
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/application/xuexitong/entity"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type IXxtCtrlV1 interface {
|
||||
List(ctx context.Context, req *v1.CourseListReq) (*utils.Response[[]*ent.CourseEntity], error)
|
||||
AddCourse(ctx context.Context, req *v1.AddCourseReq) (*utils.Response[any], error)
|
||||
UpdatePassword(ctx context.Context, req *v1.UpdateCoursePasswordReq) (*utils.Response[any], error)
|
||||
RestartCourse(ctx context.Context, req *v1.RestartCourseReq) (*utils.Response[any], error)
|
||||
PauseCourse(ctx context.Context, req *v1.PauseCourseReq) (*utils.Response[any], error)
|
||||
DeleteCourse(ctx context.Context, req *v1.DeleteCourseReq) (*utils.Response[any], error)
|
||||
QueryCourses(ctx context.Context, req *v1.QueryCourseReq) (*utils.Response[[]entity.XueXiTCourse], error)
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package course
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/application/xuexitong/entity"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type XxtCtrlV1 struct {
|
||||
}
|
||||
|
||||
// List 获取刷课列表
|
||||
func (c XxtCtrlV1) List(ctx context.Context, req *v1.CourseListReq) (res *utils.Response[[]*ent.CourseEntity], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Course.List(ctx, req), nil
|
||||
}
|
||||
|
||||
// AddCourse 添加刷课
|
||||
func (c XxtCtrlV1) AddCourse(ctx context.Context, req *v1.AddCourseReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Course.AddCourse(ctx, req), nil
|
||||
}
|
||||
|
||||
// UpdatePassword 修改刷课密码
|
||||
func (c XxtCtrlV1) UpdatePassword(ctx context.Context, req *v1.UpdateCoursePasswordReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Course.UpdatePassword(ctx, req), nil
|
||||
}
|
||||
|
||||
// RestartCourse 重刷课程
|
||||
func (c XxtCtrlV1) RestartCourse(ctx context.Context, req *v1.RestartCourseReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Course.RestartCourse(ctx, req), nil
|
||||
}
|
||||
|
||||
// PauseCourse 暂停刷课
|
||||
func (c XxtCtrlV1) PauseCourse(ctx context.Context, req *v1.PauseCourseReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Course.PauseCourse(ctx, req), nil
|
||||
}
|
||||
|
||||
// DeleteCourse 删除刷课
|
||||
func (c XxtCtrlV1) DeleteCourse(ctx context.Context, req *v1.DeleteCourseReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Course.DeleteCourse(ctx, req), nil
|
||||
}
|
||||
|
||||
// QueryCourses 查询课程列表
|
||||
func (c XxtCtrlV1) QueryCourses(ctx context.Context, req *v1.QueryCourseReq) (res *utils.Response[[]entity.XueXiTCourse], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.Course.QueryCourses(ctx, req), nil
|
||||
}
|
||||
|
||||
func NewXxtCtrlV1() IXxtCtrlV1 {
|
||||
return &XxtCtrlV1{}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package cpdaily
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type CpLeaveCtrlV1 struct {
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) GetLeaveListFromSystem(ctx context.Context, req *v1.GetLeaveListFromSystemReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.GetLeaveListFromSystem(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) List(ctx context.Context, req *v1.CpLeaveListReq) (res *utils.Response[[]*ent.CpLeave], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.List(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpLeaveCtrlV1) Report(ctx context.Context, req *v1.CpLeaveReportReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpLeave.Report(ctx, req), nil
|
||||
}
|
||||
|
||||
func NewCpLeaveCtrlV1() ICpLeaveCtrlV1 {
|
||||
return &CpLeaveCtrlV1{}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package cpdaily
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/application/cpdaily/map_info"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
@@ -11,6 +12,11 @@ import (
|
||||
type CpTaskCtrlV1 struct {
|
||||
}
|
||||
|
||||
func (c CpTaskCtrlV1) FindLocation(ctx context.Context, req *v1.FindLocationReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return utils.SuccessWithData[any](map_info.SearchAddressLongitudeAndLatitude(ctx, req.Address)), nil
|
||||
}
|
||||
|
||||
func (c CpTaskCtrlV1) List(ctx context.Context, req *v1.CpTaskListReq) (res *utils.Response[[]*ent.CpTask], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpTask.List(ctx, req), nil
|
||||
@@ -59,6 +65,12 @@ func (c CpTaskCtrlV1) PauseTask(ctx context.Context, req *v1.PauseTaskReq) (res
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpTask.PauseTask(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpTaskCtrlV1) GetTaskStatistics(ctx context.Context, req *v1.GetTaskStatisticsReq) (res *utils.Response[[]*v1.TaskStatisticsItem], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpTask.GetTaskStatistics(ctx, req), nil
|
||||
}
|
||||
|
||||
func NewCpTaskCtrlV1() ICpTaskCtrlV1 {
|
||||
return &CpTaskCtrlV1{}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@ package cpdaily
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/application/recognizer/classifier"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
@@ -13,14 +11,6 @@ import (
|
||||
type CpTaskLogCtrlV1 struct {
|
||||
}
|
||||
|
||||
func (c CpTaskLogCtrlV1) OCR(ctx context.Context, req *v1.CpTaskOCRReq) (res *utils.Response[any], err error) {
|
||||
file, _ := req.File.Open()
|
||||
defer file.Close()
|
||||
bytes, _ := io.ReadAll(file)
|
||||
result := classifier.ClassifyImage(bytes, req.Name)
|
||||
return utils.SuccessWithData[any](result), nil
|
||||
}
|
||||
|
||||
func (c CpTaskLogCtrlV1) List(ctx context.Context, req *v1.CpTaskLogListReq) (res *utils.Response[[]*ent.CpTaskLog], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpTaskLog.List(ctx, req), nil
|
||||
|
||||
@@ -4,8 +4,12 @@ import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/framework/captcha"
|
||||
"likedream-goframe/internal/framework/redis"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
)
|
||||
|
||||
type CpUserCtrlV1 struct {
|
||||
@@ -15,6 +19,11 @@ func NewCpUserCtrlV1() ICpUserCtrlV1 {
|
||||
return &CpUserCtrlV1{}
|
||||
}
|
||||
|
||||
func (c CpUserCtrlV1) LoginUrl(ctx context.Context, req *v1.CpUserLoginUrlReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpUser.LoginUrl(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpUserCtrlV1) Add(ctx context.Context, req *v1.CpUserAddReq) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpUser.Add(ctx, req), nil
|
||||
@@ -61,3 +70,34 @@ func (c CpUserCtrlV1) AuthorizeRandom(ctx context.Context, req *v1.CpUserAuthori
|
||||
defer utils.Pass(&err)
|
||||
return service.Global.CpUser.AuthorizeRandom(ctx, req), nil
|
||||
}
|
||||
func (c CpUserCtrlV1) LoginGetCode(ctx context.Context, req *v1.LoginGetCode) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
client := redis.GetClient()
|
||||
dotsStr := client.GetDel(ctx, req.CaptchaKey).Val()
|
||||
if dotsStr == "" {
|
||||
return utils.Fail(10003, "验证码错误"), nil
|
||||
}
|
||||
var dots captcha.ConfirmData
|
||||
err = sonic.Unmarshal([]byte(dotsStr), &dots)
|
||||
utils.OkOrPanic(err)
|
||||
if !captcha.VerifyCaptcha(dots, req.Dots) {
|
||||
return utils.Fail(10003, "验证码错误"), nil
|
||||
}
|
||||
return service.Global.CpUser.LoginGetCode(ctx, req), nil
|
||||
}
|
||||
|
||||
func (c CpUserCtrlV1) AddByCode(ctx context.Context, req *v1.AddByCode) (res *utils.Response[any], err error) {
|
||||
defer utils.Pass(&err)
|
||||
client := redis.GetClient()
|
||||
dotsStr := client.GetDel(ctx, req.CaptchaKey).Val()
|
||||
if dotsStr == "" {
|
||||
return utils.Fail(10003, "验证码错误"), nil
|
||||
}
|
||||
var dots captcha.ConfirmData
|
||||
err = sonic.Unmarshal([]byte(dotsStr), &dots)
|
||||
utils.OkOrPanic(err)
|
||||
if !captcha.VerifyCaptcha(dots, req.Dots) {
|
||||
return utils.Fail(10003, "验证码错误"), nil
|
||||
}
|
||||
return service.Global.CpUser.AddByCode(ctx, req), nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package cpdaily
|
||||
|
||||
import (
|
||||
"context"
|
||||
v1 "likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/ent"
|
||||
"likedream-goframe/internal/utils"
|
||||
)
|
||||
|
||||
type ICpLeaveCtrlV1 interface {
|
||||
GetLeaveListFromSystem(ctx context.Context, req *v1.GetLeaveListFromSystemReq) (*utils.Response[any], error)
|
||||
List(ctx context.Context, req *v1.CpLeaveListReq) (*utils.Response[[]*ent.CpLeave], error)
|
||||
Report(ctx context.Context, req *v1.CpLeaveReportReq) (*utils.Response[any], error)
|
||||
}
|
||||
@@ -18,4 +18,6 @@ type ICpTaskCtrlV1 interface {
|
||||
Delete(ctx context.Context, req *v1.DeleteTaskReq) (res *utils.Response[any], err error)
|
||||
ExecuteNow(ctx context.Context, req *v1.ExecuteNowReq) (res *utils.Response[any], err error)
|
||||
PauseTask(ctx context.Context, req *v1.PauseTaskReq) (res *utils.Response[any], err error)
|
||||
FindLocation(ctx context.Context, req *v1.FindLocationReq) (res *utils.Response[any], err error)
|
||||
GetTaskStatistics(ctx context.Context, req *v1.GetTaskStatisticsReq) (res *utils.Response[[]*v1.TaskStatisticsItem], err error)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,4 @@ import (
|
||||
|
||||
type ICpTaskLogCtrlV1 interface {
|
||||
List(ctx context.Context, req *v1.CpTaskLogListReq) (res *utils.Response[[]*ent.CpTaskLog], err error)
|
||||
|
||||
OCR(ctx context.Context, req *v1.CpTaskOCRReq) (res *utils.Response[any], err error)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
)
|
||||
|
||||
type ICpUserCtrlV1 interface {
|
||||
LoginUrl(ctx context.Context, req *v1.CpUserLoginUrlReq) (res *utils.Response[any], err error)
|
||||
|
||||
SchoolList(ctx context.Context, req *v1.CpSchoolListReq) (*utils.Response[[]*ent.CpSchool], error)
|
||||
// 添加用户
|
||||
Add(ctx context.Context, req *v1.CpUserAddReq) (*utils.Response[any], error)
|
||||
@@ -25,4 +27,8 @@ type ICpUserCtrlV1 interface {
|
||||
AuthorizeConfirm(ctx context.Context, req *v1.CpUserAuthorizeConfirmReq) (*utils.Response[any], error)
|
||||
// 随机授权
|
||||
AuthorizeRandom(ctx context.Context, req *v1.CpUserAuthorizeRandomReq) (res *utils.Response[any], err error)
|
||||
|
||||
// 手机登录获取验证码
|
||||
LoginGetCode(ctx context.Context, req *v1.LoginGetCode) (*utils.Response[any], error)
|
||||
AddByCode(ctx context.Context, req *v1.AddByCode) (*utils.Response[any], error)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"likedream-goframe/internal/api/v1"
|
||||
"likedream-goframe/internal/framework/captcha"
|
||||
"likedream-goframe/internal/framework/errors"
|
||||
"likedream-goframe/internal/framework/redis"
|
||||
"likedream-goframe/internal/service"
|
||||
"likedream-goframe/internal/utils"
|
||||
@@ -46,6 +47,7 @@ func (c *UserLoginV1) Login(ctx context.Context, req *v1.UserLoginReq) (res *uti
|
||||
if !captcha.VerifyCaptcha(dots, req.Dots) {
|
||||
return utils.Fail(10003, "验证码错误"), nil
|
||||
}
|
||||
|
||||
return service.Global.UserLogin.Login(ctx, req), nil
|
||||
}
|
||||
|
||||
@@ -62,6 +64,7 @@ func (c *UserLoginV1) Register(ctx context.Context, req *v1.UserRegisterReq) (re
|
||||
if !captcha.VerifyCaptcha(dots, req.Dots) {
|
||||
return utils.Fail(10003, "验证码错误"), nil
|
||||
}
|
||||
utils.OkOrPanic(errors.NewBusinessError(400, "注册功能暂时关闭,请等待重新开放"))
|
||||
return service.Global.UserLogin.Register(ctx, req), nil
|
||||
}
|
||||
|
||||
|
||||
+759
-35
@@ -11,13 +11,17 @@ import (
|
||||
|
||||
"likedream-goframe/internal/ent/migrate"
|
||||
|
||||
"likedream-goframe/internal/ent/courseentity"
|
||||
"likedream-goframe/internal/ent/cpimage"
|
||||
"likedream-goframe/internal/ent/cpleave"
|
||||
"likedream-goframe/internal/ent/cpschool"
|
||||
"likedream-goframe/internal/ent/cptask"
|
||||
"likedream-goframe/internal/ent/cptasklog"
|
||||
"likedream-goframe/internal/ent/cpuser"
|
||||
"likedream-goframe/internal/ent/sysagent"
|
||||
"likedream-goframe/internal/ent/sysbalancerecord"
|
||||
"likedream-goframe/internal/ent/syscard"
|
||||
"likedream-goframe/internal/ent/sysconfig"
|
||||
"likedream-goframe/internal/ent/sysmenu"
|
||||
"likedream-goframe/internal/ent/sysrole"
|
||||
"likedream-goframe/internal/ent/sysuser"
|
||||
@@ -37,8 +41,12 @@ type Client struct {
|
||||
config
|
||||
// Schema is the client for creating, migrating and dropping schema.
|
||||
Schema *migrate.Schema
|
||||
// CourseEntity is the client for interacting with the CourseEntity builders.
|
||||
CourseEntity *CourseEntityClient
|
||||
// CpImage is the client for interacting with the CpImage builders.
|
||||
CpImage *CpImageClient
|
||||
// CpLeave is the client for interacting with the CpLeave builders.
|
||||
CpLeave *CpLeaveClient
|
||||
// CpSchool is the client for interacting with the CpSchool builders.
|
||||
CpSchool *CpSchoolClient
|
||||
// CpTask is the client for interacting with the CpTask builders.
|
||||
@@ -49,8 +57,12 @@ type Client struct {
|
||||
CpUser *CpUserClient
|
||||
// SysAgent is the client for interacting with the SysAgent builders.
|
||||
SysAgent *SysAgentClient
|
||||
// SysBalanceRecord is the client for interacting with the SysBalanceRecord builders.
|
||||
SysBalanceRecord *SysBalanceRecordClient
|
||||
// SysCard is the client for interacting with the SysCard builders.
|
||||
SysCard *SysCardClient
|
||||
// SysConfig is the client for interacting with the SysConfig builders.
|
||||
SysConfig *SysConfigClient
|
||||
// SysMenu is the client for interacting with the SysMenu builders.
|
||||
SysMenu *SysMenuClient
|
||||
// SysRole is the client for interacting with the SysRole builders.
|
||||
@@ -70,13 +82,17 @@ func NewClient(opts ...Option) *Client {
|
||||
|
||||
func (c *Client) init() {
|
||||
c.Schema = migrate.NewSchema(c.driver)
|
||||
c.CourseEntity = NewCourseEntityClient(c.config)
|
||||
c.CpImage = NewCpImageClient(c.config)
|
||||
c.CpLeave = NewCpLeaveClient(c.config)
|
||||
c.CpSchool = NewCpSchoolClient(c.config)
|
||||
c.CpTask = NewCpTaskClient(c.config)
|
||||
c.CpTaskLog = NewCpTaskLogClient(c.config)
|
||||
c.CpUser = NewCpUserClient(c.config)
|
||||
c.SysAgent = NewSysAgentClient(c.config)
|
||||
c.SysBalanceRecord = NewSysBalanceRecordClient(c.config)
|
||||
c.SysCard = NewSysCardClient(c.config)
|
||||
c.SysConfig = NewSysConfigClient(c.config)
|
||||
c.SysMenu = NewSysMenuClient(c.config)
|
||||
c.SysRole = NewSysRoleClient(c.config)
|
||||
c.SysUser = NewSysUserClient(c.config)
|
||||
@@ -173,19 +189,23 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) {
|
||||
cfg := c.config
|
||||
cfg.driver = tx
|
||||
return &Tx{
|
||||
ctx: ctx,
|
||||
config: cfg,
|
||||
CpImage: NewCpImageClient(cfg),
|
||||
CpSchool: NewCpSchoolClient(cfg),
|
||||
CpTask: NewCpTaskClient(cfg),
|
||||
CpTaskLog: NewCpTaskLogClient(cfg),
|
||||
CpUser: NewCpUserClient(cfg),
|
||||
SysAgent: NewSysAgentClient(cfg),
|
||||
SysCard: NewSysCardClient(cfg),
|
||||
SysMenu: NewSysMenuClient(cfg),
|
||||
SysRole: NewSysRoleClient(cfg),
|
||||
SysUser: NewSysUserClient(cfg),
|
||||
SysUserLog: NewSysUserLogClient(cfg),
|
||||
ctx: ctx,
|
||||
config: cfg,
|
||||
CourseEntity: NewCourseEntityClient(cfg),
|
||||
CpImage: NewCpImageClient(cfg),
|
||||
CpLeave: NewCpLeaveClient(cfg),
|
||||
CpSchool: NewCpSchoolClient(cfg),
|
||||
CpTask: NewCpTaskClient(cfg),
|
||||
CpTaskLog: NewCpTaskLogClient(cfg),
|
||||
CpUser: NewCpUserClient(cfg),
|
||||
SysAgent: NewSysAgentClient(cfg),
|
||||
SysBalanceRecord: NewSysBalanceRecordClient(cfg),
|
||||
SysCard: NewSysCardClient(cfg),
|
||||
SysConfig: NewSysConfigClient(cfg),
|
||||
SysMenu: NewSysMenuClient(cfg),
|
||||
SysRole: NewSysRoleClient(cfg),
|
||||
SysUser: NewSysUserClient(cfg),
|
||||
SysUserLog: NewSysUserLogClient(cfg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -203,26 +223,30 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error)
|
||||
cfg := c.config
|
||||
cfg.driver = &txDriver{tx: tx, drv: c.driver}
|
||||
return &Tx{
|
||||
ctx: ctx,
|
||||
config: cfg,
|
||||
CpImage: NewCpImageClient(cfg),
|
||||
CpSchool: NewCpSchoolClient(cfg),
|
||||
CpTask: NewCpTaskClient(cfg),
|
||||
CpTaskLog: NewCpTaskLogClient(cfg),
|
||||
CpUser: NewCpUserClient(cfg),
|
||||
SysAgent: NewSysAgentClient(cfg),
|
||||
SysCard: NewSysCardClient(cfg),
|
||||
SysMenu: NewSysMenuClient(cfg),
|
||||
SysRole: NewSysRoleClient(cfg),
|
||||
SysUser: NewSysUserClient(cfg),
|
||||
SysUserLog: NewSysUserLogClient(cfg),
|
||||
ctx: ctx,
|
||||
config: cfg,
|
||||
CourseEntity: NewCourseEntityClient(cfg),
|
||||
CpImage: NewCpImageClient(cfg),
|
||||
CpLeave: NewCpLeaveClient(cfg),
|
||||
CpSchool: NewCpSchoolClient(cfg),
|
||||
CpTask: NewCpTaskClient(cfg),
|
||||
CpTaskLog: NewCpTaskLogClient(cfg),
|
||||
CpUser: NewCpUserClient(cfg),
|
||||
SysAgent: NewSysAgentClient(cfg),
|
||||
SysBalanceRecord: NewSysBalanceRecordClient(cfg),
|
||||
SysCard: NewSysCardClient(cfg),
|
||||
SysConfig: NewSysConfigClient(cfg),
|
||||
SysMenu: NewSysMenuClient(cfg),
|
||||
SysRole: NewSysRoleClient(cfg),
|
||||
SysUser: NewSysUserClient(cfg),
|
||||
SysUserLog: NewSysUserLogClient(cfg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Debug returns a new debug-client. It's used to get verbose logging on specific operations.
|
||||
//
|
||||
// client.Debug().
|
||||
// CpImage.
|
||||
// CourseEntity.
|
||||
// Query().
|
||||
// Count(ctx)
|
||||
func (c *Client) Debug() *Client {
|
||||
@@ -245,8 +269,9 @@ func (c *Client) Close() error {
|
||||
// In order to add hooks to a specific client, call: `client.Node.Use(...)`.
|
||||
func (c *Client) Use(hooks ...Hook) {
|
||||
for _, n := range []interface{ Use(...Hook) }{
|
||||
c.CpImage, c.CpSchool, c.CpTask, c.CpTaskLog, c.CpUser, c.SysAgent, c.SysCard,
|
||||
c.SysMenu, c.SysRole, c.SysUser, c.SysUserLog,
|
||||
c.CourseEntity, c.CpImage, c.CpLeave, c.CpSchool, c.CpTask, c.CpTaskLog,
|
||||
c.CpUser, c.SysAgent, c.SysBalanceRecord, c.SysCard, c.SysConfig, c.SysMenu,
|
||||
c.SysRole, c.SysUser, c.SysUserLog,
|
||||
} {
|
||||
n.Use(hooks...)
|
||||
}
|
||||
@@ -256,8 +281,9 @@ func (c *Client) Use(hooks ...Hook) {
|
||||
// In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`.
|
||||
func (c *Client) Intercept(interceptors ...Interceptor) {
|
||||
for _, n := range []interface{ Intercept(...Interceptor) }{
|
||||
c.CpImage, c.CpSchool, c.CpTask, c.CpTaskLog, c.CpUser, c.SysAgent, c.SysCard,
|
||||
c.SysMenu, c.SysRole, c.SysUser, c.SysUserLog,
|
||||
c.CourseEntity, c.CpImage, c.CpLeave, c.CpSchool, c.CpTask, c.CpTaskLog,
|
||||
c.CpUser, c.SysAgent, c.SysBalanceRecord, c.SysCard, c.SysConfig, c.SysMenu,
|
||||
c.SysRole, c.SysUser, c.SysUserLog,
|
||||
} {
|
||||
n.Intercept(interceptors...)
|
||||
}
|
||||
@@ -266,8 +292,12 @@ func (c *Client) Intercept(interceptors ...Interceptor) {
|
||||
// Mutate implements the ent.Mutator interface.
|
||||
func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
|
||||
switch m := m.(type) {
|
||||
case *CourseEntityMutation:
|
||||
return c.CourseEntity.mutate(ctx, m)
|
||||
case *CpImageMutation:
|
||||
return c.CpImage.mutate(ctx, m)
|
||||
case *CpLeaveMutation:
|
||||
return c.CpLeave.mutate(ctx, m)
|
||||
case *CpSchoolMutation:
|
||||
return c.CpSchool.mutate(ctx, m)
|
||||
case *CpTaskMutation:
|
||||
@@ -278,8 +308,12 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
|
||||
return c.CpUser.mutate(ctx, m)
|
||||
case *SysAgentMutation:
|
||||
return c.SysAgent.mutate(ctx, m)
|
||||
case *SysBalanceRecordMutation:
|
||||
return c.SysBalanceRecord.mutate(ctx, m)
|
||||
case *SysCardMutation:
|
||||
return c.SysCard.mutate(ctx, m)
|
||||
case *SysConfigMutation:
|
||||
return c.SysConfig.mutate(ctx, m)
|
||||
case *SysMenuMutation:
|
||||
return c.SysMenu.mutate(ctx, m)
|
||||
case *SysRoleMutation:
|
||||
@@ -293,6 +327,159 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// CourseEntityClient is a client for the CourseEntity schema.
|
||||
type CourseEntityClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewCourseEntityClient returns a client for the CourseEntity from the given config.
|
||||
func NewCourseEntityClient(c config) *CourseEntityClient {
|
||||
return &CourseEntityClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `courseentity.Hooks(f(g(h())))`.
|
||||
func (c *CourseEntityClient) Use(hooks ...Hook) {
|
||||
c.hooks.CourseEntity = append(c.hooks.CourseEntity, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `courseentity.Intercept(f(g(h())))`.
|
||||
func (c *CourseEntityClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.CourseEntity = append(c.inters.CourseEntity, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a CourseEntity entity.
|
||||
func (c *CourseEntityClient) Create() *CourseEntityCreate {
|
||||
mutation := newCourseEntityMutation(c.config, OpCreate)
|
||||
return &CourseEntityCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of CourseEntity entities.
|
||||
func (c *CourseEntityClient) CreateBulk(builders ...*CourseEntityCreate) *CourseEntityCreateBulk {
|
||||
return &CourseEntityCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *CourseEntityClient) MapCreateBulk(slice any, setFunc func(*CourseEntityCreate, int)) *CourseEntityCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &CourseEntityCreateBulk{err: fmt.Errorf("calling to CourseEntityClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*CourseEntityCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &CourseEntityCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for CourseEntity.
|
||||
func (c *CourseEntityClient) Update() *CourseEntityUpdate {
|
||||
mutation := newCourseEntityMutation(c.config, OpUpdate)
|
||||
return &CourseEntityUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *CourseEntityClient) UpdateOne(_m *CourseEntity) *CourseEntityUpdateOne {
|
||||
mutation := newCourseEntityMutation(c.config, OpUpdateOne, withCourseEntity(_m))
|
||||
return &CourseEntityUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *CourseEntityClient) UpdateOneID(id int64) *CourseEntityUpdateOne {
|
||||
mutation := newCourseEntityMutation(c.config, OpUpdateOne, withCourseEntityID(id))
|
||||
return &CourseEntityUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for CourseEntity.
|
||||
func (c *CourseEntityClient) Delete() *CourseEntityDelete {
|
||||
mutation := newCourseEntityMutation(c.config, OpDelete)
|
||||
return &CourseEntityDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *CourseEntityClient) DeleteOne(_m *CourseEntity) *CourseEntityDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *CourseEntityClient) DeleteOneID(id int64) *CourseEntityDeleteOne {
|
||||
builder := c.Delete().Where(courseentity.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &CourseEntityDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for CourseEntity.
|
||||
func (c *CourseEntityClient) Query() *CourseEntityQuery {
|
||||
return &CourseEntityQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypeCourseEntity},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a CourseEntity entity by its id.
|
||||
func (c *CourseEntityClient) Get(ctx context.Context, id int64) (*CourseEntity, error) {
|
||||
return c.Query().Where(courseentity.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *CourseEntityClient) GetX(ctx context.Context, id int64) *CourseEntity {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// QuerySysUser queries the sys_user edge of a CourseEntity.
|
||||
func (c *CourseEntityClient) QuerySysUser(_m *CourseEntity) *SysUserQuery {
|
||||
query := (&SysUserClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(courseentity.Table, courseentity.FieldID, id),
|
||||
sqlgraph.To(sysuser.Table, sysuser.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, courseentity.SysUserTable, courseentity.SysUserColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.SysUser
|
||||
step.Edge.Schema = schemaConfig.CourseEntity
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *CourseEntityClient) Hooks() []Hook {
|
||||
hooks := c.hooks.CourseEntity
|
||||
return append(hooks[:len(hooks):len(hooks)], courseentity.Hooks[:]...)
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *CourseEntityClient) Interceptors() []Interceptor {
|
||||
return c.inters.CourseEntity
|
||||
}
|
||||
|
||||
func (c *CourseEntityClient) mutate(ctx context.Context, m *CourseEntityMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&CourseEntityCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&CourseEntityUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&CourseEntityUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&CourseEntityDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown CourseEntity mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// CpImageClient is a client for the CpImage schema.
|
||||
type CpImageClient struct {
|
||||
config
|
||||
@@ -446,6 +633,178 @@ func (c *CpImageClient) mutate(ctx context.Context, m *CpImageMutation) (Value,
|
||||
}
|
||||
}
|
||||
|
||||
// CpLeaveClient is a client for the CpLeave schema.
|
||||
type CpLeaveClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewCpLeaveClient returns a client for the CpLeave from the given config.
|
||||
func NewCpLeaveClient(c config) *CpLeaveClient {
|
||||
return &CpLeaveClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `cpleave.Hooks(f(g(h())))`.
|
||||
func (c *CpLeaveClient) Use(hooks ...Hook) {
|
||||
c.hooks.CpLeave = append(c.hooks.CpLeave, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `cpleave.Intercept(f(g(h())))`.
|
||||
func (c *CpLeaveClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.CpLeave = append(c.inters.CpLeave, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a CpLeave entity.
|
||||
func (c *CpLeaveClient) Create() *CpLeaveCreate {
|
||||
mutation := newCpLeaveMutation(c.config, OpCreate)
|
||||
return &CpLeaveCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of CpLeave entities.
|
||||
func (c *CpLeaveClient) CreateBulk(builders ...*CpLeaveCreate) *CpLeaveCreateBulk {
|
||||
return &CpLeaveCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *CpLeaveClient) MapCreateBulk(slice any, setFunc func(*CpLeaveCreate, int)) *CpLeaveCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &CpLeaveCreateBulk{err: fmt.Errorf("calling to CpLeaveClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*CpLeaveCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &CpLeaveCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for CpLeave.
|
||||
func (c *CpLeaveClient) Update() *CpLeaveUpdate {
|
||||
mutation := newCpLeaveMutation(c.config, OpUpdate)
|
||||
return &CpLeaveUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *CpLeaveClient) UpdateOne(_m *CpLeave) *CpLeaveUpdateOne {
|
||||
mutation := newCpLeaveMutation(c.config, OpUpdateOne, withCpLeave(_m))
|
||||
return &CpLeaveUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *CpLeaveClient) UpdateOneID(id int64) *CpLeaveUpdateOne {
|
||||
mutation := newCpLeaveMutation(c.config, OpUpdateOne, withCpLeaveID(id))
|
||||
return &CpLeaveUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for CpLeave.
|
||||
func (c *CpLeaveClient) Delete() *CpLeaveDelete {
|
||||
mutation := newCpLeaveMutation(c.config, OpDelete)
|
||||
return &CpLeaveDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *CpLeaveClient) DeleteOne(_m *CpLeave) *CpLeaveDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *CpLeaveClient) DeleteOneID(id int64) *CpLeaveDeleteOne {
|
||||
builder := c.Delete().Where(cpleave.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &CpLeaveDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for CpLeave.
|
||||
func (c *CpLeaveClient) Query() *CpLeaveQuery {
|
||||
return &CpLeaveQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypeCpLeave},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a CpLeave entity by its id.
|
||||
func (c *CpLeaveClient) Get(ctx context.Context, id int64) (*CpLeave, error) {
|
||||
return c.Query().Where(cpleave.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *CpLeaveClient) GetX(ctx context.Context, id int64) *CpLeave {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// QueryCpUser queries the cp_user edge of a CpLeave.
|
||||
func (c *CpLeaveClient) QueryCpUser(_m *CpLeave) *CpUserQuery {
|
||||
query := (&CpUserClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(cpleave.Table, cpleave.FieldID, id),
|
||||
sqlgraph.To(cpuser.Table, cpuser.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, cpleave.CpUserTable, cpleave.CpUserColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.CpUser
|
||||
step.Edge.Schema = schemaConfig.CpLeave
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// QuerySysUser queries the sys_user edge of a CpLeave.
|
||||
func (c *CpLeaveClient) QuerySysUser(_m *CpLeave) *SysUserQuery {
|
||||
query := (&SysUserClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(cpleave.Table, cpleave.FieldID, id),
|
||||
sqlgraph.To(sysuser.Table, sysuser.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, cpleave.SysUserTable, cpleave.SysUserColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.SysUser
|
||||
step.Edge.Schema = schemaConfig.CpLeave
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *CpLeaveClient) Hooks() []Hook {
|
||||
hooks := c.hooks.CpLeave
|
||||
return append(hooks[:len(hooks):len(hooks)], cpleave.Hooks[:]...)
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *CpLeaveClient) Interceptors() []Interceptor {
|
||||
return c.inters.CpLeave
|
||||
}
|
||||
|
||||
func (c *CpLeaveClient) mutate(ctx context.Context, m *CpLeaveMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&CpLeaveCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&CpLeaveUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&CpLeaveUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&CpLeaveDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown CpLeave mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// CpSchoolClient is a client for the CpSchool schema.
|
||||
type CpSchoolClient struct {
|
||||
config
|
||||
@@ -1108,6 +1467,25 @@ func (c *CpUserClient) QueryCptasks(_m *CpUser) *CpTaskQuery {
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryCpLeave queries the cp_leave edge of a CpUser.
|
||||
func (c *CpUserClient) QueryCpLeave(_m *CpUser) *CpLeaveQuery {
|
||||
query := (&CpLeaveClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(cpuser.Table, cpuser.FieldID, id),
|
||||
sqlgraph.To(cpleave.Table, cpleave.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, cpuser.CpLeaveTable, cpuser.CpLeaveColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.CpLeave
|
||||
step.Edge.Schema = schemaConfig.CpLeave
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// QuerySysuser queries the sysuser edge of a CpUser.
|
||||
func (c *CpUserClient) QuerySysuser(_m *CpUser) *SysUserQuery {
|
||||
query := (&SysUserClient{config: c.config}).Query()
|
||||
@@ -1344,6 +1722,159 @@ func (c *SysAgentClient) mutate(ctx context.Context, m *SysAgentMutation) (Value
|
||||
}
|
||||
}
|
||||
|
||||
// SysBalanceRecordClient is a client for the SysBalanceRecord schema.
|
||||
type SysBalanceRecordClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewSysBalanceRecordClient returns a client for the SysBalanceRecord from the given config.
|
||||
func NewSysBalanceRecordClient(c config) *SysBalanceRecordClient {
|
||||
return &SysBalanceRecordClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `sysbalancerecord.Hooks(f(g(h())))`.
|
||||
func (c *SysBalanceRecordClient) Use(hooks ...Hook) {
|
||||
c.hooks.SysBalanceRecord = append(c.hooks.SysBalanceRecord, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `sysbalancerecord.Intercept(f(g(h())))`.
|
||||
func (c *SysBalanceRecordClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.SysBalanceRecord = append(c.inters.SysBalanceRecord, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a SysBalanceRecord entity.
|
||||
func (c *SysBalanceRecordClient) Create() *SysBalanceRecordCreate {
|
||||
mutation := newSysBalanceRecordMutation(c.config, OpCreate)
|
||||
return &SysBalanceRecordCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of SysBalanceRecord entities.
|
||||
func (c *SysBalanceRecordClient) CreateBulk(builders ...*SysBalanceRecordCreate) *SysBalanceRecordCreateBulk {
|
||||
return &SysBalanceRecordCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *SysBalanceRecordClient) MapCreateBulk(slice any, setFunc func(*SysBalanceRecordCreate, int)) *SysBalanceRecordCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &SysBalanceRecordCreateBulk{err: fmt.Errorf("calling to SysBalanceRecordClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*SysBalanceRecordCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &SysBalanceRecordCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for SysBalanceRecord.
|
||||
func (c *SysBalanceRecordClient) Update() *SysBalanceRecordUpdate {
|
||||
mutation := newSysBalanceRecordMutation(c.config, OpUpdate)
|
||||
return &SysBalanceRecordUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *SysBalanceRecordClient) UpdateOne(_m *SysBalanceRecord) *SysBalanceRecordUpdateOne {
|
||||
mutation := newSysBalanceRecordMutation(c.config, OpUpdateOne, withSysBalanceRecord(_m))
|
||||
return &SysBalanceRecordUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *SysBalanceRecordClient) UpdateOneID(id int64) *SysBalanceRecordUpdateOne {
|
||||
mutation := newSysBalanceRecordMutation(c.config, OpUpdateOne, withSysBalanceRecordID(id))
|
||||
return &SysBalanceRecordUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for SysBalanceRecord.
|
||||
func (c *SysBalanceRecordClient) Delete() *SysBalanceRecordDelete {
|
||||
mutation := newSysBalanceRecordMutation(c.config, OpDelete)
|
||||
return &SysBalanceRecordDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *SysBalanceRecordClient) DeleteOne(_m *SysBalanceRecord) *SysBalanceRecordDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *SysBalanceRecordClient) DeleteOneID(id int64) *SysBalanceRecordDeleteOne {
|
||||
builder := c.Delete().Where(sysbalancerecord.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &SysBalanceRecordDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for SysBalanceRecord.
|
||||
func (c *SysBalanceRecordClient) Query() *SysBalanceRecordQuery {
|
||||
return &SysBalanceRecordQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypeSysBalanceRecord},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a SysBalanceRecord entity by its id.
|
||||
func (c *SysBalanceRecordClient) Get(ctx context.Context, id int64) (*SysBalanceRecord, error) {
|
||||
return c.Query().Where(sysbalancerecord.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *SysBalanceRecordClient) GetX(ctx context.Context, id int64) *SysBalanceRecord {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// QueryUser queries the user edge of a SysBalanceRecord.
|
||||
func (c *SysBalanceRecordClient) QueryUser(_m *SysBalanceRecord) *SysUserQuery {
|
||||
query := (&SysUserClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(sysbalancerecord.Table, sysbalancerecord.FieldID, id),
|
||||
sqlgraph.To(sysuser.Table, sysuser.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, sysbalancerecord.UserTable, sysbalancerecord.UserColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.SysUser
|
||||
step.Edge.Schema = schemaConfig.SysBalanceRecord
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *SysBalanceRecordClient) Hooks() []Hook {
|
||||
hooks := c.hooks.SysBalanceRecord
|
||||
return append(hooks[:len(hooks):len(hooks)], sysbalancerecord.Hooks[:]...)
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *SysBalanceRecordClient) Interceptors() []Interceptor {
|
||||
return c.inters.SysBalanceRecord
|
||||
}
|
||||
|
||||
func (c *SysBalanceRecordClient) mutate(ctx context.Context, m *SysBalanceRecordMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&SysBalanceRecordCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&SysBalanceRecordUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&SysBalanceRecordUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&SysBalanceRecordDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown SysBalanceRecord mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// SysCardClient is a client for the SysCard schema.
|
||||
type SysCardClient struct {
|
||||
config
|
||||
@@ -1535,6 +2066,140 @@ func (c *SysCardClient) mutate(ctx context.Context, m *SysCardMutation) (Value,
|
||||
}
|
||||
}
|
||||
|
||||
// SysConfigClient is a client for the SysConfig schema.
|
||||
type SysConfigClient struct {
|
||||
config
|
||||
}
|
||||
|
||||
// NewSysConfigClient returns a client for the SysConfig from the given config.
|
||||
func NewSysConfigClient(c config) *SysConfigClient {
|
||||
return &SysConfigClient{config: c}
|
||||
}
|
||||
|
||||
// Use adds a list of mutation hooks to the hooks stack.
|
||||
// A call to `Use(f, g, h)` equals to `sysconfig.Hooks(f(g(h())))`.
|
||||
func (c *SysConfigClient) Use(hooks ...Hook) {
|
||||
c.hooks.SysConfig = append(c.hooks.SysConfig, hooks...)
|
||||
}
|
||||
|
||||
// Intercept adds a list of query interceptors to the interceptors stack.
|
||||
// A call to `Intercept(f, g, h)` equals to `sysconfig.Intercept(f(g(h())))`.
|
||||
func (c *SysConfigClient) Intercept(interceptors ...Interceptor) {
|
||||
c.inters.SysConfig = append(c.inters.SysConfig, interceptors...)
|
||||
}
|
||||
|
||||
// Create returns a builder for creating a SysConfig entity.
|
||||
func (c *SysConfigClient) Create() *SysConfigCreate {
|
||||
mutation := newSysConfigMutation(c.config, OpCreate)
|
||||
return &SysConfigCreate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// CreateBulk returns a builder for creating a bulk of SysConfig entities.
|
||||
func (c *SysConfigClient) CreateBulk(builders ...*SysConfigCreate) *SysConfigCreateBulk {
|
||||
return &SysConfigCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates
|
||||
// a builder and applies setFunc on it.
|
||||
func (c *SysConfigClient) MapCreateBulk(slice any, setFunc func(*SysConfigCreate, int)) *SysConfigCreateBulk {
|
||||
rv := reflect.ValueOf(slice)
|
||||
if rv.Kind() != reflect.Slice {
|
||||
return &SysConfigCreateBulk{err: fmt.Errorf("calling to SysConfigClient.MapCreateBulk with wrong type %T, need slice", slice)}
|
||||
}
|
||||
builders := make([]*SysConfigCreate, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
builders[i] = c.Create()
|
||||
setFunc(builders[i], i)
|
||||
}
|
||||
return &SysConfigCreateBulk{config: c.config, builders: builders}
|
||||
}
|
||||
|
||||
// Update returns an update builder for SysConfig.
|
||||
func (c *SysConfigClient) Update() *SysConfigUpdate {
|
||||
mutation := newSysConfigMutation(c.config, OpUpdate)
|
||||
return &SysConfigUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOne returns an update builder for the given entity.
|
||||
func (c *SysConfigClient) UpdateOne(_m *SysConfig) *SysConfigUpdateOne {
|
||||
mutation := newSysConfigMutation(c.config, OpUpdateOne, withSysConfig(_m))
|
||||
return &SysConfigUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// UpdateOneID returns an update builder for the given id.
|
||||
func (c *SysConfigClient) UpdateOneID(id int64) *SysConfigUpdateOne {
|
||||
mutation := newSysConfigMutation(c.config, OpUpdateOne, withSysConfigID(id))
|
||||
return &SysConfigUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// Delete returns a delete builder for SysConfig.
|
||||
func (c *SysConfigClient) Delete() *SysConfigDelete {
|
||||
mutation := newSysConfigMutation(c.config, OpDelete)
|
||||
return &SysConfigDelete{config: c.config, hooks: c.Hooks(), mutation: mutation}
|
||||
}
|
||||
|
||||
// DeleteOne returns a builder for deleting the given entity.
|
||||
func (c *SysConfigClient) DeleteOne(_m *SysConfig) *SysConfigDeleteOne {
|
||||
return c.DeleteOneID(_m.ID)
|
||||
}
|
||||
|
||||
// DeleteOneID returns a builder for deleting the given entity by its id.
|
||||
func (c *SysConfigClient) DeleteOneID(id int64) *SysConfigDeleteOne {
|
||||
builder := c.Delete().Where(sysconfig.ID(id))
|
||||
builder.mutation.id = &id
|
||||
builder.mutation.op = OpDeleteOne
|
||||
return &SysConfigDeleteOne{builder}
|
||||
}
|
||||
|
||||
// Query returns a query builder for SysConfig.
|
||||
func (c *SysConfigClient) Query() *SysConfigQuery {
|
||||
return &SysConfigQuery{
|
||||
config: c.config,
|
||||
ctx: &QueryContext{Type: TypeSysConfig},
|
||||
inters: c.Interceptors(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns a SysConfig entity by its id.
|
||||
func (c *SysConfigClient) Get(ctx context.Context, id int64) (*SysConfig, error) {
|
||||
return c.Query().Where(sysconfig.ID(id)).Only(ctx)
|
||||
}
|
||||
|
||||
// GetX is like Get, but panics if an error occurs.
|
||||
func (c *SysConfigClient) GetX(ctx context.Context, id int64) *SysConfig {
|
||||
obj, err := c.Get(ctx, id)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *SysConfigClient) Hooks() []Hook {
|
||||
hooks := c.hooks.SysConfig
|
||||
return append(hooks[:len(hooks):len(hooks)], sysconfig.Hooks[:]...)
|
||||
}
|
||||
|
||||
// Interceptors returns the client interceptors.
|
||||
func (c *SysConfigClient) Interceptors() []Interceptor {
|
||||
return c.inters.SysConfig
|
||||
}
|
||||
|
||||
func (c *SysConfigClient) mutate(ctx context.Context, m *SysConfigMutation) (Value, error) {
|
||||
switch m.Op() {
|
||||
case OpCreate:
|
||||
return (&SysConfigCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdate:
|
||||
return (&SysConfigUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpUpdateOne:
|
||||
return (&SysConfigUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx)
|
||||
case OpDelete, OpDeleteOne:
|
||||
return (&SysConfigDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx)
|
||||
default:
|
||||
return nil, fmt.Errorf("ent: unknown SysConfig mutation op: %q", m.Op())
|
||||
}
|
||||
}
|
||||
|
||||
// SysMenuClient is a client for the SysMenu schema.
|
||||
type SysMenuClient struct {
|
||||
config
|
||||
@@ -2139,6 +2804,44 @@ func (c *SysUserClient) QueryCpTask(_m *SysUser) *CpTaskQuery {
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryCpLeave queries the cp_leave edge of a SysUser.
|
||||
func (c *SysUserClient) QueryCpLeave(_m *SysUser) *CpLeaveQuery {
|
||||
query := (&CpLeaveClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(sysuser.Table, sysuser.FieldID, id),
|
||||
sqlgraph.To(cpleave.Table, cpleave.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, sysuser.CpLeaveTable, sysuser.CpLeaveColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.CpLeave
|
||||
step.Edge.Schema = schemaConfig.CpLeave
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryCourseEntity queries the course_entity edge of a SysUser.
|
||||
func (c *SysUserClient) QueryCourseEntity(_m *SysUser) *CourseEntityQuery {
|
||||
query := (&CourseEntityClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(sysuser.Table, sysuser.FieldID, id),
|
||||
sqlgraph.To(courseentity.Table, courseentity.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, sysuser.CourseEntityTable, sysuser.CourseEntityColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.CourseEntity
|
||||
step.Edge.Schema = schemaConfig.CourseEntity
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryCpTaskLogs queries the cp_task_logs edge of a SysUser.
|
||||
func (c *SysUserClient) QueryCpTaskLogs(_m *SysUser) *CpTaskLogQuery {
|
||||
query := (&CpTaskLogClient{config: c.config}).Query()
|
||||
@@ -2215,6 +2918,25 @@ func (c *SysUserClient) QueryCashbackCards(_m *SysUser) *SysCardQuery {
|
||||
return query
|
||||
}
|
||||
|
||||
// QueryBalanceRecords queries the balance_records edge of a SysUser.
|
||||
func (c *SysUserClient) QueryBalanceRecords(_m *SysUser) *SysBalanceRecordQuery {
|
||||
query := (&SysBalanceRecordClient{config: c.config}).Query()
|
||||
query.path = func(context.Context) (fromV *sql.Selector, _ error) {
|
||||
id := _m.ID
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(sysuser.Table, sysuser.FieldID, id),
|
||||
sqlgraph.To(sysbalancerecord.Table, sysbalancerecord.FieldID),
|
||||
sqlgraph.Edge(sqlgraph.O2M, false, sysuser.BalanceRecordsTable, sysuser.BalanceRecordsColumn),
|
||||
)
|
||||
schemaConfig := _m.schemaConfig
|
||||
step.To.Schema = schemaConfig.SysBalanceRecord
|
||||
step.Edge.Schema = schemaConfig.SysBalanceRecord
|
||||
fromV = sqlgraph.Neighbors(_m.driver.Dialect(), step)
|
||||
return fromV, nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
// Hooks returns the client hooks.
|
||||
func (c *SysUserClient) Hooks() []Hook {
|
||||
hooks := c.hooks.SysUser
|
||||
@@ -2377,12 +3099,14 @@ func (c *SysUserLogClient) mutate(ctx context.Context, m *SysUserLogMutation) (V
|
||||
// hooks and interceptors per client, for fast access.
|
||||
type (
|
||||
hooks struct {
|
||||
CpImage, CpSchool, CpTask, CpTaskLog, CpUser, SysAgent, SysCard, SysMenu,
|
||||
SysRole, SysUser, SysUserLog []ent.Hook
|
||||
CourseEntity, CpImage, CpLeave, CpSchool, CpTask, CpTaskLog, CpUser, SysAgent,
|
||||
SysBalanceRecord, SysCard, SysConfig, SysMenu, SysRole, SysUser,
|
||||
SysUserLog []ent.Hook
|
||||
}
|
||||
inters struct {
|
||||
CpImage, CpSchool, CpTask, CpTaskLog, CpUser, SysAgent, SysCard, SysMenu,
|
||||
SysRole, SysUser, SysUserLog []ent.Interceptor
|
||||
CourseEntity, CpImage, CpLeave, CpSchool, CpTask, CpTaskLog, CpUser, SysAgent,
|
||||
SysBalanceRecord, SysCard, SysConfig, SysMenu, SysRole, SysUser,
|
||||
SysUserLog []ent.Interceptor
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
// ENT数据库文件,请勿编辑。
|
||||
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"likedream-goframe/internal/ent/courseentity"
|
||||
"likedream-goframe/internal/ent/sysuser"
|
||||
"likedream-goframe/internal/framework/ent2"
|
||||
"strings"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
)
|
||||
|
||||
// CourseEntity is the model entity for the CourseEntity schema.
|
||||
type CourseEntity struct {
|
||||
config `json:"-"`
|
||||
// ID of the ent.
|
||||
ID int64 `json:"id,omitempty"`
|
||||
// CreateTime holds the value of the "create_time" field.
|
||||
CreateTime *ent2.CustomTime `json:"createTime"`
|
||||
// UpdateTime holds the value of the "update_time" field.
|
||||
UpdateTime *ent2.CustomTime `json:"updateTime"`
|
||||
// UserID holds the value of the "user_id" field.
|
||||
UserID int64 `json:"user_id,omitempty"`
|
||||
// Username holds the value of the "username" field.
|
||||
Username string `json:"username,omitempty"`
|
||||
// Password holds the value of the "password" field.
|
||||
Password string `json:"-"`
|
||||
// Type holds the value of the "type" field.
|
||||
Type courseentity.Type `json:"type,omitempty"`
|
||||
// CourseName holds the value of the "course_name" field.
|
||||
CourseName string `json:"course_name,omitempty"`
|
||||
// CourseID holds the value of the "course_id" field.
|
||||
CourseID string `json:"course_id,omitempty"`
|
||||
// Need holds the value of the "need" field.
|
||||
Need courseentity.Need `json:"need,omitempty"`
|
||||
// Status holds the value of the "status" field.
|
||||
Status courseentity.Status `json:"status,omitempty"`
|
||||
// TaskCount holds the value of the "task_count" field.
|
||||
TaskCount int `json:"task_count,omitempty"`
|
||||
// SuccessCount holds the value of the "success_count" field.
|
||||
SuccessCount int `json:"success_count,omitempty"`
|
||||
// ExamState holds the value of the "exam_state" field.
|
||||
ExamState courseentity.ExamState `json:"exam_state,omitempty"`
|
||||
// Violence holds the value of the "violence" field.
|
||||
Violence courseentity.Violence `json:"violence,omitempty"`
|
||||
// Nodes holds the value of the "nodes" field.
|
||||
Nodes string `json:"nodes,omitempty"`
|
||||
// CompletedNodes holds the value of the "completed_nodes" field.
|
||||
CompletedNodes string `json:"completed_nodes,omitempty"`
|
||||
// Desc holds the value of the "desc" field.
|
||||
Desc string `json:"desc,omitempty"`
|
||||
// Edges holds the relations/edges for other nodes in the graph.
|
||||
// The values are being populated by the CourseEntityQuery when eager-loading is set.
|
||||
Edges CourseEntityEdges `json:"edges"`
|
||||
selectValues sql.SelectValues
|
||||
}
|
||||
|
||||
// CourseEntityEdges holds the relations/edges for other nodes in the graph.
|
||||
type CourseEntityEdges struct {
|
||||
// SysUser holds the value of the sys_user edge.
|
||||
SysUser *SysUser `json:"sys_user,omitempty"`
|
||||
// loadedTypes holds the information for reporting if a
|
||||
// type was loaded (or requested) in eager-loading or not.
|
||||
loadedTypes [1]bool
|
||||
}
|
||||
|
||||
// SysUserOrErr returns the SysUser value or an error if the edge
|
||||
// was not loaded in eager-loading, or loaded but was not found.
|
||||
func (e CourseEntityEdges) SysUserOrErr() (*SysUser, error) {
|
||||
if e.SysUser != nil {
|
||||
return e.SysUser, nil
|
||||
} else if e.loadedTypes[0] {
|
||||
return nil, &NotFoundError{label: sysuser.Label}
|
||||
}
|
||||
return nil, &NotLoadedError{edge: "sys_user"}
|
||||
}
|
||||
|
||||
// scanValues returns the types for scanning values from sql.Rows.
|
||||
func (*CourseEntity) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case courseentity.FieldCreateTime, courseentity.FieldUpdateTime:
|
||||
values[i] = new(ent2.CustomTime)
|
||||
case courseentity.FieldID, courseentity.FieldUserID, courseentity.FieldTaskCount, courseentity.FieldSuccessCount:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case courseentity.FieldUsername, courseentity.FieldPassword, courseentity.FieldType, courseentity.FieldCourseName, courseentity.FieldCourseID, courseentity.FieldNeed, courseentity.FieldStatus, courseentity.FieldExamState, courseentity.FieldViolence, courseentity.FieldNodes, courseentity.FieldCompletedNodes, courseentity.FieldDesc:
|
||||
values[i] = new(sql.NullString)
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
}
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
// assignValues assigns the values that were returned from sql.Rows (after scanning)
|
||||
// to the CourseEntity fields.
|
||||
func (_m *CourseEntity) assignValues(columns []string, values []any) error {
|
||||
if m, n := len(values), len(columns); m < n {
|
||||
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
|
||||
}
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case courseentity.FieldID:
|
||||
value, ok := values[i].(*sql.NullInt64)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field id", value)
|
||||
}
|
||||
_m.ID = int64(value.Int64)
|
||||
case courseentity.FieldCreateTime:
|
||||
if value, ok := values[i].(*ent2.CustomTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field create_time", values[i])
|
||||
} else if value != nil {
|
||||
_m.CreateTime = value
|
||||
}
|
||||
case courseentity.FieldUpdateTime:
|
||||
if value, ok := values[i].(*ent2.CustomTime); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field update_time", values[i])
|
||||
} else if value != nil {
|
||||
_m.UpdateTime = value
|
||||
}
|
||||
case courseentity.FieldUserID:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field user_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.UserID = value.Int64
|
||||
}
|
||||
case courseentity.FieldUsername:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field username", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Username = value.String
|
||||
}
|
||||
case courseentity.FieldPassword:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field password", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Password = value.String
|
||||
}
|
||||
case courseentity.FieldType:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field type", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Type = courseentity.Type(value.String)
|
||||
}
|
||||
case courseentity.FieldCourseName:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field course_name", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CourseName = value.String
|
||||
}
|
||||
case courseentity.FieldCourseID:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field course_id", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CourseID = value.String
|
||||
}
|
||||
case courseentity.FieldNeed:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field need", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Need = courseentity.Need(value.String)
|
||||
}
|
||||
case courseentity.FieldStatus:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field status", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Status = courseentity.Status(value.String)
|
||||
}
|
||||
case courseentity.FieldTaskCount:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field task_count", values[i])
|
||||
} else if value.Valid {
|
||||
_m.TaskCount = int(value.Int64)
|
||||
}
|
||||
case courseentity.FieldSuccessCount:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field success_count", values[i])
|
||||
} else if value.Valid {
|
||||
_m.SuccessCount = int(value.Int64)
|
||||
}
|
||||
case courseentity.FieldExamState:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field exam_state", values[i])
|
||||
} else if value.Valid {
|
||||
_m.ExamState = courseentity.ExamState(value.String)
|
||||
}
|
||||
case courseentity.FieldViolence:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field violence", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Violence = courseentity.Violence(value.String)
|
||||
}
|
||||
case courseentity.FieldNodes:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field nodes", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Nodes = value.String
|
||||
}
|
||||
case courseentity.FieldCompletedNodes:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field completed_nodes", values[i])
|
||||
} else if value.Valid {
|
||||
_m.CompletedNodes = value.String
|
||||
}
|
||||
case courseentity.FieldDesc:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field desc", values[i])
|
||||
} else if value.Valid {
|
||||
_m.Desc = value.String
|
||||
}
|
||||
default:
|
||||
_m.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value returns the ent.Value that was dynamically selected and assigned to the CourseEntity.
|
||||
// This includes values selected through modifiers, order, etc.
|
||||
func (_m *CourseEntity) Value(name string) (ent.Value, error) {
|
||||
return _m.selectValues.Get(name)
|
||||
}
|
||||
|
||||
// QuerySysUser queries the "sys_user" edge of the CourseEntity entity.
|
||||
func (_m *CourseEntity) QuerySysUser() *SysUserQuery {
|
||||
return NewCourseEntityClient(_m.config).QuerySysUser(_m)
|
||||
}
|
||||
|
||||
// Update returns a builder for updating this CourseEntity.
|
||||
// Note that you need to call CourseEntity.Unwrap() before calling this method if this CourseEntity
|
||||
// was returned from a transaction, and the transaction was committed or rolled back.
|
||||
func (_m *CourseEntity) Update() *CourseEntityUpdateOne {
|
||||
return NewCourseEntityClient(_m.config).UpdateOne(_m)
|
||||
}
|
||||
|
||||
// Unwrap unwraps the CourseEntity entity that was returned from a transaction after it was closed,
|
||||
// so that all future queries will be executed through the driver which created the transaction.
|
||||
func (_m *CourseEntity) Unwrap() *CourseEntity {
|
||||
_tx, ok := _m.config.driver.(*txDriver)
|
||||
if !ok {
|
||||
panic("ent: CourseEntity is not a transactional entity")
|
||||
}
|
||||
_m.config.driver = _tx.drv
|
||||
return _m
|
||||
}
|
||||
|
||||
// String implements the fmt.Stringer.
|
||||
func (_m *CourseEntity) String() string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString("CourseEntity(")
|
||||
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
|
||||
builder.WriteString("create_time=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.CreateTime))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("update_time=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.UpdateTime))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("user_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.UserID))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("username=")
|
||||
builder.WriteString(_m.Username)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("password=<sensitive>")
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("type=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Type))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("course_name=")
|
||||
builder.WriteString(_m.CourseName)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("course_id=")
|
||||
builder.WriteString(_m.CourseID)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("need=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Need))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("status=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Status))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("task_count=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.TaskCount))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("success_count=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.SuccessCount))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("exam_state=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.ExamState))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("violence=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Violence))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("nodes=")
|
||||
builder.WriteString(_m.Nodes)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("completed_nodes=")
|
||||
builder.WriteString(_m.CompletedNodes)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("desc=")
|
||||
builder.WriteString(_m.Desc)
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
// CourseEntities is a parsable slice of CourseEntity.
|
||||
type CourseEntities []*CourseEntity
|
||||
@@ -0,0 +1,351 @@
|
||||
// ENT数据库文件,请勿编辑。
|
||||
|
||||
package courseentity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"likedream-goframe/internal/framework/ent2"
|
||||
|
||||
"entgo.io/ent"
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
)
|
||||
|
||||
const (
|
||||
// Label holds the string label denoting the courseentity type in the database.
|
||||
Label = "course_entity"
|
||||
// FieldID holds the string denoting the id field in the database.
|
||||
FieldID = "id"
|
||||
// FieldCreateTime holds the string denoting the create_time field in the database.
|
||||
FieldCreateTime = "create_time"
|
||||
// FieldUpdateTime holds the string denoting the update_time field in the database.
|
||||
FieldUpdateTime = "update_time"
|
||||
// FieldUserID holds the string denoting the user_id field in the database.
|
||||
FieldUserID = "user_id"
|
||||
// FieldUsername holds the string denoting the username field in the database.
|
||||
FieldUsername = "username"
|
||||
// FieldPassword holds the string denoting the password field in the database.
|
||||
FieldPassword = "password"
|
||||
// FieldType holds the string denoting the type field in the database.
|
||||
FieldType = "type"
|
||||
// FieldCourseName holds the string denoting the course_name field in the database.
|
||||
FieldCourseName = "course_name"
|
||||
// FieldCourseID holds the string denoting the course_id field in the database.
|
||||
FieldCourseID = "course_id"
|
||||
// FieldNeed holds the string denoting the need field in the database.
|
||||
FieldNeed = "need"
|
||||
// FieldStatus holds the string denoting the status field in the database.
|
||||
FieldStatus = "status"
|
||||
// FieldTaskCount holds the string denoting the task_count field in the database.
|
||||
FieldTaskCount = "task_count"
|
||||
// FieldSuccessCount holds the string denoting the success_count field in the database.
|
||||
FieldSuccessCount = "success_count"
|
||||
// FieldExamState holds the string denoting the exam_state field in the database.
|
||||
FieldExamState = "exam_state"
|
||||
// FieldViolence holds the string denoting the violence field in the database.
|
||||
FieldViolence = "violence"
|
||||
// FieldNodes holds the string denoting the nodes field in the database.
|
||||
FieldNodes = "nodes"
|
||||
// FieldCompletedNodes holds the string denoting the completed_nodes field in the database.
|
||||
FieldCompletedNodes = "completed_nodes"
|
||||
// FieldDesc holds the string denoting the desc field in the database.
|
||||
FieldDesc = "desc"
|
||||
// EdgeSysUser holds the string denoting the sys_user edge name in mutations.
|
||||
EdgeSysUser = "sys_user"
|
||||
// Table holds the table name of the courseentity in the database.
|
||||
Table = "course_entity"
|
||||
// SysUserTable is the table that holds the sys_user relation/edge.
|
||||
SysUserTable = "course_entity"
|
||||
// SysUserInverseTable is the table name for the SysUser entity.
|
||||
// It exists in this package in order to avoid circular dependency with the "sysuser" package.
|
||||
SysUserInverseTable = "sys_user"
|
||||
// SysUserColumn is the table column denoting the sys_user relation/edge.
|
||||
SysUserColumn = "user_id"
|
||||
)
|
||||
|
||||
// Columns holds all SQL columns for courseentity fields.
|
||||
var Columns = []string{
|
||||
FieldID,
|
||||
FieldCreateTime,
|
||||
FieldUpdateTime,
|
||||
FieldUserID,
|
||||
FieldUsername,
|
||||
FieldPassword,
|
||||
FieldType,
|
||||
FieldCourseName,
|
||||
FieldCourseID,
|
||||
FieldNeed,
|
||||
FieldStatus,
|
||||
FieldTaskCount,
|
||||
FieldSuccessCount,
|
||||
FieldExamState,
|
||||
FieldViolence,
|
||||
FieldNodes,
|
||||
FieldCompletedNodes,
|
||||
FieldDesc,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
func ValidColumn(column string) bool {
|
||||
for i := range Columns {
|
||||
if column == Columns[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Note that the variables below are initialized by the runtime
|
||||
// package on the initialization of the application. Therefore,
|
||||
// it should be imported in the main as follows:
|
||||
//
|
||||
// import _ "likedream-goframe/internal/ent/runtime"
|
||||
var (
|
||||
Hooks [1]ent.Hook
|
||||
// DefaultCreateTime holds the default value on creation for the "create_time" field.
|
||||
DefaultCreateTime func() *ent2.CustomTime
|
||||
// DefaultUpdateTime holds the default value on creation for the "update_time" field.
|
||||
DefaultUpdateTime func() *ent2.CustomTime
|
||||
// DefaultTaskCount holds the default value on creation for the "task_count" field.
|
||||
DefaultTaskCount int
|
||||
// DefaultSuccessCount holds the default value on creation for the "success_count" field.
|
||||
DefaultSuccessCount int
|
||||
)
|
||||
|
||||
// Type defines the type for the "type" enum field.
|
||||
type Type string
|
||||
|
||||
// Type values.
|
||||
const (
|
||||
TypeXxt Type = "xxt"
|
||||
)
|
||||
|
||||
func (_type Type) String() string {
|
||||
return string(_type)
|
||||
}
|
||||
|
||||
// TypeValidator is a validator for the "type" field enum values. It is called by the builders before save.
|
||||
func TypeValidator(_type Type) error {
|
||||
switch _type {
|
||||
case TypeXxt:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("courseentity: invalid enum value for type field: %q", _type)
|
||||
}
|
||||
}
|
||||
|
||||
// Need defines the type for the "need" enum field.
|
||||
type Need string
|
||||
|
||||
// Need values.
|
||||
const (
|
||||
NeedTask Need = "task"
|
||||
NeedExam Need = "exam"
|
||||
NeedAll Need = "all"
|
||||
)
|
||||
|
||||
func (n Need) String() string {
|
||||
return string(n)
|
||||
}
|
||||
|
||||
// NeedValidator is a validator for the "need" field enum values. It is called by the builders before save.
|
||||
func NeedValidator(n Need) error {
|
||||
switch n {
|
||||
case NeedTask, NeedExam, NeedAll:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("courseentity: invalid enum value for need field: %q", n)
|
||||
}
|
||||
}
|
||||
|
||||
// Status defines the type for the "status" enum field.
|
||||
type Status string
|
||||
|
||||
// StatusNotStart is the default value of the Status enum.
|
||||
const DefaultStatus = StatusNotStart
|
||||
|
||||
// Status values.
|
||||
const (
|
||||
StatusNotStart Status = "not_start"
|
||||
StatusWaiting Status = "waiting"
|
||||
StatusDoing Status = "doing"
|
||||
StatusDone Status = "done"
|
||||
StatusFail Status = "fail"
|
||||
StatusPause Status = "pause"
|
||||
)
|
||||
|
||||
func (s Status) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// StatusValidator is a validator for the "status" field enum values. It is called by the builders before save.
|
||||
func StatusValidator(s Status) error {
|
||||
switch s {
|
||||
case StatusNotStart, StatusWaiting, StatusDoing, StatusDone, StatusFail, StatusPause:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("courseentity: invalid enum value for status field: %q", s)
|
||||
}
|
||||
}
|
||||
|
||||
// ExamState defines the type for the "exam_state" enum field.
|
||||
type ExamState string
|
||||
|
||||
// ExamStateNotStart is the default value of the ExamState enum.
|
||||
const DefaultExamState = ExamStateNotStart
|
||||
|
||||
// ExamState values.
|
||||
const (
|
||||
ExamStateNotStart ExamState = "not_start"
|
||||
ExamStateWaiting ExamState = "waiting"
|
||||
ExamStateDoing ExamState = "doing"
|
||||
ExamStateDone ExamState = "done"
|
||||
ExamStateFail ExamState = "fail"
|
||||
)
|
||||
|
||||
func (es ExamState) String() string {
|
||||
return string(es)
|
||||
}
|
||||
|
||||
// ExamStateValidator is a validator for the "exam_state" field enum values. It is called by the builders before save.
|
||||
func ExamStateValidator(es ExamState) error {
|
||||
switch es {
|
||||
case ExamStateNotStart, ExamStateWaiting, ExamStateDoing, ExamStateDone, ExamStateFail:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("courseentity: invalid enum value for exam_state field: %q", es)
|
||||
}
|
||||
}
|
||||
|
||||
// Violence defines the type for the "violence" enum field.
|
||||
type Violence string
|
||||
|
||||
// ViolenceNo is the default value of the Violence enum.
|
||||
const DefaultViolence = ViolenceNo
|
||||
|
||||
// Violence values.
|
||||
const (
|
||||
ViolenceNo Violence = "no"
|
||||
ViolenceYes Violence = "yes"
|
||||
)
|
||||
|
||||
func (v Violence) String() string {
|
||||
return string(v)
|
||||
}
|
||||
|
||||
// ViolenceValidator is a validator for the "violence" field enum values. It is called by the builders before save.
|
||||
func ViolenceValidator(v Violence) error {
|
||||
switch v {
|
||||
case ViolenceNo, ViolenceYes:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("courseentity: invalid enum value for violence field: %q", v)
|
||||
}
|
||||
}
|
||||
|
||||
// OrderOption defines the ordering options for the CourseEntity queries.
|
||||
type OrderOption func(*sql.Selector)
|
||||
|
||||
// ByID orders the results by the id field.
|
||||
func ByID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCreateTime orders the results by the create_time field.
|
||||
func ByCreateTime(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCreateTime, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUpdateTime orders the results by the update_time field.
|
||||
func ByUpdateTime(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUpdateTime, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUserID orders the results by the user_id field.
|
||||
func ByUserID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUserID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUsername orders the results by the username field.
|
||||
func ByUsername(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUsername, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPassword orders the results by the password field.
|
||||
func ByPassword(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPassword, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByType orders the results by the type field.
|
||||
func ByType(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldType, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCourseName orders the results by the course_name field.
|
||||
func ByCourseName(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCourseName, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCourseID orders the results by the course_id field.
|
||||
func ByCourseID(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCourseID, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByNeed orders the results by the need field.
|
||||
func ByNeed(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldNeed, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByStatus orders the results by the status field.
|
||||
func ByStatus(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldStatus, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByTaskCount orders the results by the task_count field.
|
||||
func ByTaskCount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldTaskCount, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySuccessCount orders the results by the success_count field.
|
||||
func BySuccessCount(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSuccessCount, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByExamState orders the results by the exam_state field.
|
||||
func ByExamState(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldExamState, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByViolence orders the results by the violence field.
|
||||
func ByViolence(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldViolence, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByNodes orders the results by the nodes field.
|
||||
func ByNodes(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldNodes, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByCompletedNodes orders the results by the completed_nodes field.
|
||||
func ByCompletedNodes(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldCompletedNodes, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByDesc orders the results by the desc field.
|
||||
func ByDesc(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldDesc, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySysUserField orders the results by sys_user field.
|
||||
func BySysUserField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||
return func(s *sql.Selector) {
|
||||
sqlgraph.OrderByNeighborTerms(s, newSysUserStep(), sql.OrderByField(field, opts...))
|
||||
}
|
||||
}
|
||||
func newSysUserStep() *sqlgraph.Step {
|
||||
return sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.To(SysUserInverseTable, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, SysUserTable, SysUserColumn),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,986 @@
|
||||
// ENT数据库文件,请勿编辑。
|
||||
|
||||
package courseentity
|
||||
|
||||
import (
|
||||
"likedream-goframe/internal/ent/internal"
|
||||
"likedream-goframe/internal/ent/predicate"
|
||||
"likedream-goframe/internal/framework/ent2"
|
||||
|
||||
"entgo.io/ent/dialect/sql"
|
||||
"entgo.io/ent/dialect/sql/sqlgraph"
|
||||
)
|
||||
|
||||
// ID filters vertices based on their ID field.
|
||||
func ID(id int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDEQ applies the EQ predicate on the ID field.
|
||||
func IDEQ(id int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDNEQ applies the NEQ predicate on the ID field.
|
||||
func IDNEQ(id int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldID, id))
|
||||
}
|
||||
|
||||
// IDIn applies the In predicate on the ID field.
|
||||
func IDIn(ids ...int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDNotIn applies the NotIn predicate on the ID field.
|
||||
func IDNotIn(ids ...int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldID, ids...))
|
||||
}
|
||||
|
||||
// IDGT applies the GT predicate on the ID field.
|
||||
func IDGT(id int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDGTE applies the GTE predicate on the ID field.
|
||||
func IDGTE(id int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLT applies the LT predicate on the ID field.
|
||||
func IDLT(id int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldID, id))
|
||||
}
|
||||
|
||||
// IDLTE applies the LTE predicate on the ID field.
|
||||
func IDLTE(id int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldID, id))
|
||||
}
|
||||
|
||||
// CreateTime applies equality check predicate on the "create_time" field. It's identical to CreateTimeEQ.
|
||||
func CreateTime(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCreateTime, v))
|
||||
}
|
||||
|
||||
// UpdateTime applies equality check predicate on the "update_time" field. It's identical to UpdateTimeEQ.
|
||||
func UpdateTime(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldUpdateTime, v))
|
||||
}
|
||||
|
||||
// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ.
|
||||
func UserID(v int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldUserID, v))
|
||||
}
|
||||
|
||||
// Username applies equality check predicate on the "username" field. It's identical to UsernameEQ.
|
||||
func Username(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldUsername, v))
|
||||
}
|
||||
|
||||
// Password applies equality check predicate on the "password" field. It's identical to PasswordEQ.
|
||||
func Password(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldPassword, v))
|
||||
}
|
||||
|
||||
// CourseName applies equality check predicate on the "course_name" field. It's identical to CourseNameEQ.
|
||||
func CourseName(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseID applies equality check predicate on the "course_id" field. It's identical to CourseIDEQ.
|
||||
func CourseID(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// TaskCount applies equality check predicate on the "task_count" field. It's identical to TaskCountEQ.
|
||||
func TaskCount(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldTaskCount, v))
|
||||
}
|
||||
|
||||
// SuccessCount applies equality check predicate on the "success_count" field. It's identical to SuccessCountEQ.
|
||||
func SuccessCount(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldSuccessCount, v))
|
||||
}
|
||||
|
||||
// Nodes applies equality check predicate on the "nodes" field. It's identical to NodesEQ.
|
||||
func Nodes(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodes applies equality check predicate on the "completed_nodes" field. It's identical to CompletedNodesEQ.
|
||||
func CompletedNodes(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// Desc applies equality check predicate on the "desc" field. It's identical to DescEQ.
|
||||
func Desc(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldDesc, v))
|
||||
}
|
||||
|
||||
// CreateTimeEQ applies the EQ predicate on the "create_time" field.
|
||||
func CreateTimeEQ(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCreateTime, v))
|
||||
}
|
||||
|
||||
// CreateTimeNEQ applies the NEQ predicate on the "create_time" field.
|
||||
func CreateTimeNEQ(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldCreateTime, v))
|
||||
}
|
||||
|
||||
// CreateTimeIn applies the In predicate on the "create_time" field.
|
||||
func CreateTimeIn(vs ...*ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldCreateTime, vs...))
|
||||
}
|
||||
|
||||
// CreateTimeNotIn applies the NotIn predicate on the "create_time" field.
|
||||
func CreateTimeNotIn(vs ...*ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldCreateTime, vs...))
|
||||
}
|
||||
|
||||
// CreateTimeGT applies the GT predicate on the "create_time" field.
|
||||
func CreateTimeGT(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldCreateTime, v))
|
||||
}
|
||||
|
||||
// CreateTimeGTE applies the GTE predicate on the "create_time" field.
|
||||
func CreateTimeGTE(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldCreateTime, v))
|
||||
}
|
||||
|
||||
// CreateTimeLT applies the LT predicate on the "create_time" field.
|
||||
func CreateTimeLT(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldCreateTime, v))
|
||||
}
|
||||
|
||||
// CreateTimeLTE applies the LTE predicate on the "create_time" field.
|
||||
func CreateTimeLTE(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldCreateTime, v))
|
||||
}
|
||||
|
||||
// CreateTimeContains applies the Contains predicate on the "create_time" field.
|
||||
func CreateTimeContains(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldCreateTime, vc))
|
||||
}
|
||||
|
||||
// CreateTimeHasPrefix applies the HasPrefix predicate on the "create_time" field.
|
||||
func CreateTimeHasPrefix(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldCreateTime, vc))
|
||||
}
|
||||
|
||||
// CreateTimeHasSuffix applies the HasSuffix predicate on the "create_time" field.
|
||||
func CreateTimeHasSuffix(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldCreateTime, vc))
|
||||
}
|
||||
|
||||
// CreateTimeEqualFold applies the EqualFold predicate on the "create_time" field.
|
||||
func CreateTimeEqualFold(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldCreateTime, vc))
|
||||
}
|
||||
|
||||
// CreateTimeContainsFold applies the ContainsFold predicate on the "create_time" field.
|
||||
func CreateTimeContainsFold(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldCreateTime, vc))
|
||||
}
|
||||
|
||||
// UpdateTimeEQ applies the EQ predicate on the "update_time" field.
|
||||
func UpdateTimeEQ(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldUpdateTime, v))
|
||||
}
|
||||
|
||||
// UpdateTimeNEQ applies the NEQ predicate on the "update_time" field.
|
||||
func UpdateTimeNEQ(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldUpdateTime, v))
|
||||
}
|
||||
|
||||
// UpdateTimeIn applies the In predicate on the "update_time" field.
|
||||
func UpdateTimeIn(vs ...*ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldUpdateTime, vs...))
|
||||
}
|
||||
|
||||
// UpdateTimeNotIn applies the NotIn predicate on the "update_time" field.
|
||||
func UpdateTimeNotIn(vs ...*ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldUpdateTime, vs...))
|
||||
}
|
||||
|
||||
// UpdateTimeGT applies the GT predicate on the "update_time" field.
|
||||
func UpdateTimeGT(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldUpdateTime, v))
|
||||
}
|
||||
|
||||
// UpdateTimeGTE applies the GTE predicate on the "update_time" field.
|
||||
func UpdateTimeGTE(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldUpdateTime, v))
|
||||
}
|
||||
|
||||
// UpdateTimeLT applies the LT predicate on the "update_time" field.
|
||||
func UpdateTimeLT(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldUpdateTime, v))
|
||||
}
|
||||
|
||||
// UpdateTimeLTE applies the LTE predicate on the "update_time" field.
|
||||
func UpdateTimeLTE(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldUpdateTime, v))
|
||||
}
|
||||
|
||||
// UpdateTimeContains applies the Contains predicate on the "update_time" field.
|
||||
func UpdateTimeContains(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldUpdateTime, vc))
|
||||
}
|
||||
|
||||
// UpdateTimeHasPrefix applies the HasPrefix predicate on the "update_time" field.
|
||||
func UpdateTimeHasPrefix(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldUpdateTime, vc))
|
||||
}
|
||||
|
||||
// UpdateTimeHasSuffix applies the HasSuffix predicate on the "update_time" field.
|
||||
func UpdateTimeHasSuffix(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldUpdateTime, vc))
|
||||
}
|
||||
|
||||
// UpdateTimeEqualFold applies the EqualFold predicate on the "update_time" field.
|
||||
func UpdateTimeEqualFold(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldUpdateTime, vc))
|
||||
}
|
||||
|
||||
// UpdateTimeContainsFold applies the ContainsFold predicate on the "update_time" field.
|
||||
func UpdateTimeContainsFold(v *ent2.CustomTime) predicate.CourseEntity {
|
||||
vc := v.String()
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldUpdateTime, vc))
|
||||
}
|
||||
|
||||
// UserIDEQ applies the EQ predicate on the "user_id" field.
|
||||
func UserIDEQ(v int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldUserID, v))
|
||||
}
|
||||
|
||||
// UserIDNEQ applies the NEQ predicate on the "user_id" field.
|
||||
func UserIDNEQ(v int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldUserID, v))
|
||||
}
|
||||
|
||||
// UserIDIn applies the In predicate on the "user_id" field.
|
||||
func UserIDIn(vs ...int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldUserID, vs...))
|
||||
}
|
||||
|
||||
// UserIDNotIn applies the NotIn predicate on the "user_id" field.
|
||||
func UserIDNotIn(vs ...int64) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldUserID, vs...))
|
||||
}
|
||||
|
||||
// UsernameEQ applies the EQ predicate on the "username" field.
|
||||
func UsernameEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameNEQ applies the NEQ predicate on the "username" field.
|
||||
func UsernameNEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameIn applies the In predicate on the "username" field.
|
||||
func UsernameIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldUsername, vs...))
|
||||
}
|
||||
|
||||
// UsernameNotIn applies the NotIn predicate on the "username" field.
|
||||
func UsernameNotIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldUsername, vs...))
|
||||
}
|
||||
|
||||
// UsernameGT applies the GT predicate on the "username" field.
|
||||
func UsernameGT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameGTE applies the GTE predicate on the "username" field.
|
||||
func UsernameGTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameLT applies the LT predicate on the "username" field.
|
||||
func UsernameLT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameLTE applies the LTE predicate on the "username" field.
|
||||
func UsernameLTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameContains applies the Contains predicate on the "username" field.
|
||||
func UsernameContains(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameHasPrefix applies the HasPrefix predicate on the "username" field.
|
||||
func UsernameHasPrefix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameHasSuffix applies the HasSuffix predicate on the "username" field.
|
||||
func UsernameHasSuffix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameEqualFold applies the EqualFold predicate on the "username" field.
|
||||
func UsernameEqualFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldUsername, v))
|
||||
}
|
||||
|
||||
// UsernameContainsFold applies the ContainsFold predicate on the "username" field.
|
||||
func UsernameContainsFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldUsername, v))
|
||||
}
|
||||
|
||||
// PasswordEQ applies the EQ predicate on the "password" field.
|
||||
func PasswordEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordNEQ applies the NEQ predicate on the "password" field.
|
||||
func PasswordNEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordIn applies the In predicate on the "password" field.
|
||||
func PasswordIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldPassword, vs...))
|
||||
}
|
||||
|
||||
// PasswordNotIn applies the NotIn predicate on the "password" field.
|
||||
func PasswordNotIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldPassword, vs...))
|
||||
}
|
||||
|
||||
// PasswordGT applies the GT predicate on the "password" field.
|
||||
func PasswordGT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordGTE applies the GTE predicate on the "password" field.
|
||||
func PasswordGTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordLT applies the LT predicate on the "password" field.
|
||||
func PasswordLT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordLTE applies the LTE predicate on the "password" field.
|
||||
func PasswordLTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordContains applies the Contains predicate on the "password" field.
|
||||
func PasswordContains(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordHasPrefix applies the HasPrefix predicate on the "password" field.
|
||||
func PasswordHasPrefix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordHasSuffix applies the HasSuffix predicate on the "password" field.
|
||||
func PasswordHasSuffix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordEqualFold applies the EqualFold predicate on the "password" field.
|
||||
func PasswordEqualFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldPassword, v))
|
||||
}
|
||||
|
||||
// PasswordContainsFold applies the ContainsFold predicate on the "password" field.
|
||||
func PasswordContainsFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldPassword, v))
|
||||
}
|
||||
|
||||
// TypeEQ applies the EQ predicate on the "type" field.
|
||||
func TypeEQ(v Type) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldType, v))
|
||||
}
|
||||
|
||||
// TypeNEQ applies the NEQ predicate on the "type" field.
|
||||
func TypeNEQ(v Type) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldType, v))
|
||||
}
|
||||
|
||||
// TypeIn applies the In predicate on the "type" field.
|
||||
func TypeIn(vs ...Type) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldType, vs...))
|
||||
}
|
||||
|
||||
// TypeNotIn applies the NotIn predicate on the "type" field.
|
||||
func TypeNotIn(vs ...Type) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldType, vs...))
|
||||
}
|
||||
|
||||
// CourseNameEQ applies the EQ predicate on the "course_name" field.
|
||||
func CourseNameEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameNEQ applies the NEQ predicate on the "course_name" field.
|
||||
func CourseNameNEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameIn applies the In predicate on the "course_name" field.
|
||||
func CourseNameIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldCourseName, vs...))
|
||||
}
|
||||
|
||||
// CourseNameNotIn applies the NotIn predicate on the "course_name" field.
|
||||
func CourseNameNotIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldCourseName, vs...))
|
||||
}
|
||||
|
||||
// CourseNameGT applies the GT predicate on the "course_name" field.
|
||||
func CourseNameGT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameGTE applies the GTE predicate on the "course_name" field.
|
||||
func CourseNameGTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameLT applies the LT predicate on the "course_name" field.
|
||||
func CourseNameLT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameLTE applies the LTE predicate on the "course_name" field.
|
||||
func CourseNameLTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameContains applies the Contains predicate on the "course_name" field.
|
||||
func CourseNameContains(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameHasPrefix applies the HasPrefix predicate on the "course_name" field.
|
||||
func CourseNameHasPrefix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameHasSuffix applies the HasSuffix predicate on the "course_name" field.
|
||||
func CourseNameHasSuffix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameEqualFold applies the EqualFold predicate on the "course_name" field.
|
||||
func CourseNameEqualFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseNameContainsFold applies the ContainsFold predicate on the "course_name" field.
|
||||
func CourseNameContainsFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldCourseName, v))
|
||||
}
|
||||
|
||||
// CourseIDEQ applies the EQ predicate on the "course_id" field.
|
||||
func CourseIDEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDNEQ applies the NEQ predicate on the "course_id" field.
|
||||
func CourseIDNEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDIn applies the In predicate on the "course_id" field.
|
||||
func CourseIDIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldCourseID, vs...))
|
||||
}
|
||||
|
||||
// CourseIDNotIn applies the NotIn predicate on the "course_id" field.
|
||||
func CourseIDNotIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldCourseID, vs...))
|
||||
}
|
||||
|
||||
// CourseIDGT applies the GT predicate on the "course_id" field.
|
||||
func CourseIDGT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDGTE applies the GTE predicate on the "course_id" field.
|
||||
func CourseIDGTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDLT applies the LT predicate on the "course_id" field.
|
||||
func CourseIDLT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDLTE applies the LTE predicate on the "course_id" field.
|
||||
func CourseIDLTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDContains applies the Contains predicate on the "course_id" field.
|
||||
func CourseIDContains(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDHasPrefix applies the HasPrefix predicate on the "course_id" field.
|
||||
func CourseIDHasPrefix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDHasSuffix applies the HasSuffix predicate on the "course_id" field.
|
||||
func CourseIDHasSuffix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDEqualFold applies the EqualFold predicate on the "course_id" field.
|
||||
func CourseIDEqualFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// CourseIDContainsFold applies the ContainsFold predicate on the "course_id" field.
|
||||
func CourseIDContainsFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldCourseID, v))
|
||||
}
|
||||
|
||||
// NeedEQ applies the EQ predicate on the "need" field.
|
||||
func NeedEQ(v Need) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldNeed, v))
|
||||
}
|
||||
|
||||
// NeedNEQ applies the NEQ predicate on the "need" field.
|
||||
func NeedNEQ(v Need) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldNeed, v))
|
||||
}
|
||||
|
||||
// NeedIn applies the In predicate on the "need" field.
|
||||
func NeedIn(vs ...Need) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldNeed, vs...))
|
||||
}
|
||||
|
||||
// NeedNotIn applies the NotIn predicate on the "need" field.
|
||||
func NeedNotIn(vs ...Need) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldNeed, vs...))
|
||||
}
|
||||
|
||||
// StatusEQ applies the EQ predicate on the "status" field.
|
||||
func StatusEQ(v Status) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldStatus, v))
|
||||
}
|
||||
|
||||
// StatusNEQ applies the NEQ predicate on the "status" field.
|
||||
func StatusNEQ(v Status) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldStatus, v))
|
||||
}
|
||||
|
||||
// StatusIn applies the In predicate on the "status" field.
|
||||
func StatusIn(vs ...Status) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldStatus, vs...))
|
||||
}
|
||||
|
||||
// StatusNotIn applies the NotIn predicate on the "status" field.
|
||||
func StatusNotIn(vs ...Status) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldStatus, vs...))
|
||||
}
|
||||
|
||||
// TaskCountEQ applies the EQ predicate on the "task_count" field.
|
||||
func TaskCountEQ(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldTaskCount, v))
|
||||
}
|
||||
|
||||
// TaskCountNEQ applies the NEQ predicate on the "task_count" field.
|
||||
func TaskCountNEQ(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldTaskCount, v))
|
||||
}
|
||||
|
||||
// TaskCountIn applies the In predicate on the "task_count" field.
|
||||
func TaskCountIn(vs ...int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldTaskCount, vs...))
|
||||
}
|
||||
|
||||
// TaskCountNotIn applies the NotIn predicate on the "task_count" field.
|
||||
func TaskCountNotIn(vs ...int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldTaskCount, vs...))
|
||||
}
|
||||
|
||||
// TaskCountGT applies the GT predicate on the "task_count" field.
|
||||
func TaskCountGT(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldTaskCount, v))
|
||||
}
|
||||
|
||||
// TaskCountGTE applies the GTE predicate on the "task_count" field.
|
||||
func TaskCountGTE(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldTaskCount, v))
|
||||
}
|
||||
|
||||
// TaskCountLT applies the LT predicate on the "task_count" field.
|
||||
func TaskCountLT(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldTaskCount, v))
|
||||
}
|
||||
|
||||
// TaskCountLTE applies the LTE predicate on the "task_count" field.
|
||||
func TaskCountLTE(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldTaskCount, v))
|
||||
}
|
||||
|
||||
// SuccessCountEQ applies the EQ predicate on the "success_count" field.
|
||||
func SuccessCountEQ(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldSuccessCount, v))
|
||||
}
|
||||
|
||||
// SuccessCountNEQ applies the NEQ predicate on the "success_count" field.
|
||||
func SuccessCountNEQ(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldSuccessCount, v))
|
||||
}
|
||||
|
||||
// SuccessCountIn applies the In predicate on the "success_count" field.
|
||||
func SuccessCountIn(vs ...int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldSuccessCount, vs...))
|
||||
}
|
||||
|
||||
// SuccessCountNotIn applies the NotIn predicate on the "success_count" field.
|
||||
func SuccessCountNotIn(vs ...int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldSuccessCount, vs...))
|
||||
}
|
||||
|
||||
// SuccessCountGT applies the GT predicate on the "success_count" field.
|
||||
func SuccessCountGT(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldSuccessCount, v))
|
||||
}
|
||||
|
||||
// SuccessCountGTE applies the GTE predicate on the "success_count" field.
|
||||
func SuccessCountGTE(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldSuccessCount, v))
|
||||
}
|
||||
|
||||
// SuccessCountLT applies the LT predicate on the "success_count" field.
|
||||
func SuccessCountLT(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldSuccessCount, v))
|
||||
}
|
||||
|
||||
// SuccessCountLTE applies the LTE predicate on the "success_count" field.
|
||||
func SuccessCountLTE(v int) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldSuccessCount, v))
|
||||
}
|
||||
|
||||
// ExamStateEQ applies the EQ predicate on the "exam_state" field.
|
||||
func ExamStateEQ(v ExamState) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldExamState, v))
|
||||
}
|
||||
|
||||
// ExamStateNEQ applies the NEQ predicate on the "exam_state" field.
|
||||
func ExamStateNEQ(v ExamState) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldExamState, v))
|
||||
}
|
||||
|
||||
// ExamStateIn applies the In predicate on the "exam_state" field.
|
||||
func ExamStateIn(vs ...ExamState) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldExamState, vs...))
|
||||
}
|
||||
|
||||
// ExamStateNotIn applies the NotIn predicate on the "exam_state" field.
|
||||
func ExamStateNotIn(vs ...ExamState) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldExamState, vs...))
|
||||
}
|
||||
|
||||
// ViolenceEQ applies the EQ predicate on the "violence" field.
|
||||
func ViolenceEQ(v Violence) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldViolence, v))
|
||||
}
|
||||
|
||||
// ViolenceNEQ applies the NEQ predicate on the "violence" field.
|
||||
func ViolenceNEQ(v Violence) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldViolence, v))
|
||||
}
|
||||
|
||||
// ViolenceIn applies the In predicate on the "violence" field.
|
||||
func ViolenceIn(vs ...Violence) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldViolence, vs...))
|
||||
}
|
||||
|
||||
// ViolenceNotIn applies the NotIn predicate on the "violence" field.
|
||||
func ViolenceNotIn(vs ...Violence) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldViolence, vs...))
|
||||
}
|
||||
|
||||
// NodesEQ applies the EQ predicate on the "nodes" field.
|
||||
func NodesEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesNEQ applies the NEQ predicate on the "nodes" field.
|
||||
func NodesNEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesIn applies the In predicate on the "nodes" field.
|
||||
func NodesIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldNodes, vs...))
|
||||
}
|
||||
|
||||
// NodesNotIn applies the NotIn predicate on the "nodes" field.
|
||||
func NodesNotIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldNodes, vs...))
|
||||
}
|
||||
|
||||
// NodesGT applies the GT predicate on the "nodes" field.
|
||||
func NodesGT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesGTE applies the GTE predicate on the "nodes" field.
|
||||
func NodesGTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesLT applies the LT predicate on the "nodes" field.
|
||||
func NodesLT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesLTE applies the LTE predicate on the "nodes" field.
|
||||
func NodesLTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesContains applies the Contains predicate on the "nodes" field.
|
||||
func NodesContains(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesHasPrefix applies the HasPrefix predicate on the "nodes" field.
|
||||
func NodesHasPrefix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesHasSuffix applies the HasSuffix predicate on the "nodes" field.
|
||||
func NodesHasSuffix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesIsNil applies the IsNil predicate on the "nodes" field.
|
||||
func NodesIsNil() predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIsNull(FieldNodes))
|
||||
}
|
||||
|
||||
// NodesNotNil applies the NotNil predicate on the "nodes" field.
|
||||
func NodesNotNil() predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotNull(FieldNodes))
|
||||
}
|
||||
|
||||
// NodesEqualFold applies the EqualFold predicate on the "nodes" field.
|
||||
func NodesEqualFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldNodes, v))
|
||||
}
|
||||
|
||||
// NodesContainsFold applies the ContainsFold predicate on the "nodes" field.
|
||||
func NodesContainsFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesEQ applies the EQ predicate on the "completed_nodes" field.
|
||||
func CompletedNodesEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesNEQ applies the NEQ predicate on the "completed_nodes" field.
|
||||
func CompletedNodesNEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesIn applies the In predicate on the "completed_nodes" field.
|
||||
func CompletedNodesIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldCompletedNodes, vs...))
|
||||
}
|
||||
|
||||
// CompletedNodesNotIn applies the NotIn predicate on the "completed_nodes" field.
|
||||
func CompletedNodesNotIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldCompletedNodes, vs...))
|
||||
}
|
||||
|
||||
// CompletedNodesGT applies the GT predicate on the "completed_nodes" field.
|
||||
func CompletedNodesGT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesGTE applies the GTE predicate on the "completed_nodes" field.
|
||||
func CompletedNodesGTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesLT applies the LT predicate on the "completed_nodes" field.
|
||||
func CompletedNodesLT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesLTE applies the LTE predicate on the "completed_nodes" field.
|
||||
func CompletedNodesLTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesContains applies the Contains predicate on the "completed_nodes" field.
|
||||
func CompletedNodesContains(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesHasPrefix applies the HasPrefix predicate on the "completed_nodes" field.
|
||||
func CompletedNodesHasPrefix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesHasSuffix applies the HasSuffix predicate on the "completed_nodes" field.
|
||||
func CompletedNodesHasSuffix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesIsNil applies the IsNil predicate on the "completed_nodes" field.
|
||||
func CompletedNodesIsNil() predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIsNull(FieldCompletedNodes))
|
||||
}
|
||||
|
||||
// CompletedNodesNotNil applies the NotNil predicate on the "completed_nodes" field.
|
||||
func CompletedNodesNotNil() predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotNull(FieldCompletedNodes))
|
||||
}
|
||||
|
||||
// CompletedNodesEqualFold applies the EqualFold predicate on the "completed_nodes" field.
|
||||
func CompletedNodesEqualFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// CompletedNodesContainsFold applies the ContainsFold predicate on the "completed_nodes" field.
|
||||
func CompletedNodesContainsFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldCompletedNodes, v))
|
||||
}
|
||||
|
||||
// DescEQ applies the EQ predicate on the "desc" field.
|
||||
func DescEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEQ(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescNEQ applies the NEQ predicate on the "desc" field.
|
||||
func DescNEQ(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNEQ(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescIn applies the In predicate on the "desc" field.
|
||||
func DescIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIn(FieldDesc, vs...))
|
||||
}
|
||||
|
||||
// DescNotIn applies the NotIn predicate on the "desc" field.
|
||||
func DescNotIn(vs ...string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotIn(FieldDesc, vs...))
|
||||
}
|
||||
|
||||
// DescGT applies the GT predicate on the "desc" field.
|
||||
func DescGT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGT(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescGTE applies the GTE predicate on the "desc" field.
|
||||
func DescGTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldGTE(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescLT applies the LT predicate on the "desc" field.
|
||||
func DescLT(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLT(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescLTE applies the LTE predicate on the "desc" field.
|
||||
func DescLTE(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldLTE(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescContains applies the Contains predicate on the "desc" field.
|
||||
func DescContains(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContains(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescHasPrefix applies the HasPrefix predicate on the "desc" field.
|
||||
func DescHasPrefix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasPrefix(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescHasSuffix applies the HasSuffix predicate on the "desc" field.
|
||||
func DescHasSuffix(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldHasSuffix(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescIsNil applies the IsNil predicate on the "desc" field.
|
||||
func DescIsNil() predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldIsNull(FieldDesc))
|
||||
}
|
||||
|
||||
// DescNotNil applies the NotNil predicate on the "desc" field.
|
||||
func DescNotNil() predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldNotNull(FieldDesc))
|
||||
}
|
||||
|
||||
// DescEqualFold applies the EqualFold predicate on the "desc" field.
|
||||
func DescEqualFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldEqualFold(FieldDesc, v))
|
||||
}
|
||||
|
||||
// DescContainsFold applies the ContainsFold predicate on the "desc" field.
|
||||
func DescContainsFold(v string) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.FieldContainsFold(FieldDesc, v))
|
||||
}
|
||||
|
||||
// HasSysUser applies the HasEdge predicate on the "sys_user" edge.
|
||||
func HasSysUser() predicate.CourseEntity {
|
||||
return predicate.CourseEntity(func(s *sql.Selector) {
|
||||
step := sqlgraph.NewStep(
|
||||
sqlgraph.From(Table, FieldID),
|
||||
sqlgraph.Edge(sqlgraph.M2O, true, SysUserTable, SysUserColumn),
|
||||
)
|
||||
schemaConfig := internal.SchemaConfigFromContext(s.Context())
|
||||
step.To.Schema = schemaConfig.SysUser
|
||||
step.Edge.Schema = schemaConfig.CourseEntity
|
||||
sqlgraph.HasNeighbors(s, step)
|
||||
})
|
||||
}
|
||||
|
||||
// HasSysUserWith applies the HasEdge predicate on the "sys_user" edge with a given conditions (other predicates).
|
||||
func HasSysUserWith(preds ...predicate.SysUser) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(func(s *sql.Selector) {
|
||||
step := newSysUserStep()
|
||||
schemaConfig := internal.SchemaConfigFromContext(s.Context())
|
||||
step.To.Schema = schemaConfig.SysUser
|
||||
step.Edge.Schema = schemaConfig.CourseEntity
|
||||
sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) {
|
||||
for _, p := range preds {
|
||||
p(s)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.CourseEntity) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.AndPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Or groups predicates with the OR operator between them.
|
||||
func Or(predicates ...predicate.CourseEntity) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.OrPredicates(predicates...))
|
||||
}
|
||||
|
||||
// Not applies the not operator on the given predicate.
|
||||
func Not(p predicate.CourseEntity) predicate.CourseEntity {
|
||||
return predicate.CourseEntity(sql.NotPredicates(p))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user