这两批改动此前一直压在工作区未提交,本次一并归档。go build ./... 通过。
一、招聘爬虫健壮性
- 新增 internal/service/recruitment/source_config.go:
crawl_source.config(VARCHAR(1000) JSON)的源级抓取参数解析 —— 增量窗口天数、
单次详情页上限、最大翻页数、详情间隔限速、自定义标准词/排除词。
全部字段可选,JSON 解析失败即回退默认值,保证历史数据零迁移可用,
且一个源的脏配置不会拖垮整个调度。
- 新增 internal/service/recruitment/keywords.go(含 keywords_test.go 与 testdata/):
链接筛选由「URL 形态命中 AND 文本语义命中」改为评分制 —— URL 形态加分、
标准词加分、排除词大幅减分,达阈值即入选。原与逻辑会系统性漏抓
「补充工作人员的通知」「公开选调公务员简章」等标题变体,且静默无报错。
- 新增 manifest/sql/recruitment/004_crawl_source_status.sql:
crawl_source 增加「最近一次运行状态」冗余列,抓取结束时写入,
使 Sources() 查询零 JOIN 零扫描 —— 规避原实现全表扫描只增不减的 crawl_log、
随运行时间线性劣化的问题。幂等,可重复执行。
- internal/service/recruitment/crawler.go:在既有「静态两级 / SPA / curl 回退」
流程上做锚点抽取与过滤、编码回退的健壮性增强。
- internal/service/recruitment/bark.go、recruitment.go:配合上述调整。
二、通知记录增强
- api/notice、internal/controller/notice、internal/service/notice、
internal/model/{dto,entity,do}/notice.go:通知日志查询与操作扩展 ——
批次号、状态、重试次数、来源、耗时、详情、删除、清空。
- 新增 internal/model/dto/notice_meta.go(字典选项元数据,供前端筛选器取选项)。
- 新增 manifest/sql/017_notice_log_enhance.sql:notice_log 扩展列 +
删除/清空/详情/字典选项接口权限,幂等(ALTER 走 information_schema 判断,
菜单 ON DUPLICATE KEY UPDATE,角色绑定 INSERT IGNORE)。
三、仓库卫生
- .gitignore 补 rc_*.log 与 rc_verify*,挡掉本地离线验证产物
(含 30MB 的 rc_verify.exe),避免误入库。
设计依据见 docs/recruitment-crawler-design.md。
注:017 与 recruitment/004 两个 SQL 为增量迁移,DB 结构变更不自动 DDL,
生产库需手动导入。
130 lines
4.3 KiB
Go
130 lines
4.3 KiB
Go
// Package dto 定义通知模块的服务边界对象(入参/出参)。
|
||
package dto
|
||
|
||
import "strings"
|
||
|
||
// NoticeChannelVO 渠道出参。
|
||
type NoticeChannelVO struct {
|
||
Id uint64
|
||
Code string
|
||
Name string
|
||
Enabled int
|
||
Config string
|
||
Remark string
|
||
}
|
||
|
||
// NoticeChannelInput 渠道入参。
|
||
type NoticeChannelInput struct {
|
||
Id uint64
|
||
Code string
|
||
Name string
|
||
Enabled int
|
||
Config string
|
||
Remark string
|
||
}
|
||
|
||
// NoticeRuleVO 规则出参。
|
||
type NoticeRuleVO struct {
|
||
Id uint64
|
||
Name string
|
||
EventType string
|
||
ChannelCodes []string
|
||
UserIds []uint64
|
||
TitleTemplate string
|
||
BodyTemplate string
|
||
Enabled int
|
||
}
|
||
|
||
// NoticeRuleInput 规则入参。
|
||
type NoticeRuleInput struct {
|
||
Id uint64
|
||
Name string
|
||
EventType string
|
||
ChannelCodes []string
|
||
UserIds []uint64
|
||
TitleTemplate string
|
||
BodyTemplate string
|
||
Enabled int
|
||
}
|
||
|
||
// NoticeLogVO 通知历史记录出参。
|
||
// 除落库字段外,额外补齐「渠道名称/事件名称/类型/分组/接收人」等派生字段,供表格直接展示。
|
||
type NoticeLogVO struct {
|
||
Id uint64 `json:"id"` // 主键
|
||
BatchId string `json:"batchId"` // 批次号(同一次业务触发的多条投递共用)
|
||
RuleId uint64 `json:"ruleId"` // 规则ID
|
||
RuleName string `json:"ruleName"` // 规则名称(派生,规则已删除则为空)
|
||
EventType string `json:"eventType"` // 事件编码
|
||
EventName string `json:"eventName"` // 事件名称(派生)
|
||
NoticeType string `json:"noticeType"` // 类型编码(派生)
|
||
TypeName string `json:"typeName"` // 类型名称(派生)
|
||
Group string `json:"group"` // 分组编码(派生)
|
||
GroupName string `json:"groupName"` // 分组名称(派生)
|
||
ChannelCode string `json:"channelCode"` // 渠道编码
|
||
ChannelName string `json:"channelName"` // 渠道名称(派生)
|
||
UserId uint64 `json:"userId"` // 接收用户ID
|
||
UserName string `json:"userName"` // 接收人(昵称/账号,派生)
|
||
Target string `json:"target"` // 发送目标(设备key/token)
|
||
Title string `json:"title"` // 标题
|
||
Body string `json:"body"` // 内容
|
||
Status int `json:"status"` // 0待发送 1成功 2失败
|
||
StatusName string `json:"statusName"` // 状态名称(派生)
|
||
Result int `json:"result"` // 兼容旧字段:1成功 0失败
|
||
Error string `json:"error"` // 错误信息
|
||
RetryCount int `json:"retryCount"` // 已重试次数
|
||
DurationMs int `json:"durationMs"` // 渠道接口耗时(毫秒)
|
||
Source string `json:"source"` // 触发来源:auto/manual/test
|
||
Remark string `json:"remark"` // 备注(如测试说明)
|
||
CreatedAt string `json:"createdAt"` // 通知时间
|
||
}
|
||
|
||
// NoticeLogFilter 通知历史记录筛选(分页 + 多维条件)。
|
||
type NoticeLogFilter struct {
|
||
Page int // 页码
|
||
Size int // 每页条数
|
||
Keyword string // 关键字:标题/内容/目标/错误 模糊
|
||
NoticeType string // 类型编码(job/security/...)
|
||
Group string // 分组编码(auto_job/server/...)
|
||
EventType string // 事件编码
|
||
ChannelCode string // 渠道编码
|
||
UserId uint64 // 接收用户ID
|
||
BatchId string // 批次号
|
||
Status int // 0全部 1成功 2失败(兼容旧的 result 字段)
|
||
Result int // 兼容旧参数:1成功 2失败
|
||
DateFrom string // 起始时间(yyyy-MM-dd HH:mm:ss)
|
||
DateTo string // 结束时间
|
||
OrderBy string // createdAt(默认) | durationMs
|
||
OrderDir string // desc(默认) | asc
|
||
}
|
||
|
||
// 构造并归一化:Result 为兼容字段,优先级低于 Status。
|
||
func (f *NoticeLogFilter) Normalize() {
|
||
if f.Page <= 0 {
|
||
f.Page = 1
|
||
}
|
||
if f.Size <= 0 {
|
||
f.Size = 10
|
||
}
|
||
if f.Size > 100 {
|
||
f.Size = 100
|
||
}
|
||
if f.Status == 0 && f.Result > 0 {
|
||
f.Status = f.Result
|
||
}
|
||
if f.OrderDir != "asc" {
|
||
f.OrderDir = "desc"
|
||
}
|
||
if f.OrderBy != "durationMs" {
|
||
f.OrderBy = "createdAt"
|
||
}
|
||
}
|
||
|
||
// RenderTemplate 简单模板渲染:将 {{key}} 替换为 vars 中对应值。
|
||
func RenderTemplate(tpl string, vars map[string]string) string {
|
||
out := tpl
|
||
for k, v := range vars {
|
||
out = strings.ReplaceAll(out, "{{"+k+"}}", v)
|
||
}
|
||
return out
|
||
}
|