初始化项目
This commit is contained in:
57
Dockerfile
Normal file
57
Dockerfile
Normal file
@@ -0,0 +1,57 @@
|
||||
FROM golang:1.25.3
|
||||
RUN go env -w GO111MODULE=on
|
||||
RUN go env -w GOPROXY=https://goproxy.cn,direct
|
||||
ENV WORKDIR /usr/local/bin/app
|
||||
WORKDIR $WORKDIR
|
||||
|
||||
ENV TIME_ZONE=Asia/Seoul
|
||||
RUN useradd -ms /bin/bash golang
|
||||
|
||||
|
||||
RUN ln -sf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime \
|
||||
&& chmod 0755 /usr/bin/wall \
|
||||
&& chmod 0755 /usr/bin/passwd \
|
||||
&& chmod 0755 /usr/bin/newgrp \
|
||||
&& chmod 0755 /usr/bin/chfn \
|
||||
&& chmod 0755 /usr/bin/chage \
|
||||
&& chmod 0755 /usr/bin/gpasswd \
|
||||
&& chmod 0755 /usr/bin/chsh \
|
||||
&& chmod 0755 /usr/bin/expiry \
|
||||
&& chmod 0755 /bin/umount \
|
||||
&& chmod 0755 /bin/mount \
|
||||
&& chmod 0755 /bin/su \
|
||||
&& chmod 0755 /sbin/unix_chkpwd \
|
||||
&& chmod 110 /usr/bin/chfn \
|
||||
&& chmod 110 /usr/bin/passwd \
|
||||
&& chmod 110 /usr/bin/newgrp \
|
||||
&& chmod 110 /usr/bin/chsh \
|
||||
&& chmod 110 /usr/bin/wall \
|
||||
&& chmod 110 /usr/bin/gpasswd \
|
||||
&& chmod 110 /usr/bin/expiry \
|
||||
&& chmod 110 /usr/bin/chage \
|
||||
&& chmod 110 /bin/mount \
|
||||
&& chmod 110 /bin/umount \
|
||||
&& chmod 110 /bin/su \
|
||||
&& chmod 110 /sbin/unix_chkpwd \
|
||||
&& chmod 110 /usr/lib/openssh/ssh-keysign \
|
||||
&& chmod 110 /usr/bin/ssh-agent
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
# RUN chown -R golang:golang $WORKDIR
|
||||
RUN go mod download && go mod verify
|
||||
COPY ../../cidService $WORKDIR
|
||||
RUN chown -R golang:golang $WORKDIR
|
||||
# Remove SetUID, SetGID
|
||||
RUN chmod 0755 /usr/local/bin/app/api \
|
||||
&& chmod 0755 /usr/local/bin/app/common \
|
||||
&& chmod 0755 /usr/local/bin/app/middleware \
|
||||
&& chmod 0755 /usr/local/bin/app/model \
|
||||
&& rm -rf .git \
|
||||
&& rm -rf .gitignore \
|
||||
&& rm -rf .gitlab-ci.yml \
|
||||
&& rm -rf Dockerfile \
|
||||
&& rm -rf config-local.yml
|
||||
USER golang
|
||||
RUN go build -v -o /usr/local/bin/app ./...
|
||||
EXPOSE 3002
|
||||
CMD ./cidService
|
||||
40
config.yml
Normal file
40
config.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
server:
|
||||
address : ":3002"
|
||||
name: "cidService"
|
||||
jwt:
|
||||
secret: "abcdefghijklmnopqrstuvwxyz"
|
||||
rate:
|
||||
limit: 200
|
||||
burst: 300
|
||||
mongo:
|
||||
logger:
|
||||
level: "all"
|
||||
stdout: true
|
||||
address: "mongodb://192.168.3.200:27017/cid_service?retryWrites=true"
|
||||
redis:
|
||||
# 集群模式配置方法
|
||||
default:
|
||||
address: 192.168.3.200:6379
|
||||
db: 0
|
||||
idleTimeout: "60s" #连接最大空闲时间,使用时间字符串例如30s/1m/1d
|
||||
maxConnLifetime: "90s" #连接最长存活时间,使用时间字符串例如30s/1m/1d
|
||||
waitTimeout: "60s" #等待连接池连接的超时时间,使用时间字符串例如30s/1m/1d
|
||||
dialTimeout: "30s" #TCP连接的超时时间,使用时间字符串例如30s/1m/1d
|
||||
readTimeout: "30s" #TCP的Read操作超时时间,使用时间字符串例如30s/1m/1d
|
||||
writeTimeout: "30s" #TCP的Write操作超时时间,使用时间字符串例如30s/1m/1d
|
||||
maxActive: 100
|
||||
consul:
|
||||
address: 192.168.3.200:8500
|
||||
# pass: jiahui8888
|
||||
rabbitMQ:
|
||||
host: 192.168.3.200
|
||||
port: 5672
|
||||
username: guest # 默认用户名
|
||||
password: guest # 默认密码
|
||||
jaeger: #链路追踪
|
||||
addr: 192.168.3.200:4318
|
||||
|
||||
# RAGFlow 智能客服配置
|
||||
ragflow:
|
||||
base_url: "http://192.168.3.200:9380" # RAGFlow 服务地址
|
||||
api_key: "ragflow-your-api-key-here" # RAGFlow API Key(登录 RAGFlow 管理界面 -> 设置 -> API Keys)
|
||||
1
consts/errors.go
Normal file
1
consts/errors.go
Normal file
@@ -0,0 +1 @@
|
||||
package consts
|
||||
1
consts/redis_key.go
Normal file
1
consts/redis_key.go
Normal file
@@ -0,0 +1 @@
|
||||
package consts
|
||||
27
controller/data_controller.go
Normal file
27
controller/data_controller.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"cidService/model/dto"
|
||||
"cidService/service"
|
||||
"context"
|
||||
)
|
||||
|
||||
type cData struct{}
|
||||
|
||||
var Data = &cData{}
|
||||
|
||||
// Add 添加数据
|
||||
func (c *cData) Add(ctx context.Context, req *dto.AddDataReq) (res *dto.AddDataRes, err error) {
|
||||
return service.Data.Add(ctx, req)
|
||||
}
|
||||
|
||||
// Update 更新数据
|
||||
func (c *cData) Update(ctx context.Context, req *dto.UpdateDataReq) (res interface{}, err error) {
|
||||
err = service.Data.Update(ctx, req)
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取数据列表
|
||||
func (c *cData) List(ctx context.Context, req *dto.ListDataReq) (res *dto.ListDataRes, err error) {
|
||||
return service.Data.List(ctx, req)
|
||||
}
|
||||
121
dao/data_dao.go
Normal file
121
dao/data_dao.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"context"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"gitee.com/red-future---jilin-g/common/mongo"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||||
)
|
||||
|
||||
var Data = &data{}
|
||||
|
||||
type data struct{}
|
||||
|
||||
// Insert 插入数据
|
||||
func (d *data) Insert(ctx context.Context, data *entity.Data) (err error) {
|
||||
// 获取stream消息
|
||||
redis := g.Redis()
|
||||
streamMsg, err := redis.Do(ctx, "XREAD", "STREAMS", "data_stream", "$")
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "获取stream消息失败: %v", err)
|
||||
} else {
|
||||
g.Log().Infof(ctx, "获取到stream消息: %v", streamMsg)
|
||||
}
|
||||
|
||||
_, err = mongo.Insert(ctx, []interface{}{data}, entity.DataCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新数据
|
||||
func (d *data) Update(ctx context.Context, req *dto.UpdateDataReq) (err error) {
|
||||
objectId, err := bson.ObjectIDFromHex(req.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
filter := bson.M{"_id": objectId}
|
||||
|
||||
// 构建动态更新字段
|
||||
updateFields := bson.M{}
|
||||
if !g.IsEmpty(req.CustomerId) {
|
||||
updateFields["customerId"] = req.CustomerId
|
||||
}
|
||||
if !g.IsEmpty(req.CustomerServiceId) {
|
||||
updateFields["customerServiceId"] = req.CustomerServiceId
|
||||
}
|
||||
if req.IsInbound != nil {
|
||||
updateFields["isInbound"] = *req.IsInbound
|
||||
}
|
||||
if req.IsActive != nil {
|
||||
updateFields["isActive"] = *req.IsActive
|
||||
}
|
||||
if req.IsServed != nil {
|
||||
updateFields["isServed"] = *req.IsServed
|
||||
}
|
||||
if req.HasSentContactCard != nil {
|
||||
updateFields["hasSentContactCard"] = *req.HasSentContactCard
|
||||
}
|
||||
if req.HasSentNameCard != nil {
|
||||
updateFields["hasSentNameCard"] = *req.HasSentNameCard
|
||||
}
|
||||
if req.HasLeftContactInfo != nil {
|
||||
updateFields["hasLeftContactInfo"] = *req.HasLeftContactInfo
|
||||
}
|
||||
|
||||
if len(updateFields) > 0 {
|
||||
update := bson.M{"$set": updateFields}
|
||||
_, err = mongo.Update(ctx, filter, update, entity.DataCollection)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// buildListFilter 构建列表查询的过滤条件
|
||||
func (d *data) buildListFilter(req *dto.ListDataReq) bson.M {
|
||||
filter := bson.M{}
|
||||
if !g.IsEmpty(req.CustomerId) {
|
||||
filter["customerId"] = req.CustomerId
|
||||
}
|
||||
if !g.IsEmpty(req.CustomerServiceId) {
|
||||
filter["customerServiceId"] = req.CustomerServiceId
|
||||
}
|
||||
return filter
|
||||
}
|
||||
|
||||
// checkTotalCount 检查总数
|
||||
func (d *data) checkTotalCount(ctx context.Context, filter bson.M) (total int64, err error) {
|
||||
total, err = mongo.Count(ctx, filter, entity.DataCollection)
|
||||
return
|
||||
}
|
||||
|
||||
// List 获取数据列表
|
||||
func (d *data) List(ctx context.Context, req *dto.ListDataReq) (list []*entity.Data, total int64, err error) {
|
||||
// 构建查询过滤条件
|
||||
filter := d.buildListFilter(req)
|
||||
|
||||
// 检查总数
|
||||
total, err = d.checkTotalCount(ctx, filter)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 分页参数处理
|
||||
pageNum := req.PageNum
|
||||
if pageNum <= 0 {
|
||||
pageNum = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = http.PageSize
|
||||
}
|
||||
|
||||
limit := int64(pageSize)
|
||||
skip := int64((pageNum - 1) * pageSize)
|
||||
opts := options.Find().SetLimit(limit).SetSkip(skip).SetSort(bson.M{"sessionStartTime": -1})
|
||||
|
||||
err = mongo.Find(ctx, filter, &list, entity.DataCollection, opts)
|
||||
return
|
||||
}
|
||||
14
go.mod
Normal file
14
go.mod
Normal file
@@ -0,0 +1,14 @@
|
||||
module cidService
|
||||
|
||||
go 1.25.3
|
||||
|
||||
require (
|
||||
gitee.com/red-future---jilin-g/common v0.1.9
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.5
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.5
|
||||
github.com/gogf/gf/v2 v2.9.5
|
||||
go.mongodb.org/mongo-driver/v2 v2.4.0
|
||||
golang.org/x/net v0.47.0
|
||||
)
|
||||
|
||||
//replace gitee.com/red-future---jilin-g/common v0.1.9 => ../common
|
||||
21
main.go
Normal file
21
main.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"cidService/controller"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"gitee.com/red-future---jilin-g/common/jaeger"
|
||||
_ "gitee.com/red-future---jilin-g/common/mongo"
|
||||
_ "gitee.com/red-future---jilin-g/common/ragflow" // RAGFlow 客户端自动初始化
|
||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||
_ "github.com/gogf/gf/contrib/nosql/redis/v2"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer jaeger.ShutDown(context.Background())
|
||||
http.RouteRegister([]interface{}{
|
||||
controller.Data,
|
||||
})
|
||||
select {}
|
||||
}
|
||||
67
model/dto/data_dto.go
Normal file
67
model/dto/data_dto.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"cidService/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// AddDataReq 添加数据
|
||||
type AddDataReq struct {
|
||||
g.Meta `path:"/add" method:"post" tags:"数据管理" summary:"添加数据" dc:"记录客服与客户的交互数据"` // 路由: POST /data/add
|
||||
CustomerId string `json:"customerId" v:"required"` // 客户ID
|
||||
CustomerServiceId string `json:"customerServiceId" v:"required"` // 客服ID
|
||||
CustomerServicePlatform string `json:"customerServicePlatform" v:"required"` // 客服平台
|
||||
CustomerServiceName string `json:"customerServiceName" v:"required"` // 客服名称
|
||||
IsInbound bool `json:"isInbound"` // 是否进线
|
||||
IsActive bool `json:"isActive"` // 是否活跃
|
||||
IsServed bool `json:"isServed"` // 是否接待
|
||||
HasSentContactCard bool `json:"hasSentContactCard"` // 是否发联系卡
|
||||
HasSentNameCard bool `json:"hasSentNameCard"` // 是否发名片
|
||||
HasLeftContactInfo bool `json:"hasLeftContactInfo"` // 是否留资
|
||||
SessionStartTime int64 `json:"sessionStartTime"` // 会话开始时间
|
||||
MessageTime int64 `json:"messageTime"` // 消息时间
|
||||
}
|
||||
|
||||
type AddDataRes struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// UpdateDataReq 更新数据
|
||||
type UpdateDataReq struct {
|
||||
g.Meta `path:"/update" method:"post" tags:"数据管理" summary:"更新数据" dc:"更新客服交互数据"` // 路由: POST /data/update
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
CustomerId string `json:"customerId"`
|
||||
CustomerServiceId string `json:"customerServiceId"`
|
||||
CustomerServicePlatform string `json:"customerServicePlatform"`
|
||||
CustomerServiceName string `json:"customerServiceName"`
|
||||
IsInbound *bool `json:"isInbound"` // 使用指针以区分 false 和未传值
|
||||
IsActive *bool `json:"isActive"`
|
||||
IsServed *bool `json:"isServed"`
|
||||
HasSentContactCard *bool `json:"hasSentContactCard"`
|
||||
HasSentNameCard *bool `json:"hasSentNameCard"`
|
||||
HasLeftContactInfo *bool `json:"hasLeftContactInfo"`
|
||||
SessionStartTime int64 `json:"sessionStartTime"`
|
||||
MessageTime int64 `json:"messageTime"`
|
||||
}
|
||||
|
||||
// GetDataReq 获取单个数据
|
||||
type GetDataReq struct {
|
||||
g.Meta `path:"/one" method:"get" tags:"数据管理" summary:"获取数据详情" dc:"根据ID获取单条数据记录"` // 路由: GET /data/one
|
||||
Id string `json:"id" v:"required"` // ID
|
||||
}
|
||||
|
||||
// ListDataReq 获取数据列表
|
||||
type ListDataReq struct {
|
||||
g.Meta `path:"/list" method:"get" tags:"数据管理" summary:"获取数据列表" dc:"分页查询交互数据,支持按客户、客服、时间筛选"` // 路由: GET /data/list
|
||||
http.Page
|
||||
CustomerId string `json:"customerId"` // 筛选:客户ID
|
||||
CustomerServiceId string `json:"customerServiceId"` // 筛选:客服ID
|
||||
DateRange []string `json:"dateRange"` // 筛选:时间范围 [start, end]
|
||||
}
|
||||
|
||||
type ListDataRes struct {
|
||||
List []*entity.Data `json:"list"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
25
model/entity/data.go
Normal file
25
model/entity/data.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"gitee.com/red-future---jilin-g/common/do"
|
||||
)
|
||||
|
||||
const DataCollection = "data"
|
||||
|
||||
type Data struct {
|
||||
do.MongoBaseDO `bson:",inline"` // 嵌入基础字段:Id, Creator, CreatedAt, Updater, UpdatedAt, TenantId, IsDeleted
|
||||
|
||||
// 业务字段
|
||||
CustomerId string `bson:"customerId" json:"customerId"` // 客户ID
|
||||
CustomerServiceId string `bson:"customerServiceId" json:"customerServiceId"` // 客服ID
|
||||
CustomerServicePlatform string `bson:"customerServicePlatform" json:"customerServicePlatform"` // 客服平台
|
||||
CustomerServiceName string `bson:"customerServiceName" json:"customerServiceName"` // 客服名称
|
||||
IsInbound bool `bson:"isInbound" json:"isInbound"` // 用户是否点开了客服页面
|
||||
IsActive bool `bson:"isActive" json:"isActive"` // 用户是否开口询问
|
||||
IsServed bool `bson:"isServed" json:"isServed"` // 客服是否回答了用户
|
||||
HasSentContactCard bool `bson:"hasSentContactCard" json:"hasSentContactCard"` // 客服是否发送了联系卡
|
||||
HasSentNameCard bool `bson:"hasSentNameCard" json:"hasSentNameCard"` // 客服是否发送了名称卡
|
||||
HasLeftContactInfo bool `bson:"hasLeftContactInfo" json:"hasLeftContactInfo"` // 用户是否留下了联系信息
|
||||
SessionStartTime int64 `bson:"sessionStartTime" json:"sessionStartTime"` // 业务数据的时间
|
||||
MessageTime int64 `bson:"messageTime" json:"messageTime"` // 消息时间
|
||||
}
|
||||
53
service/data_service.go
Normal file
53
service/data_service.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"cidService/dao"
|
||||
"cidService/model/dto"
|
||||
"cidService/model/entity"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var Data = new(data)
|
||||
|
||||
type data struct{}
|
||||
|
||||
// Add 添加数据
|
||||
func (s *data) Add(ctx context.Context, req *dto.AddDataReq) (res *dto.AddDataRes, err error) {
|
||||
data := &entity.Data{}
|
||||
if err = gconv.Struct(req, data); err != nil {
|
||||
return
|
||||
}
|
||||
// 设置基础字段
|
||||
now := time.Now()
|
||||
data.CreatedAt = now
|
||||
data.UpdatedAt = now
|
||||
data.IsDeleted = false
|
||||
// 注意:Creator、Updater、TenantId 保持零值,不设置
|
||||
|
||||
if err = dao.Data.Insert(ctx, data); err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.AddDataRes{Id: data.Id.Hex()}
|
||||
return
|
||||
}
|
||||
|
||||
// Update 更新数据
|
||||
func (s *data) Update(ctx context.Context, req *dto.UpdateDataReq) (err error) {
|
||||
return dao.Data.Update(ctx, req)
|
||||
}
|
||||
|
||||
// List 获取数据列表
|
||||
func (s *data) List(ctx context.Context, req *dto.ListDataReq) (res *dto.ListDataRes, err error) {
|
||||
list, total, err := dao.Data.List(ctx, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res = &dto.ListDataRes{
|
||||
List: list,
|
||||
Total: int(total),
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user