This commit is contained in:
hailin 2025-06-20 12:35:40 +08:00
parent 747a0cb171
commit 5007fc9e24
6 changed files with 117 additions and 4 deletions

View File

@ -15,6 +15,7 @@ type BizApi interface {
NewsDraftDelete(c *gin.Context) //草稿删除
NewsTag(c *gin.Context) //新闻打标签
NewsAsync(c *gin.Context) //异步同步数据
NewsAsyncBatch(c *gin.Context) //一次性整批同步数据
NewsPullNew(c *gin.Context) //拉取新的数据
QaList(c *gin.Context) //Q&A列表
QaAdd(c *gin.Context) //Q&A新增

View File

@ -555,6 +555,28 @@ func (m *Controller) NewsAsync(c *gin.Context) {
m.OK(c, resp, len(resp.List), total)
}
func (m *Controller) NewsAsyncBatch(c *gin.Context) {
var req proto.NewsAsyncBatchReq
if err := m.bindJSON(c, &req); err != nil {
log.Errorf("%s", err)
return
}
log.Infof("....................NewsAsyncBatch request: %+v", req)
ctx := sessions.GetContext(c)
var ok bool
if ctx != nil {
ok = m.CheckPrivilege(c, ctx, privilege.NewsAccess)
}
ok = ok
resp, total, code := m.BizCore.NewsAsyncBatch(ctx, &req, true)
if !code.Ok() {
m.Error(c, code)
return
}
m.OK(c, resp, len(resp.List), total)
}
func (m *Controller) NewsPullNew(c *gin.Context) {
var req proto.NewsPullNewReq
if err := m.bindJSON(c, &req); err != nil {

View File

@ -911,6 +911,42 @@ func (m *BizCore) NewsAsync(ctx *itypes.Context, req *proto.NewsAsyncReq, needEx
}, total, itypes.BizOK
}
// NewsAsyncBatch批量差异同步
func (m *BizCore) NewsAsyncBatch(ctx *itypes.Context, req *proto.NewsAsyncBatchReq, needExtra bool) (resp *proto.NewsAsyncResp, total int64, code itypes.BizCode) {
const batchSize = 5000 // 防止 SQL 占位符过长,按需调整
if len(req.List) == 0 {
return &proto.NewsAsyncResp{List: []*models.NewsDO{}}, 0, itypes.BizOK
}
var all []*models.NewsDO
for start := 0; start < len(req.List); start += batchSize {
end := start + batchSize
if end > len(req.List) {
end = len(req.List)
}
// ── ① 把这一块转成 DAO 参数 ──
pairs := make([]dao.OrgDigestPair, end-start)
for i, v := range req.List[start:end] {
pairs[i] = dao.OrgDigestPair{OrgId: v.Org_Id, Digest: v.Digest}
}
// ── ② 一次 SQL 抓差异 ──
chunk, _, err := m.newsDAO.QueryAsyncBatch(pairs)
if err != nil {
return nil, 0, itypes.NewBizCodeDatabaseError(err.Error())
}
all = append(all, chunk...)
}
return &proto.NewsAsyncResp{
List: all,
}, int64(len(all)), itypes.BizOK
}
func (m *BizCore) NewsPullNew(ctx *itypes.Context, req *proto.NewsPullNewReq) (resp *proto.NewsPullNewResp, total int64, code itypes.BizCode) {
dos, total, err := m.newsDAO.QueryPullNew(&dao.NewsPullNewCondition{
OrgIDs: req.OrgIDs,

View File

@ -10,6 +10,12 @@ import (
"github.com/civet148/sqlca/v2"
)
// 客户端带来的本地状态 (org_id, digest)
type OrgDigestPair struct {
OrgId int64
Digest string
}
type NewsAsyncCondition struct {
Org_Id int64
Digest string
@ -393,6 +399,52 @@ func (dao *NewsDAO) QueryAsync(cond *NewsAsyncCondition) (dos []*models.NewsDO,
return []*models.NewsDO{record}, 1, nil
}
// 一次 SQL 抓取该批 org_id对比 digest返回需要下发的记录
func (dao *NewsDAO) QueryAsyncBatch(pairs []OrgDigestPair) (dos []*models.NewsDO, total int64, err error) {
if len(pairs) == 0 {
return []*models.NewsDO{}, 0, nil
}
// ① 提取 org_id 列表,同时建映射表 clientDigest[org_id] = digest
orgIDs := make([]int64, 0, len(pairs))
clientDigest := make(map[int64]string, len(pairs))
for _, p := range pairs {
orgIDs = append(orgIDs, p.OrgId)
clientDigest[p.OrgId] = p.Digest
}
// ② 一次 SQLSELECT * FROM news WHERE org_id IN ( … )
var rows []*models.NewsDO
// err 已在函数签名里声明
_, err = dao.db.
Model(&rows). // 告诉 sqlca 目标对象是 []*models.NewsDO
Table(models.TableNameNews).
Where("org_id IN ?", orgIDs).
Query() // 用 Query 而不是 Find
if err != nil {
return nil, 0, err
}
// ③ 在 Go 层比对 digest
for _, row := range rows {
cDigest := clientDigest[row.OrgId] // 客户端传来的 digest
// 直接从 map[string]interface{} 里取
var sDigest string
if d, ok := row.ExtraData["digest"].(string); ok {
sDigest = d
}
// cDigest 为空 或 与服务器端不同,都需要下发
if cDigest == "" || cDigest != sDigest {
dos = append(dos, row)
}
}
return dos, int64(len(dos)), nil
}
func (dao *NewsDAO) QueryPullNew(cond *NewsPullNewCondition) (dos []*models.NewsDO, total int64, err error) {
e := dao.db.Model(&dos).
Table(models.TableNameNews).

View File

@ -285,6 +285,10 @@ type NewsAsyncReq struct {
Digest string `json:"digest"`
}
type NewsAsyncBatchReq struct {
List []NewsAsyncReq `json:"list"`
}
type NewsAsyncResp struct {
List []*models.NewsDO `json:"list"`
}
@ -296,7 +300,3 @@ type NewsPullNewReq struct {
type NewsPullNewResp struct {
List []*models.NewsDO `json:"list"`
}
type NewsAsyncBatchReq struct {
List []NewsAsyncReq `json:"list"`
}

View File

@ -27,6 +27,7 @@ const (
RouterSubPathNewsDraftDelete = "/draft/delete"
RouterSubPathNewsTag = "/tag"
RouterSubPathNewsAsync = "/async"
RouterSubPathNewsAsyncBatch = "/asyncbatch"
RouterSubPathNewsPullNew = "/pullnew"
RouterSubPathQaList = "/list"
RouterSubPathQaAdd = "/add"
@ -51,6 +52,7 @@ func InitRouterGroupBiz(r *gin.Engine, handlers api.BizApi) {
groupNews.POST(RouterSubPathNewsList, handlers.NewsList)
groupNews.POST(RouterSubPathNewsAsync, handlers.NewsAsync)
groupNews.POST(RouterSubPathNewsAsyncBatch, handlers.NewsAsyncBatch)
groupNews.POST(RouterSubPathNewsPullNew, handlers.NewsPullNew)
groupNews.Use(middleware.JWT()) //use JWT token middleware
{