Compare commits
24 Commits
c96ee6cc38
...
c4e2d30fc5
| Author | SHA1 | Date |
|---|---|---|
|
|
c4e2d30fc5 | |
|
|
fab60c6fc8 | |
|
|
ecd2490a24 | |
|
|
b3c807f0ac | |
|
|
3b8af9ada9 | |
|
|
6d31c923fb | |
|
|
12751a6434 | |
|
|
1b8077f403 | |
|
|
fcf6bcbe75 | |
|
|
1e75c68984 | |
|
|
7ab366d5d4 | |
|
|
056a784dea | |
|
|
531facbb07 | |
|
|
59a7d1c7a5 | |
|
|
f9b49d21b3 | |
|
|
c0986179b5 | |
|
|
941827ce41 | |
|
|
7f704b3cb1 | |
|
|
69178bd431 | |
|
|
f2c2276ca6 | |
|
|
e1581b2d6f | |
|
|
219df62816 | |
|
|
67c047367d | |
|
|
95a01dd4b7 |
|
|
@ -12,6 +12,7 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
configPath := flag.String("config", "./config/config_test.yaml", "Path to configuration file")
|
configPath := flag.String("config", "./config/config_test.yaml", "Path to configuration file")
|
||||||
onBot := flag.String("bot", "", "bot start")
|
onBot := flag.String("bot", "", "bot start")
|
||||||
|
cron := flag.String("cron", "", "close")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
bc, err := config.LoadConfig(*configPath)
|
bc, err := config.LoadConfig(*configPath)
|
||||||
|
|
@ -29,7 +30,7 @@ func main() {
|
||||||
//钉钉机器人
|
//钉钉机器人
|
||||||
app.DingBotServer.Run(ctx, *onBot)
|
app.DingBotServer.Run(ctx, *onBot)
|
||||||
//定时任务 - 测试环境不启用
|
//定时任务 - 测试环境不启用
|
||||||
if configPath != nil && *configPath == "./config/config.yaml" {
|
if *cron == "start" {
|
||||||
app.Cron.Run(ctx)
|
app.Cron.Run(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ redis:
|
||||||
host: 47.97.27.195:6379
|
host: 47.97.27.195:6379
|
||||||
type: node
|
type: node
|
||||||
pass: lansexiongdi@666
|
pass: lansexiongdi@666
|
||||||
key: report-api-test
|
key: ai_scheduler_prov
|
||||||
pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池
|
pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池
|
||||||
minIdleConns: 2 #最小空闲连接数
|
minIdleConns: 2 #最小空闲连接数
|
||||||
maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭
|
maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭
|
||||||
|
|
@ -108,6 +108,8 @@ tools:
|
||||||
base_url: "https://api.coze.cn"
|
base_url: "https://api.coze.cn"
|
||||||
api_key: "7583905168607100978"
|
api_key: "7583905168607100978"
|
||||||
api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ"
|
api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ"
|
||||||
|
zltxResellerAuthProductToManagerAndDefaultLossReason:
|
||||||
|
base_url: "https://revcl.1688sup.com/api/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason"
|
||||||
|
|
||||||
# eino tool 配置
|
# eino tool 配置
|
||||||
eino_tools:
|
eino_tools:
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ lsxd:
|
||||||
phone: "ORlviZN7N06W2+WKLe76xg=="
|
phone: "ORlviZN7N06W2+WKLe76xg=="
|
||||||
password: "V5Uh8C4bamEM6UQZh4TCeQ=="
|
password: "V5Uh8C4bamEM6UQZh4TCeQ=="
|
||||||
check_token_url: "https://api.user.1688sup.com/v1/user/welcome"
|
check_token_url: "https://api.user.1688sup.com/v1/user/welcome"
|
||||||
|
code: "456789"
|
||||||
|
|
||||||
sys:
|
sys:
|
||||||
session_len: 6
|
session_len: 6
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ server:
|
||||||
host: "0.0.0.0"
|
host: "0.0.0.0"
|
||||||
|
|
||||||
ollama:
|
ollama:
|
||||||
base_url: "http://127.0.0.1:11434"
|
base_url: "http://192.168.6.115:11434"
|
||||||
model: "qwen3-coder:480b-cloud"
|
model: "qwen3:8b"
|
||||||
generate_model: "qwen3-coder:480b-cloud"
|
generate_model: "qwen3:8b"
|
||||||
mapping_model: "deepseek-v3.2:cloud"
|
mapping_model: "qwen3:8b"
|
||||||
vl_model: "gemini-3-pro-preview"
|
vl_model: "gemini-3-pro-preview"
|
||||||
timeout: "120s"
|
timeout: "120s"
|
||||||
level: "info"
|
level: "info"
|
||||||
|
|
@ -32,8 +32,6 @@ lsxd:
|
||||||
code: "123456"
|
code: "123456"
|
||||||
check_token_url: "http://api.test.user.1688sup.com/v1/user/welcome"
|
check_token_url: "http://api.test.user.1688sup.com/v1/user/welcome"
|
||||||
|
|
||||||
zltx:
|
|
||||||
req_url: "https://gateway.dev.cdlsxd.cn/zltx_api"
|
|
||||||
|
|
||||||
sys:
|
sys:
|
||||||
session_len: 6
|
session_len: 6
|
||||||
|
|
@ -45,7 +43,7 @@ redis:
|
||||||
host: 47.97.27.195:6379
|
host: 47.97.27.195:6379
|
||||||
type: node
|
type: node
|
||||||
pass: lansexiongdi@666
|
pass: lansexiongdi@666
|
||||||
key: ai_scheduler-test
|
key: ai_scheduler_test
|
||||||
pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池
|
pollSize: 5 #连接池大小,不配置,或配置为0表示不启用连接池
|
||||||
minIdleConns: 2 #最小空闲连接数
|
minIdleConns: 2 #最小空闲连接数
|
||||||
maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭
|
maxIdleTime: 30 #每个连接最大空闲时间,如果超过了这个时间会被关闭
|
||||||
|
|
@ -106,6 +104,8 @@ tools:
|
||||||
base_url: "https://api.coze.cn"
|
base_url: "https://api.coze.cn"
|
||||||
api_key: "7583905168607100978"
|
api_key: "7583905168607100978"
|
||||||
api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ"
|
api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ"
|
||||||
|
zltxResellerAuthProductToManagerAndDefaultLossReason:
|
||||||
|
base_url: "https://revcl.1688sup.com/api/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason"
|
||||||
|
|
||||||
# eino tool 配置
|
# eino tool 配置
|
||||||
eino_tools:
|
eino_tools:
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,12 @@ fi
|
||||||
CONFIG_FILE="config/config.yaml"
|
CONFIG_FILE="config/config.yaml"
|
||||||
BRANCH="master"
|
BRANCH="master"
|
||||||
BOT="All"
|
BOT="All"
|
||||||
|
CRON="start"
|
||||||
if [ "$MODE" = "dev" ]; then
|
if [ "$MODE" = "dev" ]; then
|
||||||
CONFIG_FILE="config/config_test.yaml"
|
CONFIG_FILE="config/config_test.yaml"
|
||||||
BOT="zltx"
|
BOT="zltx"
|
||||||
BRANCH="test"
|
BRANCH="test"
|
||||||
|
CRON="close"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
git fetch origin
|
git fetch origin
|
||||||
|
|
@ -47,6 +49,8 @@ docker run -itd \
|
||||||
-v ./cache:/app/cache \
|
-v ./cache:/app/cache \
|
||||||
-v ./tmpl:/app/tmpl \
|
-v ./tmpl:/app/tmpl \
|
||||||
-v ./go.mod:/app/go.mod \
|
-v ./go.mod:/app/go.mod \
|
||||||
"${CONTAINER_NAME}" ./server --config "./${CONFIG_FILE}" --bot "${BOT}"
|
"${CONTAINER_NAME}" ./server \
|
||||||
|
--config "./${CONFIG_FILE}" --bot "${BOT}" --cron "${CRON}"
|
||||||
|
|
||||||
|
|
||||||
docker logs -f ${CONTAINER_NAME}
|
docker logs -f ${CONTAINER_NAME}
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"ai_scheduler/internal/data/impl"
|
"ai_scheduler/internal/data/impl"
|
||||||
"ai_scheduler/internal/data/model"
|
"ai_scheduler/internal/data/model"
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
|
"ai_scheduler/internal/pkg"
|
||||||
"ai_scheduler/internal/tools"
|
"ai_scheduler/internal/tools"
|
||||||
"ai_scheduler/internal/tools/bbxt"
|
"ai_scheduler/internal/tools/bbxt"
|
||||||
"ai_scheduler/tmpl/dataTemp"
|
"ai_scheduler/tmpl/dataTemp"
|
||||||
|
|
@ -19,7 +20,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
|
||||||
|
|
||||||
|
|
@ -45,6 +45,7 @@ type DingTalkBotBiz struct {
|
||||||
qywxGroupHandle *qywx.Group
|
qywxGroupHandle *qywx.Group
|
||||||
groupConfigBiz *GroupConfigBiz
|
groupConfigBiz *GroupConfigBiz
|
||||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
||||||
|
macro *do.Macro
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDingTalkBotBiz
|
// NewDingTalkBotBiz
|
||||||
|
|
@ -60,6 +61,7 @@ func NewDingTalkBotBiz(
|
||||||
conf *config.Config,
|
conf *config.Config,
|
||||||
cardSend *dingtalk.SendCardClient,
|
cardSend *dingtalk.SendCardClient,
|
||||||
groupConfigBiz *GroupConfigBiz,
|
groupConfigBiz *GroupConfigBiz,
|
||||||
|
macro *do.Macro,
|
||||||
) *DingTalkBotBiz {
|
) *DingTalkBotBiz {
|
||||||
return &DingTalkBotBiz{
|
return &DingTalkBotBiz{
|
||||||
do: do,
|
do: do,
|
||||||
|
|
@ -74,6 +76,7 @@ func NewDingTalkBotBiz(
|
||||||
conf: conf,
|
conf: conf,
|
||||||
cardSend: cardSend,
|
cardSend: cardSend,
|
||||||
reportDailyCacheImpl: reportDailyCacheImpl,
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
|
macro: macro,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -148,10 +151,14 @@ func (d *DingTalkBotBiz) handleGroupChat(ctx context.Context, requireData *entit
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//宏
|
//宏
|
||||||
err, isFinal := d.Macro(ctx, requireData, groupConfig)
|
sucMsg, err, isFinal := d.macro.Router(ctx, requireData.Req.Text.Content, groupConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
entitys.ResText(requireData.Ch, "", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(sucMsg) > 0 {
|
||||||
|
entitys.ResText(requireData.Ch, "", sucMsg)
|
||||||
|
}
|
||||||
if isFinal {
|
if isFinal {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -168,102 +175,6 @@ func (d *DingTalkBotBiz) handleGroupChat(ctx context.Context, requireData *entit
|
||||||
return d.groupConfigBiz.handleMatch(ctx, rec, groupConfig)
|
return d.groupConfigBiz.handleMatch(ctx, rec, groupConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DingTalkBotBiz) Macro(ctx context.Context, requireData *entitys.RequireDataDingTalkBot, groupConfig *model.AiBotGroupConfig) (err error, isFinish bool) {
|
|
||||||
content := processString(requireData.Req.Text.Content)
|
|
||||||
|
|
||||||
if strings.Contains(content, "[利润同比报表]商品修改:") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if parts := strings.SplitN(content, ":", 2); len(parts) == 2 {
|
|
||||||
itemInfo := strings.TrimSpace(parts[1])
|
|
||||||
log.Infof("商品修改信息: %s", itemInfo)
|
|
||||||
groupConfig.ProductName = itemInfo
|
|
||||||
cond := builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"config_id": groupConfig.ConfigID})
|
|
||||||
err = d.botGroupImpl.UpdateByCond(&cond, groupConfig)
|
|
||||||
if err != nil {
|
|
||||||
entitys.ResText(requireData.Ch, "", fmt.Sprintf("修改失败:%v", err))
|
|
||||||
}
|
|
||||||
entitys.ResText(requireData.Ch, "", "修改成功")
|
|
||||||
isFinish = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[利润同比报表]商品列表") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if len(groupConfig.ProductName) == 0 {
|
|
||||||
entitys.ResText(requireData.Ch, "", "暂未设置")
|
|
||||||
} else {
|
|
||||||
entitys.ResText(requireData.Ch, "", groupConfig.ProductName)
|
|
||||||
isFinish = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[负利润分析]获取") {
|
|
||||||
var (
|
|
||||||
data model.AiReportDailyCache
|
|
||||||
value map[int32]*bbxt.ResellerLossSumProductRelation
|
|
||||||
)
|
|
||||||
cond := builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"`index`": bbxt.IndexLossSumDetail})
|
|
||||||
cond = cond.And(builder.Eq{"`key`": time.Now().Format(time.DateOnly)})
|
|
||||||
err = d.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &data)
|
|
||||||
if err != nil {
|
|
||||||
entitys.ResText(requireData.Ch, "", "获取失败")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal([]byte(data.Value), &value)
|
|
||||||
if err != nil {
|
|
||||||
entitys.ResText(requireData.Ch, "", "获取失败,格式解析错误")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[负利润分析]更新") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if len(groupConfig.ProductName) == 0 {
|
|
||||||
entitys.ResText(requireData.Ch, "", "暂未设置")
|
|
||||||
} else {
|
|
||||||
entitys.ResText(requireData.Ch, "", groupConfig.ProductName)
|
|
||||||
isFinish = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(content, "[负利润分析]同步") {
|
|
||||||
// 提取冒号后的内容
|
|
||||||
if len(groupConfig.ProductName) == 0 {
|
|
||||||
entitys.ResText(requireData.Ch, "", "暂未设置")
|
|
||||||
} else {
|
|
||||||
entitys.ResText(requireData.Ch, "", groupConfig.ProductName)
|
|
||||||
isFinish = true
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func processString(s string) string {
|
|
||||||
// 1. 替换中文逗号为英文逗号
|
|
||||||
s = strings.ReplaceAll(s, ",", ",")
|
|
||||||
|
|
||||||
// 2. 过滤控制字符(如 \n, \t, \r 等)
|
|
||||||
var result []rune
|
|
||||||
for _, char := range s {
|
|
||||||
// 判断是否是控制字符(ASCII < 32 或 = 127)
|
|
||||||
if !unicode.IsControl(char) {
|
|
||||||
// 如果需要完全移除 \n 和 \t,可以改成:
|
|
||||||
// if !unicode.IsControl(char)
|
|
||||||
result = append(result, char)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DingTalkBotBiz) initGroup(ctx context.Context, conversationId string, conversationTitle string, robotCode string) (group *model.AiBotGroup, err error) {
|
func (d *DingTalkBotBiz) initGroup(ctx context.Context, conversationId string, conversationTitle string, robotCode string) (group *model.AiBotGroup, err error) {
|
||||||
group, err = d.botGroupImpl.GetByConversationIdAndRobotCode(conversationId, robotCode)
|
group, err = d.botGroupImpl.GetByConversationIdAndRobotCode(conversationId, robotCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -313,11 +224,16 @@ func (d *DingTalkBotBiz) recognize(ctx context.Context, requireData *entitys.Req
|
||||||
|
|
||||||
rec.Tasks = append(rec.Tasks, entitys.RegistrationTask{
|
rec.Tasks = append(rec.Tasks, entitys.RegistrationTask{
|
||||||
Name: task.Index,
|
Name: task.Index,
|
||||||
Desc: task.Desc,
|
Desc: task.TempPrompt,
|
||||||
TaskConfigDetail: taskConfig, // 直接使用解析后的配置,避免重复构建
|
TaskConfigDetail: taskConfig, // 直接使用解析后的配置,避免重复构建
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rec.Ext = pkg.JsonByteIgonErr(&entitys.TaskExt{
|
||||||
|
UserName: requireData.Req.SenderNick,
|
||||||
|
})
|
||||||
|
|
||||||
err = d.handle.Recognize(ctx, rec, &do.WithDingTalkBot{})
|
err = d.handle.Recognize(ctx, rec, &do.WithDingTalkBot{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -483,7 +399,7 @@ func (d *DingTalkBotBiz) defaultPrompt() string {
|
||||||
- 注意区分 parameters 中的 必须参数(required) 和 可选参数(optional),按下述参数提取规则处理。
|
- 注意区分 parameters 中的 必须参数(required) 和 可选参数(optional),按下述参数提取规则处理。
|
||||||
- 若**完全无法匹配**,立即设置 is_match: false,并在 chat 中已第一人称的角度提醒用户需要适用何种工具(例:"请问您是要查询订单还是商品呢")。
|
- 若**完全无法匹配**,立即设置 is_match: false,并在 chat 中已第一人称的角度提醒用户需要适用何种工具(例:"请问您是要查询订单还是商品呢")。
|
||||||
|
|
||||||
1. **参数提取**:
|
3. **参数提取**:
|
||||||
|
|
||||||
- 根据 parameters 字段列出的参数名,从用户输入中提取对应值。
|
- 根据 parameters 字段列出的参数名,从用户输入中提取对应值。
|
||||||
- **仅提取**明确提及的参数,忽略未列出的内容。
|
- **仅提取**明确提及的参数,忽略未列出的内容。
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,9 @@ func (r *Handle) HandleMatch(ctx context.Context, client *gateway.Client, rec *e
|
||||||
case constants.TaskTypeFunc:
|
case constants.TaskTypeFunc:
|
||||||
return r.handleTask(ctx, rec, pointTask)
|
return r.handleTask(ctx, rec, pointTask)
|
||||||
case constants.TaskTypeBot:
|
case constants.TaskTypeBot:
|
||||||
return r.handleBot(ctx, rec, pointTask)
|
return r.HandleBot(ctx, rec, &entitys.Task{
|
||||||
|
Index: pointTask.Index,
|
||||||
|
})
|
||||||
case constants.TaskTypeEinoWorkflow:
|
case constants.TaskTypeEinoWorkflow:
|
||||||
return r.handleEinoWorkflow(ctx, rec, pointTask)
|
return r.handleEinoWorkflow(ctx, rec, pointTask)
|
||||||
case constants.TaskTypeCozeWorkflow:
|
case constants.TaskTypeCozeWorkflow:
|
||||||
|
|
@ -247,23 +249,34 @@ func (r *Handle) handleKnowle(ctx context.Context, rec *entitys.Recognize, task
|
||||||
}
|
}
|
||||||
|
|
||||||
// bot 临时实现,后续转到 eino 工作流
|
// bot 临时实现,后续转到 eino 工作流
|
||||||
func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *model.AiTask) (err error) {
|
func (r *Handle) HandleBot(ctx context.Context, rec *entitys.Recognize, task *entitys.Task) (err error) {
|
||||||
if task.Index == "bug_optimization_submit" {
|
if task.Index == "bug_optimization_submit" {
|
||||||
entitys.ResLoading(rec.Ch, task.Index, "需求记录中...")
|
var unionId string
|
||||||
|
entitys.ResLoading(rec.Ch, task.Index, "需求记录中...\n")
|
||||||
// Ext 中获取 sessionId
|
|
||||||
sessionID := rec.GetSession()
|
|
||||||
// 获取dingtalk accessToken
|
// 获取dingtalk accessToken
|
||||||
accessToken, _ := r.dingtalkOldClient.GetAccessToken()
|
accessToken, _ := r.dingtalkOldClient.GetAccessToken()
|
||||||
// 获取创建者 dingtalk unionId
|
// Ext 中获取 sessionId
|
||||||
unionId := r.getUserDingtalkUnionId(ctx, accessToken, sessionID)
|
taskExt := rec.GetTaskExt()
|
||||||
|
if taskExt == nil {
|
||||||
|
return errorcode.ParamErr("taskExt参数错误")
|
||||||
|
}
|
||||||
|
if len(taskExt.Session) > 0 {
|
||||||
|
// 获取创建者 dingtalk unionId
|
||||||
|
unionId = r.getUserDingtalkUnionId(ctx, accessToken, taskExt.Session)
|
||||||
|
} else if len(taskExt.UserName) > 0 {
|
||||||
|
unionId = r.getUserDingtalkUnionIdWithUserName(ctx, accessToken, taskExt.UserName)
|
||||||
|
} else {
|
||||||
|
return errorcode.ParamErr("taskExt参数错误,重要参数缺失")
|
||||||
|
}
|
||||||
|
|
||||||
// 附件url
|
// 附件url
|
||||||
var attachmentUrl string
|
var attachmentUrl string
|
||||||
for _, file := range rec.UserContent.File {
|
for _, file := range rec.UserContent.File {
|
||||||
attachmentUrl = file.FileUrl
|
attachmentUrl = file.FileUrl
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
recordId, err := r.dingtalkNotableClient.InsertRecord(accessToken, &dingtalk.InsertRecordReq{
|
|
||||||
|
req := &dingtalk.InsertRecordReq{
|
||||||
BaseId: r.conf.Dingtalk.TableDemand.BaseId,
|
BaseId: r.conf.Dingtalk.TableDemand.BaseId,
|
||||||
SheetIdOrName: r.conf.Dingtalk.TableDemand.SheetIdOrName,
|
SheetIdOrName: r.conf.Dingtalk.TableDemand.SheetIdOrName,
|
||||||
// OperatorId: tool_callback.BotBugOptimizationSubmitAdminUnionId,
|
// OperatorId: tool_callback.BotBugOptimizationSubmitAdminUnionId,
|
||||||
|
|
@ -271,7 +284,9 @@ func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *mo
|
||||||
CreatorUnionId: unionId,
|
CreatorUnionId: unionId,
|
||||||
Content: rec.UserContent.Text,
|
Content: rec.UserContent.Text,
|
||||||
AttachmentUrl: attachmentUrl,
|
AttachmentUrl: attachmentUrl,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
recordId, err := r.dingtalkNotableClient.InsertRecord(accessToken, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCode := r.dingtalkNotableClient.GetHTTPStatus(err)
|
errCode := r.dingtalkNotableClient.GetHTTPStatus(err)
|
||||||
// 权限不足
|
// 权限不足
|
||||||
|
|
@ -284,12 +299,16 @@ func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *mo
|
||||||
if recordId == "" {
|
if recordId == "" {
|
||||||
return errors.NewBusinessErr(422, "创建记录失败,请联系管理员")
|
return errors.NewBusinessErr(422, "创建记录失败,请联系管理员")
|
||||||
}
|
}
|
||||||
|
var detailPage string
|
||||||
entitys.ResLog(rec.Ch, task.Index, "需求记录完成")
|
entitys.ResLog(rec.Ch, task.Index, "需求记录完成")
|
||||||
|
switch task.OutPutFormat {
|
||||||
// 构建跳转链接
|
case entitys.OutPutFormatMarkdown:
|
||||||
detailPage := util.BuildJumpLink(r.conf.Dingtalk.TableDemand.Url, "去查看")
|
// 构建跳转链接
|
||||||
|
detailPage = "[去查看](" + r.conf.Dingtalk.TableDemand.Url + ")"
|
||||||
|
default:
|
||||||
|
// 构建跳转链接
|
||||||
|
detailPage = util.BuildJumpLink(r.conf.Dingtalk.TableDemand.Url, "去查看")
|
||||||
|
}
|
||||||
entitys.ResText(rec.Ch, task.Index, fmt.Sprintf("需求已记录,正在分配相关人员处理,请您耐心等待处理结果。点击查看工单进度:%s", detailPage))
|
entitys.ResText(rec.Ch, task.Index, fmt.Sprintf("需求已记录,正在分配相关人员处理,请您耐心等待处理结果。点击查看工单进度:%s", detailPage))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -300,16 +319,21 @@ func (r *Handle) handleBot(ctx context.Context, rec *entitys.Recognize, task *mo
|
||||||
|
|
||||||
// getUserDingtalkUnionId 获取用户的 dingtalk unionId
|
// getUserDingtalkUnionId 获取用户的 dingtalk unionId
|
||||||
func (r *Handle) getUserDingtalkUnionId(ctx context.Context, accessToken, sessionID string) (unionId string) {
|
func (r *Handle) getUserDingtalkUnionId(ctx context.Context, accessToken, sessionID string) (unionId string) {
|
||||||
// 查询用户名
|
if len(sessionID) == 0 {
|
||||||
|
// 查询用户名
|
||||||
|
return ""
|
||||||
|
}
|
||||||
session, has, err := r.sessionImpl.FindOne(r.sessionImpl.WithSessionId(sessionID))
|
session, has, err := r.sessionImpl.FindOne(r.sessionImpl.WithSessionId(sessionID))
|
||||||
if err != nil || !has {
|
if err != nil || !has {
|
||||||
log.Warnf("session not found: %s", sessionID)
|
log.Warnf("session not found: %s", sessionID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
creatorName := session.UserName
|
return r.getUserDingtalkUnionIdWithUserName(ctx, accessToken, session.UserName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Handle) getUserDingtalkUnionIdWithUserName(ctx context.Context, accessToken, userName string) (unionId string) {
|
||||||
// 获取创建者uid 用户名 -> dingtalk uid
|
// 获取创建者uid 用户名 -> dingtalk uid
|
||||||
creatorId, err := r.dingtalkContactClient.SearchUserOne(accessToken, creatorName)
|
creatorId, err := r.dingtalkContactClient.SearchUserOne(accessToken, userName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("search dingtalk user one failed: %v", err)
|
log.Warnf("search dingtalk user one failed: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,460 @@
|
||||||
|
package do
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ai_scheduler/internal/config"
|
||||||
|
"ai_scheduler/internal/data/impl"
|
||||||
|
"ai_scheduler/internal/data/model"
|
||||||
|
"ai_scheduler/internal/pkg"
|
||||||
|
"ai_scheduler/internal/pkg/lsxd"
|
||||||
|
"ai_scheduler/internal/tools/bbxt"
|
||||||
|
"ai_scheduler/utils"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2/log"
|
||||||
|
"xorm.io/builder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Macro struct {
|
||||||
|
botGroupImpl *impl.BotGroupImpl
|
||||||
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl
|
||||||
|
config *config.Config
|
||||||
|
rdb *utils.Rdb
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMacro(
|
||||||
|
botGroupImpl *impl.BotGroupImpl,
|
||||||
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
||||||
|
config *config.Config,
|
||||||
|
rdb *utils.Rdb,
|
||||||
|
) *Macro {
|
||||||
|
return &Macro{
|
||||||
|
botGroupImpl: botGroupImpl,
|
||||||
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
|
config: config,
|
||||||
|
rdb: rdb,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MacroFunc func(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig, config *config.Config) (successMsg string, err error, isFinish bool)
|
||||||
|
|
||||||
|
func (m *Macro) Router(ctx context.Context, reqContent string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||||
|
reqContent = strings.TrimSpace(reqContent)
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(reqContent, "[利润同比报表]商品修改"):
|
||||||
|
return m.ProductModify(ctx, reqContent, groupConfig)
|
||||||
|
case strings.HasPrefix(reqContent, "[利润同比报表]商品列表"):
|
||||||
|
return m.ProductList(ctx, groupConfig)
|
||||||
|
case strings.HasPrefix(reqContent, "[负利润分析]导出"):
|
||||||
|
return m.NegativeProfitGet(ctx)
|
||||||
|
case strings.HasPrefix(reqContent, "[负利润分析]更新"):
|
||||||
|
return m.NegativeProfitUpdate(ctx, reqContent)
|
||||||
|
case strings.HasPrefix(reqContent, "[负利润分析]清理"):
|
||||||
|
return m.NegativeProfitClear()
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) NegativeProfitClear() (successMsg string, err error, isFinish bool) {
|
||||||
|
dayDate := time.Now().Format(time.DateOnly)
|
||||||
|
cond := builder.NewCond()
|
||||||
|
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||||
|
cond = cond.And(builder.Eq{"cache_key": dayDate})
|
||||||
|
cond = cond.And(builder.Eq{"status": 1})
|
||||||
|
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
|
||||||
|
Status: 2,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("解析失败:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isFinish = true
|
||||||
|
successMsg = "清理成功"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string) (successMsg string, err error, isFinish bool) {
|
||||||
|
//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
|
||||||
|
jsonData, err := ParseLossData(content)
|
||||||
|
b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
now := time.Now()
|
||||||
|
dayData := now.Format(time.DateOnly)
|
||||||
|
value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var setData = make(map[int32]*bbxt.ResellerLossSumProductRelation)
|
||||||
|
for k, v := range jsonData {
|
||||||
|
if _, ok := value[k]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for productId, product := range v.Products {
|
||||||
|
if _, ok := value[k].Products[productId]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if value[k].Products[productId].LossReason == product.LossReason {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ex := setData[k]; !ex {
|
||||||
|
setData[k] = &bbxt.ResellerLossSumProductRelation{
|
||||||
|
ResellerName: value[k].ResellerName,
|
||||||
|
AfterSaleName: value[k].AfterSaleName,
|
||||||
|
Products: make(map[int32]*bbxt.LossReason),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setData[k].Products[productId] = &bbxt.LossReason{
|
||||||
|
ProductName: product.ProductName,
|
||||||
|
LossReason: product.LossReason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond := builder.NewCond()
|
||||||
|
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
|
||||||
|
cond = cond.And(builder.Eq{"cache_key": dayData})
|
||||||
|
cond = cond.And(builder.Eq{"status": 1})
|
||||||
|
var cache model.AiReportDailyCache
|
||||||
|
err = m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cache.ID == 0 {
|
||||||
|
|
||||||
|
cache = model.AiReportDailyCache{
|
||||||
|
CacheKey: dayData,
|
||||||
|
CacheIndex: bbxt.IndexLossSumDetail,
|
||||||
|
Value: pkg.JsonStringIgonErr(setData),
|
||||||
|
}
|
||||||
|
_, err = m.reportDailyCacheImpl.Add(&cache)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
|
||||||
|
Value: pkg.JsonStringIgonErr(setData),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isFinish = true
|
||||||
|
successMsg = "更新成功"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err error, isFinish bool) {
|
||||||
|
b, err := bbxt.NewBbxtTools(m.config, lsxd.NewLogin(m.config, m.rdb))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
now := time.Now()
|
||||||
|
value, err := b.GetMapResellerLossSumProductRelation(ctx, now, m.GetReportCache)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//将value转为string
|
||||||
|
//**[供应商id]供应商名称->商务名称**\n
|
||||||
|
//└──商品名称:亏损原因\n
|
||||||
|
var valueString strings.Builder
|
||||||
|
valueString.WriteString("[负利润分析]更新:\n")
|
||||||
|
for k, v := range value {
|
||||||
|
if len(v.AfterSaleName) == 0 {
|
||||||
|
v.AfterSaleName = "未查找到对应商务"
|
||||||
|
}
|
||||||
|
valueString.WriteString(fmt.Sprintf("**[%d]%s->%s**\n", k, v.ResellerName, v.AfterSaleName))
|
||||||
|
for kk, vv := range v.Products {
|
||||||
|
valueString.WriteString(fmt.Sprintf("└── [%d]%s:%s\n", kk, vv.ProductName, vv.LossReason))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
successMsg = valueString.String()
|
||||||
|
isFinish = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) ProductModify(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||||
|
content = processString(content)
|
||||||
|
if parts := strings.SplitN(content, ":", 2); len(parts) == 2 {
|
||||||
|
itemInfo := strings.TrimSpace(parts[1])
|
||||||
|
log.Infof("商品修改信息: %s", itemInfo)
|
||||||
|
groupConfig.ProductName = itemInfo
|
||||||
|
cond := builder.NewCond()
|
||||||
|
cond = cond.And(builder.Eq{"config_id": groupConfig.ConfigID})
|
||||||
|
err = m.botGroupImpl.UpdateByCond(&cond, groupConfig)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("修改失败:%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
successMsg = "修改成功"
|
||||||
|
isFinish = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) ProductList(ctx context.Context, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
|
||||||
|
if len(groupConfig.ProductName) == 0 {
|
||||||
|
successMsg = "暂未设置"
|
||||||
|
} else {
|
||||||
|
successMsg = groupConfig.ProductName
|
||||||
|
isFinish = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func processString(s string) string {
|
||||||
|
// 替换中文逗号为英文逗号
|
||||||
|
s = strings.ReplaceAll(s, ",", ",")
|
||||||
|
|
||||||
|
return string(clearSpacialFormat(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearSpacialFormat(s string) (result []rune) {
|
||||||
|
//过滤控制字符(如 \n, \t, \r 等)
|
||||||
|
for _, char := range s {
|
||||||
|
// 判断是否是控制字符(ASCII < 32 或 = 127)
|
||||||
|
if !unicode.IsControl(char) {
|
||||||
|
// 如果需要完全移除 \n 和 \t,可以改成:
|
||||||
|
// if !unicode.IsControl(char)
|
||||||
|
result = append(result, char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseLossData(input string) (map[int32]*bbxt.ResellerLossSumProductRelation, error) {
|
||||||
|
result := make(map[int32]*bbxt.ResellerLossSumProductRelation)
|
||||||
|
|
||||||
|
// 按行分割
|
||||||
|
lines := strings.Split(input, "\n")
|
||||||
|
|
||||||
|
// 跳过第一行的标题
|
||||||
|
startIdx := 0
|
||||||
|
for i, line := range lines {
|
||||||
|
if strings.HasPrefix(line, "[") && strings.Contains(line, "]") && strings.Contains(line, "->") {
|
||||||
|
startIdx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentResellerID int32
|
||||||
|
var currentReseller *bbxt.ResellerLossSumProductRelation
|
||||||
|
|
||||||
|
for i := startIdx; i < len(lines); i++ {
|
||||||
|
line := strings.TrimSpace(lines[i])
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是供应商行(以 [ 开头)
|
||||||
|
if strings.HasPrefix(line, "[") && strings.Contains(line, "]") {
|
||||||
|
// 解析供应商行:[25131]兴业银行-营销系统->未查找到对应商务
|
||||||
|
|
||||||
|
// 找到第一个 ] 的位置
|
||||||
|
bracketEnd := strings.Index(line, "]")
|
||||||
|
if bracketEnd == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取供应商ID
|
||||||
|
idStr := line[1:bracketEnd]
|
||||||
|
id, err := strconv.ParseInt(idStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
currentResellerID = int32(id)
|
||||||
|
|
||||||
|
// 提取供应商名称和商务名称
|
||||||
|
remaining := strings.TrimSpace(line[bracketEnd+1:])
|
||||||
|
|
||||||
|
// 分割供应商名称和商务名称
|
||||||
|
var resellerName, afterSaleName string
|
||||||
|
arrowIdx := strings.Index(remaining, "->")
|
||||||
|
if arrowIdx != -1 {
|
||||||
|
resellerName = strings.TrimSpace(remaining[:arrowIdx])
|
||||||
|
afterSaleName = strings.TrimSpace(remaining[arrowIdx+2:])
|
||||||
|
} else {
|
||||||
|
resellerName = remaining
|
||||||
|
afterSaleName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的供应商对象
|
||||||
|
currentReseller = &bbxt.ResellerLossSumProductRelation{
|
||||||
|
AfterSaleName: afterSaleName,
|
||||||
|
ResellerName: resellerName,
|
||||||
|
Products: make(map[int32]*bbxt.LossReason),
|
||||||
|
}
|
||||||
|
|
||||||
|
result[currentResellerID] = currentReseller
|
||||||
|
|
||||||
|
} else if strings.Contains(line, "└──") {
|
||||||
|
// 解析商品行:└── [460]全国话费30元:未填写
|
||||||
|
if currentReseller == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除└──前缀
|
||||||
|
productLine := strings.TrimPrefix(line, "└──")
|
||||||
|
productLine = strings.TrimSpace(productLine)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(productLine, "[") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到商品ID的结束位置
|
||||||
|
prodBracketEnd := strings.Index(productLine, "]")
|
||||||
|
if prodBracketEnd == -1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取商品ID
|
||||||
|
prodIDStr := productLine[1:prodBracketEnd]
|
||||||
|
prodID, err := strconv.ParseInt(prodIDStr, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取商品名称和亏损原因
|
||||||
|
prodRemaining := strings.TrimSpace(productLine[prodBracketEnd+1:])
|
||||||
|
|
||||||
|
// 找到冒号分隔符
|
||||||
|
colonIdx := strings.Index(prodRemaining, ":")
|
||||||
|
var productName, lossReason string
|
||||||
|
|
||||||
|
if colonIdx != -1 {
|
||||||
|
productName = strings.TrimSpace(prodRemaining[:colonIdx])
|
||||||
|
lossReason = strings.TrimSpace(prodRemaining[colonIdx+1:])
|
||||||
|
} else {
|
||||||
|
productName = prodRemaining
|
||||||
|
lossReason = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到当前供应商的商品列表中
|
||||||
|
currentReseller.Products[int32(prodID)] = &bbxt.LossReason{
|
||||||
|
ProductName: productName,
|
||||||
|
LossReason: lossReason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Macro) GetReportCache(ctx context.Context, day time.Time, totalDetail []*bbxt.ResellerLoss, bbxtObj *bbxt.BbxtTools) error {
|
||||||
|
dayDate := day.Format(time.DateOnly)
|
||||||
|
|
||||||
|
// 1. 从 API 获取数据并填充
|
||||||
|
apiRelations, err := bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get API data failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 API 数据填充损失原因
|
||||||
|
fillLossReasonFromData(totalDetail, apiRelations, "未填写")
|
||||||
|
|
||||||
|
// 2. 从缓存获取数据并覆盖
|
||||||
|
cachedRelations, err := m.getCachedRelations(dayDate)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get cache data failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用缓存数据覆盖损失原因
|
||||||
|
if cachedRelations != nil {
|
||||||
|
fillLossReasonFromData(totalDetail, cachedRelations, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从缓存获取关系数据
|
||||||
|
func (m *Macro) getCachedRelations(dayDate string) (map[int32]*bbxt.ResellerLossSumProductRelation, error) {
|
||||||
|
cond := builder.NewCond().
|
||||||
|
And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail}).
|
||||||
|
And(builder.Eq{"cache_key": dayDate}).
|
||||||
|
And(builder.Eq{"status": 1})
|
||||||
|
|
||||||
|
var cache model.AiReportDailyCache
|
||||||
|
err := m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
// 缓存不存在是正常情况
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("query cache failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cache.ID == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var relations map[int32]*bbxt.ResellerLossSumProductRelation
|
||||||
|
if err := json.Unmarshal([]byte(cache.Value), &relations); err != nil {
|
||||||
|
return nil, fmt.Errorf("unmarshal cache failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return relations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用指定数据源填充损失原因
|
||||||
|
func fillLossReasonFromData(
|
||||||
|
totalDetail []*bbxt.ResellerLoss,
|
||||||
|
relations map[int32]*bbxt.ResellerLossSumProductRelation,
|
||||||
|
defaultReason string, // 当数据不存在时使用的默认值
|
||||||
|
) {
|
||||||
|
for _, detail := range totalDetail {
|
||||||
|
resellerRelation, exists := relations[detail.ResellerId]
|
||||||
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置售后经理(只有在有值时才设置)
|
||||||
|
if resellerRelation.AfterSaleName != "" {
|
||||||
|
detail.Manager = resellerRelation.AfterSaleName
|
||||||
|
}
|
||||||
|
|
||||||
|
// 为每个产品设置损失原因
|
||||||
|
for _, product := range detail.ProductLoss {
|
||||||
|
setProductLossReason(product, resellerRelation, defaultReason)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置单个产品的损失原因
|
||||||
|
func setProductLossReason(
|
||||||
|
product *bbxt.ProductLoss,
|
||||||
|
resellerRelation *bbxt.ResellerLossSumProductRelation,
|
||||||
|
defaultReason string,
|
||||||
|
) {
|
||||||
|
// 如果该经销商没有产品数据,跳过
|
||||||
|
if resellerRelation.Products == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
productRelation, exists := resellerRelation.Products[product.ProductId]
|
||||||
|
if !exists {
|
||||||
|
if defaultReason != "" {
|
||||||
|
product.LossReason = defaultReason
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有损失原因则设置,否则使用默认值
|
||||||
|
if productRelation.LossReason != "" {
|
||||||
|
product.LossReason = productRelation.LossReason
|
||||||
|
} else if defaultReason != "" {
|
||||||
|
product.LossReason = defaultReason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -166,6 +166,7 @@ func (f *WithDingTalkBot) getUserContent(ctx context.Context, rec *entitys.Recog
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rec.ChatHis.Messages) > 0 {
|
if len(rec.ChatHis.Messages) > 0 {
|
||||||
|
content.WriteString("\n")
|
||||||
content.WriteString("### 引用历史聊天记录:\n")
|
content.WriteString("### 引用历史聊天记录:\n")
|
||||||
content.WriteString(pkg.JsonStringIgonErr(rec.ChatHis))
|
content.WriteString(pkg.JsonStringIgonErr(rec.ChatHis))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package biz
|
package biz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"ai_scheduler/internal/biz/do"
|
||||||
"ai_scheduler/internal/biz/tools_regis"
|
"ai_scheduler/internal/biz/tools_regis"
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
"ai_scheduler/internal/data/constants"
|
"ai_scheduler/internal/data/constants"
|
||||||
|
|
@ -9,7 +10,6 @@ import (
|
||||||
"ai_scheduler/internal/domain/workflow/recharge"
|
"ai_scheduler/internal/domain/workflow/recharge"
|
||||||
"ai_scheduler/internal/domain/workflow/runtime"
|
"ai_scheduler/internal/domain/workflow/runtime"
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
"ai_scheduler/internal/pkg"
|
|
||||||
"ai_scheduler/internal/pkg/l_request"
|
"ai_scheduler/internal/pkg/l_request"
|
||||||
"ai_scheduler/internal/pkg/lsxd"
|
"ai_scheduler/internal/pkg/lsxd"
|
||||||
"ai_scheduler/internal/pkg/utils_oss"
|
"ai_scheduler/internal/pkg/utils_oss"
|
||||||
|
|
@ -17,7 +17,6 @@ import (
|
||||||
"ai_scheduler/internal/tools/bbxt"
|
"ai_scheduler/internal/tools/bbxt"
|
||||||
"ai_scheduler/utils"
|
"ai_scheduler/utils"
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -42,6 +41,8 @@ type GroupConfigBiz struct {
|
||||||
toolManager *tools.Manager
|
toolManager *tools.Manager
|
||||||
conf *config.Config
|
conf *config.Config
|
||||||
rdb *utils.Rdb
|
rdb *utils.Rdb
|
||||||
|
macro *do.Macro
|
||||||
|
handle *do.Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDingTalkBotBiz
|
// NewDingTalkBotBiz
|
||||||
|
|
@ -53,6 +54,9 @@ func NewGroupConfigBiz(
|
||||||
conf *config.Config,
|
conf *config.Config,
|
||||||
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
|
||||||
rdb *utils.Rdb,
|
rdb *utils.Rdb,
|
||||||
|
macro *do.Macro,
|
||||||
|
toolManager *tools.Manager,
|
||||||
|
handle *do.Handle,
|
||||||
) *GroupConfigBiz {
|
) *GroupConfigBiz {
|
||||||
return &GroupConfigBiz{
|
return &GroupConfigBiz{
|
||||||
botTools: tools.BootTools,
|
botTools: tools.BootTools,
|
||||||
|
|
@ -62,6 +66,9 @@ func NewGroupConfigBiz(
|
||||||
conf: conf,
|
conf: conf,
|
||||||
reportDailyCacheImpl: reportDailyCacheImpl,
|
reportDailyCacheImpl: reportDailyCacheImpl,
|
||||||
rdb: rdb,
|
rdb: rdb,
|
||||||
|
macro: macro,
|
||||||
|
toolManager: toolManager,
|
||||||
|
handle: handle,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,7 +94,7 @@ func (g *GroupConfigBiz) GetReportLists(ctx context.Context, groupConfig *model.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
reports, err = reportList.DailyReport(ctx, time.Now(), bbxt.DownWardValue, product, bbxt.SumFilter, g.ossClient, g.GetReportCache)
|
reports, err = reportList.DailyReport(ctx, time.Now(), bbxt.DownWardValue, product, bbxt.SumFilter, g.ossClient, g.macro.GetReportCache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +171,7 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
|
||||||
var reports []*bbxt.ReportRes
|
var reports []*bbxt.ReportRes
|
||||||
switch rec.Match.Index {
|
switch rec.Match.Index {
|
||||||
case "report_loss_analysis":
|
case "report_loss_analysis":
|
||||||
repo, _err := rep.StatisOursProductLossSum(ctx, t, g.GetReportCache)
|
repo, _err := rep.StatisOursProductLossSum(ctx, t, g.macro.GetReportCache)
|
||||||
if _err != nil {
|
if _err != nil {
|
||||||
return _err
|
return _err
|
||||||
}
|
}
|
||||||
|
|
@ -185,15 +192,15 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
|
||||||
reports = append(reports, repo)
|
reports = append(reports, repo)
|
||||||
case "report_daily":
|
case "report_daily":
|
||||||
product := strings.Split(groupConfig.ProductName, ",")
|
product := strings.Split(groupConfig.ProductName, ",")
|
||||||
repo, _err := rep.DailyReport(ctx, t, bbxt.DownWardValue, product, bbxt.SumFilter, nil, g.GetReportCache)
|
repo, _err := rep.DailyReport(ctx, t, bbxt.DownWardValue, product, bbxt.SumFilter, nil, g.macro.GetReportCache)
|
||||||
|
if _err != nil {
|
||||||
|
return _err
|
||||||
|
}
|
||||||
|
rechargeReport, _err := g.rechargeDailyReport(ctx, t, product, nil)
|
||||||
if _err != nil {
|
if _err != nil {
|
||||||
return _err
|
return _err
|
||||||
}
|
}
|
||||||
reports = append(reports, repo...)
|
reports = append(reports, repo...)
|
||||||
rechargeReport, _err := g.rechargeDailyReport(ctx, t, product, nil)
|
|
||||||
if _err != nil || len(repo) == 0 {
|
|
||||||
return _err
|
|
||||||
}
|
|
||||||
reports = append(reports, rechargeReport...)
|
reports = append(reports, rechargeReport...)
|
||||||
case "report_daily_recharge":
|
case "report_daily_recharge":
|
||||||
product := strings.Split(groupConfig.ProductName, ",")
|
product := strings.Split(groupConfig.ProductName, ",")
|
||||||
|
|
@ -224,7 +231,6 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
|
||||||
}
|
}
|
||||||
|
|
||||||
entitys.ResText(rec.Ch, "", fmt.Sprintf("%s", report.Title, report.Url))
|
entitys.ResText(rec.Ch, "", fmt.Sprintf("%s", report.Title, report.Url))
|
||||||
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -253,6 +259,11 @@ func (g *GroupConfigBiz) handleMatch(ctx context.Context, rec *entitys.Recognize
|
||||||
switch constants.TaskType(pointTask.Type) {
|
switch constants.TaskType(pointTask.Type) {
|
||||||
case constants.TaskTypeFunc:
|
case constants.TaskTypeFunc:
|
||||||
return g.handleTask(ctx, rec, pointTask)
|
return g.handleTask(ctx, rec, pointTask)
|
||||||
|
case constants.TaskTypeBot:
|
||||||
|
return g.handle.HandleBot(ctx, rec, &entitys.Task{
|
||||||
|
Index: pointTask.Index,
|
||||||
|
OutPutFormat: entitys.OutPutFormatMarkdown,
|
||||||
|
})
|
||||||
case constants.TaskTypeReport:
|
case constants.TaskTypeReport:
|
||||||
return g.handleReport(ctx, rec, pointTask, groupConfig)
|
return g.handleReport(ctx, rec, pointTask, groupConfig)
|
||||||
case constants.TaskTypeCozeWorkflow:
|
case constants.TaskTypeCozeWorkflow:
|
||||||
|
|
@ -302,7 +313,6 @@ func (q *GroupConfigBiz) handleTask(ctx context.Context, rec *entitys.Recognize,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = q.toolManager.ExecuteTool(ctx, configData.Tool, rec)
|
err = q.toolManager.ExecuteTool(ctx, configData.Tool, rec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -415,47 +425,3 @@ func (g *GroupConfigBiz) otherTask(ctx context.Context, rec *entitys.Recognize)
|
||||||
entitys.ResText(rec.Ch, "", rec.Match.Reasoning)
|
entitys.ResText(rec.Ch, "", rec.Match.Reasoning)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupConfigBiz) GetReportCache(ctx context.Context, day time.Time, totalDetail []*bbxt.ResellerLoss, bbxtObj *bbxt.BbxtTools) error {
|
|
||||||
var ResellerProductRelation map[int32]*bbxt.ResellerLossSumProductRelation
|
|
||||||
|
|
||||||
dayDate := day.Format(time.DateOnly)
|
|
||||||
cond := builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"index": bbxt.IndexLossSumDetail})
|
|
||||||
cond = cond.And(builder.Eq{"key": dayDate})
|
|
||||||
var cache model.AiReportDailyCache
|
|
||||||
err := g.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(sql.ErrNoRows, err) {
|
|
||||||
ResellerProductRelation, err = bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cache = model.AiReportDailyCache{
|
|
||||||
Key: dayDate,
|
|
||||||
Index: bbxt.IndexLossSumDetail,
|
|
||||||
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
|
|
||||||
}
|
|
||||||
_, err = g.reportDailyCacheImpl.Add(&cache)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = json.Unmarshal([]byte(cache.Value), &ResellerProductRelation)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, v := range totalDetail {
|
|
||||||
if _, ex := ResellerProductRelation[v.ResellerId]; !ex {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
v.Manager = ResellerProductRelation[v.ResellerId].AfterSaleName
|
|
||||||
for _, vv := range v.ProductLoss {
|
|
||||||
if _, ex := ResellerProductRelation[v.ResellerId].Products[vv.ProductId]; !ex {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
vv.LossReason = ResellerProductRelation[v.ResellerId].Products[vv.ProductId].LossReason
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const DefaultInterval = 100 * time.Millisecond
|
const DefaultInterval = 100 * time.Millisecond
|
||||||
const HeardBeatX = 50
|
const HeardBeatX = 100
|
||||||
|
|
||||||
type SendCardClient struct {
|
type SendCardClient struct {
|
||||||
Auth *Auth
|
Auth *Auth
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,5 @@ var ProviderSetBiz = wire.NewSet(
|
||||||
NewDingTalkBotBiz,
|
NewDingTalkBotBiz,
|
||||||
NewQywxAppBiz,
|
NewQywxAppBiz,
|
||||||
NewGroupConfigBiz,
|
NewGroupConfigBiz,
|
||||||
|
do.NewMacro,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ type Config struct {
|
||||||
LLM LLM `mapstructure:"llm"`
|
LLM LLM `mapstructure:"llm"`
|
||||||
Dingtalk DingtalkConfig `mapstructure:"dingtalk"`
|
Dingtalk DingtalkConfig `mapstructure:"dingtalk"`
|
||||||
Qywx QywxConfig `mapstructure:"qywx"`
|
Qywx QywxConfig `mapstructure:"qywx"`
|
||||||
ZLTX ZLTX `mapstructure:"zltx"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ZLTX struct {
|
type ZLTX struct {
|
||||||
|
|
@ -196,7 +195,8 @@ type ToolsConfig struct {
|
||||||
// Coze 快递查询工具
|
// Coze 快递查询工具
|
||||||
CozeExpress ToolConfig `mapstructure:"cozeExpress"`
|
CozeExpress ToolConfig `mapstructure:"cozeExpress"`
|
||||||
// Coze 公司查询工具
|
// Coze 公司查询工具
|
||||||
CozeCompany ToolConfig `mapstructure:"cozeCompany"`
|
CozeCompany ToolConfig `mapstructure:"cozeCompany"`
|
||||||
|
ZltxResellerAuthProductToManagerAndDefaultLossReason ToolConfig `mapstructure:"zltxResellerAuthProductToManagerAndDefaultLossReason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToolConfig 单个工具配置
|
// ToolConfig 单个工具配置
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@ const TableNameAiReportDailyCache = "ai_report_daily_cache"
|
||||||
|
|
||||||
// AiReportDailyCache mapped from table <ai_report_daily_cache>
|
// AiReportDailyCache mapped from table <ai_report_daily_cache>
|
||||||
type AiReportDailyCache struct {
|
type AiReportDailyCache struct {
|
||||||
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
|
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
|
||||||
Key string `gorm:"column:key;not null;default:1;comment:索引方式,可以是任意类型" json:"key"` // 索引方式,可以是任意类型
|
CacheKey string `gorm:"column:cache_key;not null;default:1;comment:索引方式,可以是任意类型" json:"cache_key"` // 索引方式,可以是任意类型
|
||||||
Value string `gorm:"column:value;comment:类型下所需路由以及参数" json:"value"` // 类型下所需路由以及参数
|
Value string `gorm:"column:value;comment:类型下所需路由以及参数" json:"value"` // 类型下所需路由以及参数
|
||||||
Index string `gorm:"column:index;not null;comment:类型" json:"index"` // 类型
|
CacheIndex string `gorm:"column:cache_index;not null;comment:类型" json:"cache_index"` // 类型
|
||||||
|
Status int32 `gorm:"column:status;not null;default:1" json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName AiReportDailyCache's table name
|
// TableName AiReportDailyCache's table name
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,13 @@ type DingTalkBot struct {
|
||||||
ClientId string `json:"client_id"`
|
ClientId string `json:"client_id"`
|
||||||
ClientSecret string `json:"client_secret"`
|
ClientSecret string `json:"client_secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Task struct {
|
||||||
|
Index string `json:"bot_index"`
|
||||||
|
OutPutFormat OutPutFormat `json:"out_put_format"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutPutFormat string
|
||||||
|
|
||||||
|
const OutPutFormatMarkdown OutPutFormat = "markdown"
|
||||||
|
const OutPutFormatHtml OutPutFormat = "html"
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ type TaskExt struct {
|
||||||
SessionInfo model.AiSession
|
SessionInfo model.AiSession
|
||||||
Sys model.AiSy
|
Sys model.AiSy
|
||||||
KnowledgeConf KnowledgeBaseRequest
|
KnowledgeConf KnowledgeBaseRequest
|
||||||
|
UserName string
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegistrationTask struct {
|
type RegistrationTask struct {
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,9 @@ type FunctionCall struct {
|
||||||
type ToolDefinition struct {
|
type ToolDefinition struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Function FunctionDef `json:"function"`
|
Function FunctionDef `json:"function"`
|
||||||
|
AuthFunc AuthFunc `json:"function"`
|
||||||
}
|
}
|
||||||
|
type AuthFunc func(rec *Recognize) (token []byte, err error)
|
||||||
|
|
||||||
// FunctionDef 函数定义
|
// FunctionDef 函数定义
|
||||||
type FunctionDef struct {
|
type FunctionDef struct {
|
||||||
|
|
@ -77,7 +79,7 @@ type FunctionDef struct {
|
||||||
type Tool interface {
|
type Tool interface {
|
||||||
Name() string
|
Name() string
|
||||||
Description() string
|
Description() string
|
||||||
Definition() ToolDefinition
|
Definition(ctx context.Context) ToolDefinition
|
||||||
Execute(ctx context.Context, requireData *Recognize) error
|
Execute(ctx context.Context, requireData *Recognize) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,8 @@ func (l *Login) cacheToken(ctx context.Context, token string) error {
|
||||||
if token == "" {
|
if token == "" {
|
||||||
return errors.New("token is empty")
|
return errors.New("token is empty")
|
||||||
}
|
}
|
||||||
return l.redisCli.Set(ctx, l.getCacheKey(), token, constants.EXPIRE_LSXD_TOKEN).Err()
|
key := l.getCacheKey()
|
||||||
|
return l.redisCli.Set(ctx, key, token, constants.EXPIRE_LSXD_TOKEN).Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) doRequest(ctx context.Context, method string, url string, authorization string, body []byte) (int, error) {
|
func (l *Login) doRequest(ctx context.Context, method string, url string, authorization string, body []byte) (int, error) {
|
||||||
|
|
@ -190,7 +191,7 @@ func (l *Login) doRequestWithBody(ctx context.Context, method string, url string
|
||||||
req.Header.Set("Content-Type", contentType)
|
req.Header.Set("Content-Type", contentType)
|
||||||
}
|
}
|
||||||
if authorization != "" {
|
if authorization != "" {
|
||||||
req.Header.Set("Authorization", authorization)
|
req.Header.Set("Authorization", "Bearer "+authorization)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := (&http.Client{}).Do(req)
|
resp, err := (&http.Client{}).Do(req)
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,8 @@ func run() {
|
||||||
group := qywx.NewGroup(botGroupQywxImpl, qywxAuth)
|
group := qywx.NewGroup(botGroupQywxImpl, qywxAuth)
|
||||||
other := qywx.NewOther(qywxAuth)
|
other := qywx.NewOther(qywxAuth)
|
||||||
qywxAppBiz := biz.NewQywxAppBiz(configConfig, botGroupQywxImpl, group, other)
|
qywxAppBiz := biz.NewQywxAppBiz(configConfig, botGroupQywxImpl, group, other)
|
||||||
groupConfigBiz := biz.NewGroupConfigBiz(toolRegis, utils_ossClient, botGroupConfigImpl, registry, configConfig)
|
groupConfigBiz := biz.NewGroupConfigBiz(toolRegis, utils_ossClient, botGroupConfigImpl, registry, configConfig, impl.NewReportDailyCacheImpl(db), rdb)
|
||||||
dingTalkBotBiz := biz.NewDingTalkBotBiz(doDo, handle, botConfigImpl, botGroupImpl, user, botChatHisImpl, manager, configConfig, sendCardClient, groupConfigBiz)
|
dingTalkBotBiz := biz.NewDingTalkBotBiz(doDo, handle, botConfigImpl, botGroupImpl, user, botChatHisImpl, impl.NewReportDailyCacheImpl(db), manager, configConfig, sendCardClient, groupConfigBiz)
|
||||||
// 初始化钉钉机器人服务
|
// 初始化钉钉机器人服务
|
||||||
cronService = NewCronService(configConfig, dingTalkBotBiz, qywxAppBiz, groupConfigBiz)
|
cronService = NewCronService(configConfig, dingTalkBotBiz, qywxAppBiz, groupConfigBiz)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ import (
|
||||||
"ai_scheduler/internal/pkg"
|
"ai_scheduler/internal/pkg"
|
||||||
"ai_scheduler/internal/pkg/l_request"
|
"ai_scheduler/internal/pkg/l_request"
|
||||||
"ai_scheduler/internal/pkg/util"
|
"ai_scheduler/internal/pkg/util"
|
||||||
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-kratos/kratos/v2/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StatisOursProductLossSumReq struct {
|
type StatisOursProductLossSumReq struct {
|
||||||
|
|
@ -195,48 +196,49 @@ type GetManagerAndDefaultLossReasonResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetManagerAndDefaultLossReasonResponseList struct {
|
type GetManagerAndDefaultLossReasonResponseList struct {
|
||||||
ResellerInfo *GetManagerAndDefaultLossReasonResponse_ResellerInfo `json:"GetManagerAndDefaultLossReasonResponse_ResellerInfo,omitempty"`
|
ResellerInfo *GetManagerAndDefaultLossReasonResponse_ResellerInfo `json:"resellerInfo,omitempty"`
|
||||||
ProductList []*GetManagerAndDefaultLossReasonResponse_ProductList `json:"GetManagerAndDefaultLossReasonResponse_ProductList,omitempty"`
|
ProductList []*GetManagerAndDefaultLossReasonResponse_ProductList `json:"productList,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetManagerAndDefaultLossReasonResponse_ResellerInfo struct {
|
type GetManagerAndDefaultLossReasonResponse_ResellerInfo struct {
|
||||||
ResellerId int32 `json:"reseller_id,omitempty"`
|
ResellerId int32 `json:"resellerId,omitempty"`
|
||||||
AfterSaleName string `json:"after_sale_name,omitempty"`
|
AfterSaleName string `json:"AfterSaleName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetManagerAndDefaultLossReasonResponse_ProductList struct {
|
type GetManagerAndDefaultLossReasonResponse_ProductList struct {
|
||||||
ProductId int32 `json:"product_id,omitempty"`
|
ProductId int32 `json:"productId,omitempty"`
|
||||||
LossReason string `json:"loss_reason,omitempty"`
|
LossReason string `json:"lossReason,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//return []*GetManagerAndDefaultLossReasonResponseList{
|
||||||
|
//{
|
||||||
|
//ResellerInfo: &GetManagerAndDefaultLossReasonResponse_ResellerInfo{
|
||||||
|
//ResellerId: 25009,
|
||||||
|
//AfterSaleName: "张三",
|
||||||
|
//},
|
||||||
|
//ProductList: []*GetManagerAndDefaultLossReasonResponse_ProductList{
|
||||||
|
//{
|
||||||
|
//ProductId: 129,
|
||||||
|
//LossReason: "小米钱包h5-QQ音乐绿钻季卡原因",
|
||||||
|
//},
|
||||||
|
//{
|
||||||
|
//ProductId: 2218,
|
||||||
|
//LossReason: "小米钱包h5-百度网盘新vip会员月卡原因",
|
||||||
|
//},
|
||||||
|
//{
|
||||||
|
//ProductId: 3226,
|
||||||
|
//LossReason: "小米钱包h5-腾讯视频月卡-小米钱包2024原因",
|
||||||
|
//},
|
||||||
|
//{
|
||||||
|
//ProductId: 3364,
|
||||||
|
//LossReason: "小米钱包h5-腾讯视频月卡-0元直充原因",
|
||||||
|
//},
|
||||||
|
//},
|
||||||
|
//},
|
||||||
|
//}, nil
|
||||||
|
|
||||||
// GetStatisFilterOfficialProductApi 官方商品列表
|
// GetStatisFilterOfficialProductApi 官方商品列表
|
||||||
func GetManagerAndDefaultLossReasonApi(param *GetManagerAndDefaultLossReasonRequest, token string, reqUrl string) ([]*GetManagerAndDefaultLossReasonResponseList, error) {
|
func GetManagerAndDefaultLossReasonApi(param *GetManagerAndDefaultLossReasonRequest, token string, reqUrl string) ([]*GetManagerAndDefaultLossReasonResponseList, error) {
|
||||||
return []*GetManagerAndDefaultLossReasonResponseList{
|
|
||||||
{
|
|
||||||
ResellerInfo: &GetManagerAndDefaultLossReasonResponse_ResellerInfo{
|
|
||||||
ResellerId: 25009,
|
|
||||||
AfterSaleName: "张三",
|
|
||||||
},
|
|
||||||
ProductList: []*GetManagerAndDefaultLossReasonResponse_ProductList{
|
|
||||||
{
|
|
||||||
ProductId: 129,
|
|
||||||
LossReason: "小米钱包h5-QQ音乐绿钻季卡原因",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ProductId: 2218,
|
|
||||||
LossReason: "小米钱包h5-百度网盘新vip会员月卡原因",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ProductId: 3226,
|
|
||||||
LossReason: "小米钱包h5-腾讯视频月卡-小米钱包2024原因",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ProductId: 3364,
|
|
||||||
LossReason: "小米钱包h5-腾讯视频月卡-0元直充原因",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
reqParam, err := util.StructToMap(param)
|
reqParam, err := util.StructToMap(param)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -244,17 +246,20 @@ func GetManagerAndDefaultLossReasonApi(param *GetManagerAndDefaultLossReasonRequ
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &l_request.Request{
|
req := &l_request.Request{
|
||||||
Url: reqUrl + "/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason",
|
Url: reqUrl,
|
||||||
Method: http.MethodPost,
|
Method: http.MethodPost,
|
||||||
Json: reqParam,
|
Json: reqParam,
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
"Authorization": fmt.Sprintf("Bearer %s", token),
|
"Authorization": fmt.Sprintf("Bearer %s", token),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
log.Debug(pkg.JsonStringIgonErr(req.Headers))
|
||||||
res, err := req.Send()
|
res, err := req.Send()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Debug(err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
log.Debug(string(res.Content))
|
||||||
if res.StatusCode != http.StatusOK {
|
if res.StatusCode != http.StatusOK {
|
||||||
return nil, fmt.Errorf("request failed, status code: %d,resion: %s", res.StatusCode, res.Reason)
|
return nil, fmt.Errorf("request failed, status code: %d,resion: %s", res.StatusCode, res.Reason)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ var (
|
||||||
SumFilter int32 = -150
|
SumFilter int32 = -150
|
||||||
)
|
)
|
||||||
|
|
||||||
var resellerBlackListProduct = []string{
|
var ResellerBlackListProduct = []string{
|
||||||
"悦跑",
|
"悦跑",
|
||||||
"电商-独立",
|
"电商-独立",
|
||||||
"蓝星严选连续包月",
|
"蓝星严选连续包月",
|
||||||
|
|
@ -103,9 +103,7 @@ func (b *BbxtTools) DailyReport(
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (b *BbxtTools) ResellerLossSort(ctx context.Context, now time.Time) ([]*ResellerLoss, error) {
|
||||||
// StatisOursProductLossSum 负利润分析
|
|
||||||
func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report []*ReportRes, err error) {
|
|
||||||
ct := []string{
|
ct := []string{
|
||||||
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
|
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
|
||||||
adjustedTime(now), //adjustedTime(time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())),
|
adjustedTime(now), //adjustedTime(time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())),
|
||||||
|
|
@ -115,13 +113,10 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
Ct: ct,
|
Ct: ct,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
resellerMap = make(map[int32]*ResellerLoss)
|
resellerMap = make(map[int32]*ResellerLoss)
|
||||||
total [][]string
|
|
||||||
gt []*ResellerLoss
|
|
||||||
totalDetail []*ResellerLoss
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, info := range data.List {
|
for _, info := range data.List {
|
||||||
|
|
@ -166,14 +161,66 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
sort.Slice(resellers, func(i, j int) bool {
|
sort.Slice(resellers, func(i, j int) bool {
|
||||||
return resellers[i].Total < resellers[j].Total
|
return resellers[i].Total < resellers[j].Total
|
||||||
})
|
})
|
||||||
var (
|
return resellers, nil
|
||||||
totalSum float64
|
}
|
||||||
|
|
||||||
|
func (b *BbxtTools) GetMapResellerLossSumProductRelation(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (map[int32]*ResellerLossSumProductRelation, error) {
|
||||||
|
resellers, err := b.ResellerLossSort(ctx, now)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var totalDetail []*ResellerLoss
|
||||||
|
for _, v := range resellers {
|
||||||
|
if v.Total <= -100 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||||
|
|
||||||
|
totalDetail = append(totalDetail, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if len(totalDetail) > 0 {
|
||||||
|
err = initFunc(ctx, now, totalDetail, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value := b.ResellerLossToMapResellerLossSumProductRelation(totalDetail)
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BbxtTools) ResellerLossToMapResellerLossSumProductRelation(totalDetail []*ResellerLoss) map[int32]*ResellerLossSumProductRelation {
|
||||||
|
relations := make(map[int32]*ResellerLossSumProductRelation)
|
||||||
|
for _, detail := range totalDetail {
|
||||||
|
if _, ok := relations[detail.ResellerId]; !ok {
|
||||||
|
relations[detail.ResellerId] = &ResellerLossSumProductRelation{
|
||||||
|
ResellerName: detail.ResellerName,
|
||||||
|
AfterSaleName: detail.Manager,
|
||||||
|
Products: make(map[int32]*LossReason),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, product := range detail.ProductLoss {
|
||||||
|
relations[detail.ResellerId].Products[product.ProductId] = &LossReason{
|
||||||
|
ProductName: product.ProductName,
|
||||||
|
LossReason: product.LossReason,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return relations
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatisOursProductLossSum 负利润分析
|
||||||
|
func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report []*ReportRes, err error) {
|
||||||
|
resellers, err := b.ResellerLossSort(ctx, now)
|
||||||
|
var (
|
||||||
|
total [][]string
|
||||||
|
gt []*ResellerLoss
|
||||||
|
totalDetail []*ResellerLoss
|
||||||
|
totalSum float64
|
||||||
totalSum500 float64
|
totalSum500 float64
|
||||||
)
|
)
|
||||||
// 构建分组
|
// 构建分组
|
||||||
for _, v := range resellers {
|
for _, v := range resellers {
|
||||||
if v.Total <= -100 && !slices.Contains(resellerBlackListProduct, v.ResellerName) {
|
if v.Total <= -100 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||||
total = append(total, []string{
|
total = append(total, []string{
|
||||||
fmt.Sprintf("%s", v.ResellerName),
|
fmt.Sprintf("%s", v.ResellerName),
|
||||||
fmt.Sprintf("%.2f", v.Total),
|
fmt.Sprintf("%.2f", v.Total),
|
||||||
|
|
@ -181,7 +228,7 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
totalSum += v.Total
|
totalSum += v.Total
|
||||||
totalDetail = append(totalDetail, v)
|
totalDetail = append(totalDetail, v)
|
||||||
}
|
}
|
||||||
if v.Total <= -500 && !slices.Contains(resellerBlackListProduct, v.ResellerName) {
|
if v.Total <= -500 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) {
|
||||||
gt = append(gt, v)
|
gt = append(gt, v)
|
||||||
totalSum500 += v.Total
|
totalSum500 += v.Total
|
||||||
}
|
}
|
||||||
|
|
@ -218,24 +265,24 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if len(totalDetail) > 0 {
|
if len(totalDetail) > 0 {
|
||||||
// err = initFunc(ctx, now, totalDetail, b)
|
err = initFunc(ctx, now, totalDetail, b)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// filePath := b.cacheDir + "/kshj_total_ana" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
|
filePath := b.cacheDir + "/kshj_total_ana" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
|
||||||
// title := "截至" + timeCh + "亏损100以上的分销商&产品负利润原因"
|
title := "截至" + timeCh + "亏损100以上的分销商&产品负利润原因"
|
||||||
// err = b.resellerDetailFillExcelAna(b.excelTempDir+"/"+"kshj_total_ana.xlsx", filePath, totalDetail, title)
|
err = b.resellerDetailFillExcelAna(b.excelTempDir+"/"+"kshj_total_ana.xlsx", filePath, totalDetail, title)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// report[2] = &ReportRes{
|
report[2] = &ReportRes{
|
||||||
// ReportName: "负利润分析(亏损100以上)",
|
ReportName: "负利润分析(亏损100以上)",
|
||||||
// Title: "截至" + timeCh + "亏损100以上利润原因",
|
Title: "截至" + timeCh + "亏损100以上利润原因",
|
||||||
// Path: filePath,
|
Path: filePath,
|
||||||
// Data: total,
|
Data: total,
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
return report, nil
|
return report, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,13 +310,13 @@ func (b *BbxtTools) GetResellerLossMannagerAndLossReasonFromApi(ctx context.Cont
|
||||||
for _, product := range v.ProductLoss {
|
for _, product := range v.ProductLoss {
|
||||||
relationMap[v.ResellerId].Products[product.ProductId] = &LossReason{
|
relationMap[v.ResellerId].Products[product.ProductId] = &LossReason{
|
||||||
ProductName: product.ProductName,
|
ProductName: product.ProductName,
|
||||||
LossReason: "未填写", // 初始化为未填写
|
LossReason: "", // 初始化为未填写
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res, err := GetManagerAndDefaultLossReasonApi(&GetManagerAndDefaultLossReasonRequest{
|
res, err := GetManagerAndDefaultLossReasonApi(&GetManagerAndDefaultLossReasonRequest{
|
||||||
Param: resellerMap,
|
Param: resellerMap,
|
||||||
}, b.login.GetToken(ctx), b.config.ZLTX.ReqUrl)
|
}, b.login.GetToken(ctx), b.config.Tools.ZltxResellerAuthProductToManagerAndDefaultLossReason.BaseURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -283,6 +330,12 @@ func (b *BbxtTools) GetResellerLossMannagerAndLossReasonFromApi(ctx context.Cont
|
||||||
relationMap[v.ResellerInfo.ResellerId].AfterSaleName = v.ResellerInfo.AfterSaleName
|
relationMap[v.ResellerInfo.ResellerId].AfterSaleName = v.ResellerInfo.AfterSaleName
|
||||||
|
|
||||||
for _, vv := range v.ProductList {
|
for _, vv := range v.ProductList {
|
||||||
|
if _, ex := relationMap[v.ResellerInfo.ResellerId].Products[vv.ProductId]; !ex {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(vv.LossReason) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
relationMap[v.ResellerInfo.ResellerId].Products[vv.ProductId].LossReason = vv.LossReason
|
relationMap[v.ResellerInfo.ResellerId].Products[vv.ProductId].LossReason = vv.LossReason
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,7 @@ func Test_GetStatisOfficialProductSumDecline(t *testing.T) {
|
||||||
}
|
}
|
||||||
s := "官方--腾讯-周卡,官方--腾讯-月卡,官方--腾讯-季卡,官方--腾讯-年卡,官方--优酷周卡,官方--优酷月卡,官方--优酷季卡,官方--优酷年卡,官方--爱奇艺-周卡,官方--爱奇艺-月卡,官方--爱奇艺-季卡,官方--爱奇艺-年卡,官方--芒果-PC周卡,官方--芒果-PC月卡,官方--芒果-PC季卡,官方--美团外卖红包5元,官方--美团外卖红包10元,官方--QQ音乐-绿钻月卡,官方--饿了么超级会员月卡,官方--网易云黑胶vip月卡,官方--喜马拉雅巅峰会员月卡"
|
s := "官方--腾讯-周卡,官方--腾讯-月卡,官方--腾讯-季卡,官方--腾讯-年卡,官方--优酷周卡,官方--优酷月卡,官方--优酷季卡,官方--优酷年卡,官方--爱奇艺-周卡,官方--爱奇艺-月卡,官方--爱奇艺-季卡,官方--爱奇艺-年卡,官方--芒果-PC周卡,官方--芒果-PC月卡,官方--芒果-PC季卡,官方--美团外卖红包5元,官方--美团外卖红包10元,官方--QQ音乐-绿钻月卡,官方--饿了么超级会员月卡,官方--网易云黑胶vip月卡,官方--喜马拉雅巅峰会员月卡"
|
||||||
//s := "官方--QQ音乐-绿钻月卡"
|
//s := "官方--QQ音乐-绿钻月卡"
|
||||||
now := time.Now()
|
report, err := o.GetStatisOfficialProductSumDecline(time.Now(), 1000, strings.Split(s, ","), -150)
|
||||||
report, err := o.GetStatisOfficialProductSumDecline(time.Date(now.Year(), now.Month(), now.Day(), 12, 0, 0, 0, now.Location()), 1000, strings.Split(s, ","), -150)
|
|
||||||
|
|
||||||
t.Log(report, err)
|
t.Log(report, err)
|
||||||
|
|
||||||
|
|
@ -111,8 +110,8 @@ func GetReportCache(ctx context.Context, day time.Time, totalDetail []*ResellerL
|
||||||
var ResellerProductRelation map[int32]*ResellerLossSumProductRelation
|
var ResellerProductRelation map[int32]*ResellerLossSumProductRelation
|
||||||
dayDate := day.Format(time.DateOnly)
|
dayDate := day.Format(time.DateOnly)
|
||||||
cond := builder.NewCond()
|
cond := builder.NewCond()
|
||||||
cond = cond.And(builder.Eq{"`index`": IndexLossSumDetail})
|
cond = cond.And(builder.Eq{"cache_index": IndexLossSumDetail})
|
||||||
cond = cond.And(builder.Eq{"`key`": dayDate})
|
cond = cond.And(builder.Eq{"cache_key": dayDate})
|
||||||
var cache model.AiReportDailyCache
|
var cache model.AiReportDailyCache
|
||||||
|
|
||||||
err := reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
err := reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
|
||||||
|
|
@ -125,9 +124,9 @@ func GetReportCache(ctx context.Context, day time.Time, totalDetail []*ResellerL
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cache = model.AiReportDailyCache{
|
cache = model.AiReportDailyCache{
|
||||||
Key: dayDate,
|
CacheKey: dayDate,
|
||||||
Index: IndexLossSumDetail,
|
CacheIndex: IndexLossSumDetail,
|
||||||
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
|
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
|
||||||
}
|
}
|
||||||
_, err = reportDailyCacheImpl.Add(&cache)
|
_, err = reportDailyCacheImpl.Add(&cache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"ai_scheduler/internal/pkg/utils_ollama"
|
"ai_scheduler/internal/pkg/utils_ollama"
|
||||||
"ai_scheduler/internal/tools/public"
|
"ai_scheduler/internal/tools/public"
|
||||||
zltxtool "ai_scheduler/internal/tools/zltx"
|
zltxtool "ai_scheduler/internal/tools/zltx"
|
||||||
|
"ai_scheduler/utils"
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -15,10 +16,11 @@ import (
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
tools map[string]entitys.Tool
|
tools map[string]entitys.Tool
|
||||||
llm *utils_ollama.Client
|
llm *utils_ollama.Client
|
||||||
|
rdb *utils.Rdb
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager 创建工具管理器
|
// NewManager 创建工具管理器
|
||||||
func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
func NewManager(config *config.Config, llm *utils_ollama.Client, rdb *utils.Rdb) *Manager {
|
||||||
m := &Manager{
|
m := &Manager{
|
||||||
tools: make(map[string]entitys.Tool),
|
tools: make(map[string]entitys.Tool),
|
||||||
llm: llm,
|
llm: llm,
|
||||||
|
|
@ -26,7 +28,7 @@ func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
||||||
|
|
||||||
// 注册直连天下订单详情工具
|
// 注册直连天下订单详情工具
|
||||||
if config.Tools.ZltxOrderDetail.Enabled {
|
if config.Tools.ZltxOrderDetail.Enabled {
|
||||||
zltxOrderDetailTool := zltxtool.NewZltxOrderDetailTool(config.Tools.ZltxOrderDetail, m.llm)
|
zltxOrderDetailTool := zltxtool.NewZltxOrderDetailTool(config, rdb, m.llm)
|
||||||
m.tools[zltxOrderDetailTool.Name()] = zltxOrderDetailTool
|
m.tools[zltxOrderDetailTool.Name()] = zltxOrderDetailTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,7 +45,7 @@ func NewManager(config *config.Config, llm *utils_ollama.Client) *Manager {
|
||||||
}
|
}
|
||||||
//注册直连天下订单统计工具
|
//注册直连天下订单统计工具
|
||||||
if config.Tools.ZltxOrderStatistics.Enabled {
|
if config.Tools.ZltxOrderStatistics.Enabled {
|
||||||
zltxOrderStatisticsTool := zltxtool.NewZltxOrderStatisticsTool(config.Tools.ZltxOrderStatistics)
|
zltxOrderStatisticsTool := zltxtool.NewZltxOrderStatisticsTool(config, rdb)
|
||||||
m.tools[zltxOrderStatisticsTool.Name()] = zltxOrderStatisticsTool
|
m.tools[zltxOrderStatisticsTool.Name()] = zltxOrderStatisticsTool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,5 +106,10 @@ func (m *Manager) ExecuteTool(ctx context.Context, name string, rec *entitys.Rec
|
||||||
return fmt.Errorf("tool not found: %s", name)
|
return fmt.Errorf("tool not found: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m.ExecuteToolWithToolObj(ctx, tool, rec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecuteTool 执行工具
|
||||||
|
func (m *Manager) ExecuteToolWithToolObj(ctx context.Context, tool entitys.Tool, rec *entitys.Recognize) error {
|
||||||
return tool.Execute(ctx, rec)
|
return tool.Execute(ctx, rec)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ func (c *CozeCompany) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definition 返回工具定义
|
// Definition 返回工具定义
|
||||||
func (c *CozeCompany) Definition() entitys.ToolDefinition {
|
func (c *CozeCompany) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ func (c *CozeExpress) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definition 返回工具定义
|
// Definition 返回工具定义
|
||||||
func (c *CozeExpress) Definition() entitys.ToolDefinition {
|
func (c *CozeExpress) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ func (k *KnowledgeBaseTool) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definition 返回工具定义
|
// Definition 返回工具定义
|
||||||
func (k *KnowledgeBaseTool) Definition() entitys.ToolDefinition {
|
func (k *KnowledgeBaseTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ type NormalChat struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definition 返回工具定义
|
// Definition 返回工具定义
|
||||||
func (w *NormalChatTool) Definition() entitys.ToolDefinition {
|
func (w *NormalChatTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{}
|
return entitys.ToolDefinition{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func (w *WeatherTool) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definition 返回工具定义
|
// Definition 返回工具定义
|
||||||
func (w *WeatherTool) Definition() entitys.ToolDefinition {
|
func (w *WeatherTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func (t *OrderAfterSaleResellerTool) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未使用-仅实现接口
|
// 未使用-仅实现接口
|
||||||
func (t *OrderAfterSaleResellerTool) Definition() entitys.ToolDefinition {
|
func (t *OrderAfterSaleResellerTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{}
|
return entitys.ToolDefinition{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ func (t *OrderAfterSaleResellerBatchTool) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未使用-仅实现接口
|
// 未使用-仅实现接口
|
||||||
func (t *OrderAfterSaleResellerBatchTool) Definition() entitys.ToolDefinition {
|
func (t *OrderAfterSaleResellerBatchTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{}
|
return entitys.ToolDefinition{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func (t *OrderAfterSaleSupplierTool) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未使用-仅实现接口
|
// 未使用-仅实现接口
|
||||||
func (t *OrderAfterSaleSupplierTool) Definition() entitys.ToolDefinition {
|
func (t *OrderAfterSaleSupplierTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{}
|
return entitys.ToolDefinition{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,26 +4,28 @@ import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
"ai_scheduler/internal/pkg"
|
"ai_scheduler/internal/pkg"
|
||||||
|
"ai_scheduler/internal/pkg/lsxd"
|
||||||
"ai_scheduler/internal/pkg/rec_extra"
|
"ai_scheduler/internal/pkg/rec_extra"
|
||||||
"ai_scheduler/internal/pkg/utils_ollama"
|
"ai_scheduler/internal/pkg/utils_ollama"
|
||||||
|
"ai_scheduler/utils"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"gitea.cdlsxd.cn/self-tools/l_request"
|
"gitea.cdlsxd.cn/self-tools/l_request"
|
||||||
"github.com/gofiber/fiber/v2/log"
|
|
||||||
"github.com/ollama/ollama/api"
|
"github.com/ollama/ollama/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ZltxOrderDetailTool 直连天下订单详情工具
|
// ZltxOrderDetailTool 直连天下订单详情工具
|
||||||
type ZltxOrderDetailTool struct {
|
type ZltxOrderDetailTool struct {
|
||||||
config config.ToolConfig
|
config *config.Config
|
||||||
llm *utils_ollama.Client
|
llm *utils_ollama.Client
|
||||||
|
rdb *utils.Rdb
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewZltxOrderDetailTool 创建直连天下订单详情工具
|
// NewZltxOrderDetailTool 创建直连天下订单详情工具
|
||||||
func NewZltxOrderDetailTool(config config.ToolConfig, llm *utils_ollama.Client) *ZltxOrderDetailTool {
|
func NewZltxOrderDetailTool(config *config.Config, rdb *utils.Rdb, llm *utils_ollama.Client) *ZltxOrderDetailTool {
|
||||||
return &ZltxOrderDetailTool{config: config, llm: llm}
|
return &ZltxOrderDetailTool{config: config, rdb: rdb, llm: llm}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name 返回工具名称
|
// Name 返回工具名称
|
||||||
|
|
@ -37,7 +39,7 @@ func (w *ZltxOrderDetailTool) Description() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Definition 返回工具定义
|
// Definition 返回工具定义
|
||||||
func (w *ZltxOrderDetailTool) Definition() entitys.ToolDefinition {
|
func (w *ZltxOrderDetailTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
@ -54,6 +56,19 @@ func (w *ZltxOrderDetailTool) Definition() entitys.ToolDefinition {
|
||||||
"required": []string{"number"},
|
"required": []string{"number"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
AuthFunc: func(rec *entitys.Recognize) ([]byte, error) {
|
||||||
|
ext, err := rec_extra.GetTaskRecExt(rec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(ext.Auth) > 0 {
|
||||||
|
return []byte(ext.Auth), nil
|
||||||
|
} else {
|
||||||
|
login := lsxd.NewLogin(w.config, w.rdb)
|
||||||
|
token := login.GetToken(ctx)
|
||||||
|
return []byte(token), nil
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +108,7 @@ func (w *ZltxOrderDetailTool) Execute(ctx context.Context, rec *entitys.Recogniz
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这里可以集成真实的直连天下订单详情API
|
// 这里可以集成真实的直连天下订单详情API
|
||||||
return w.getZltxOrderDetail(rec, req.OrderNumber)
|
return w.getZltxOrderDetail(ctx, rec, req.OrderNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ZltxOrderDetailRequest) UnmarshalJSON(data []byte) error {
|
func (r *ZltxOrderDetailRequest) UnmarshalJSON(data []byte) error {
|
||||||
|
|
@ -113,8 +128,8 @@ func (r *ZltxOrderDetailRequest) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMockZltxOrderDetail 获取模拟直连天下订单详情数据
|
// getMockZltxOrderDetail 获取模拟直连天下订单详情数据
|
||||||
func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number interface{}) (err error) {
|
func (w *ZltxOrderDetailTool) getZltxOrderDetail(ctx context.Context, rec *entitys.Recognize, number interface{}) (err error) {
|
||||||
log.Infof("订单编号:%v,类型:%v")
|
|
||||||
var orderNum string
|
var orderNum string
|
||||||
switch number.(type) {
|
switch number.(type) {
|
||||||
case int, int32, int64:
|
case int, int32, int64:
|
||||||
|
|
@ -127,15 +142,15 @@ func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number
|
||||||
orderNum = fmt.Sprintf("%v", number)
|
orderNum = fmt.Sprintf("%v", number)
|
||||||
}
|
}
|
||||||
|
|
||||||
ext, err := rec_extra.GetTaskRecExt(rec)
|
token, err := w.Definition(ctx).AuthFunc(rec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
//查询订单详情
|
//查询订单详情
|
||||||
req := l_request.Request{
|
req := l_request.Request{
|
||||||
Url: fmt.Sprintf(w.config.BaseURL, orderNum),
|
Url: fmt.Sprintf(w.config.Tools.ZltxOrderDetail.BaseURL, orderNum),
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
|
"Authorization": fmt.Sprintf("Bearer %s", token),
|
||||||
},
|
},
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
}
|
}
|
||||||
|
|
@ -160,11 +175,10 @@ func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number
|
||||||
|
|
||||||
if resData.Data.Direct != nil {
|
if resData.Data.Direct != nil {
|
||||||
entitys.ResLoading(rec.Ch, w.Name(), "正在分析订单日志")
|
entitys.ResLoading(rec.Ch, w.Name(), "正在分析订单日志")
|
||||||
|
|
||||||
req = l_request.Request{
|
req = l_request.Request{
|
||||||
Url: fmt.Sprintf(w.config.AddURL, resData.Data.Direct["orderOrderNumber"].(string), resData.Data.Direct["serialNumber"].(string)),
|
Url: fmt.Sprintf(w.config.Tools.ZltxOrderDetail.AddURL, resData.Data.Direct["orderOrderNumber"].(string), resData.Data.Direct["serialNumber"].(string)),
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
|
"Authorization": fmt.Sprintf("Bearer %s", token),
|
||||||
},
|
},
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
}
|
}
|
||||||
|
|
@ -184,7 +198,7 @@ func (w *ZltxOrderDetailTool) getZltxOrderDetail(rec *entitys.Recognize, number
|
||||||
return fmt.Errorf("订单日志解析失败:%s", err)
|
return fmt.Errorf("订单日志解析失败:%s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = w.llm.ChatStream(context.TODO(), rec.Ch, []api.Message{
|
err = w.llm.ChatStream(ctx, rec.Ch, []api.Message{
|
||||||
{
|
{
|
||||||
Role: "system",
|
Role: "system",
|
||||||
Content: "你是一个订单日志助手。用户可能会提供订单日志,你需要按以下规则处理:\n" +
|
Content: "你是一个订单日志助手。用户可能会提供订单日志,你需要按以下规则处理:\n" +
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ func (t *ZltxOrderLogTool) Description() string {
|
||||||
return "查询订单日志"
|
return "查询订单日志"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ZltxOrderLogTool) Definition() entitys.ToolDefinition {
|
func (t *ZltxOrderLogTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ func (z ZltxProductTool) Description() string {
|
||||||
return "获取直连天下商品信息"
|
return "获取直连天下商品信息"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z ZltxProductTool) Definition() entitys.ToolDefinition {
|
func (z ZltxProductTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ package zltx
|
||||||
import (
|
import (
|
||||||
"ai_scheduler/internal/config"
|
"ai_scheduler/internal/config"
|
||||||
"ai_scheduler/internal/entitys"
|
"ai_scheduler/internal/entitys"
|
||||||
|
"ai_scheduler/internal/pkg/lsxd"
|
||||||
"ai_scheduler/internal/pkg/rec_extra"
|
"ai_scheduler/internal/pkg/rec_extra"
|
||||||
|
"ai_scheduler/utils"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -13,7 +15,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ZltxOrderStatisticsTool struct {
|
type ZltxOrderStatisticsTool struct {
|
||||||
config config.ToolConfig
|
config *config.Config
|
||||||
|
rdb *utils.Rdb
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z ZltxOrderStatisticsTool) Name() string {
|
func (z ZltxOrderStatisticsTool) Name() string {
|
||||||
|
|
@ -24,7 +27,7 @@ func (z ZltxOrderStatisticsTool) Description() string {
|
||||||
return "通过账号获取订单统计信息"
|
return "通过账号获取订单统计信息"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z ZltxOrderStatisticsTool) Definition() entitys.ToolDefinition {
|
func (z ZltxOrderStatisticsTool) Definition(ctx context.Context) entitys.ToolDefinition {
|
||||||
return entitys.ToolDefinition{
|
return entitys.ToolDefinition{
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: entitys.FunctionDef{
|
Function: entitys.FunctionDef{
|
||||||
|
|
@ -41,6 +44,19 @@ func (z ZltxOrderStatisticsTool) Definition() entitys.ToolDefinition {
|
||||||
"required": []string{"number"},
|
"required": []string{"number"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
AuthFunc: func(rec *entitys.Recognize) ([]byte, error) {
|
||||||
|
ext, err := rec_extra.GetTaskRecExt(rec)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(ext.Auth) > 0 {
|
||||||
|
return []byte(ext.Auth), nil
|
||||||
|
} else {
|
||||||
|
login := lsxd.NewLogin(z.config, z.rdb)
|
||||||
|
token := login.GetToken(ctx)
|
||||||
|
return []byte(token), nil
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,7 +72,7 @@ func (z ZltxOrderStatisticsTool) Execute(ctx context.Context, rec *entitys.Recog
|
||||||
if req.Number == nil {
|
if req.Number == nil {
|
||||||
return fmt.Errorf("number is required")
|
return fmt.Errorf("number is required")
|
||||||
}
|
}
|
||||||
return z.getZltxOrderStatistics(req.Number, rec)
|
return z.getZltxOrderStatistics(ctx, req.Number, rec)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ZltxOrderStatisticsResponse struct {
|
type ZltxOrderStatisticsResponse struct {
|
||||||
|
|
@ -76,17 +92,17 @@ type ZltxOrderStatisticsData struct {
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z ZltxOrderStatisticsTool) getZltxOrderStatistics(number interface{}, rec *entitys.Recognize) error {
|
func (z ZltxOrderStatisticsTool) getZltxOrderStatistics(ctx context.Context, number interface{}, rec *entitys.Recognize) error {
|
||||||
ext, err := rec_extra.GetTaskRecExt(rec)
|
token, err := z.Definition(ctx).AuthFunc(rec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//查询订单详情
|
//查询订单详情
|
||||||
url := fmt.Sprintf("%s%s", z.config.BaseURL, fmt.Sprintf("%v", number))
|
url := fmt.Sprintf("%s%s", z.config.Tools.ZltxOrderStatistics.BaseURL, fmt.Sprintf("%v", number))
|
||||||
req := l_request.Request{
|
req := l_request.Request{
|
||||||
Url: url,
|
Url: url,
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
"Authorization": fmt.Sprintf("Bearer %s", ext.Auth),
|
"Authorization": fmt.Sprintf("Bearer %s", string(token)),
|
||||||
},
|
},
|
||||||
Method: "GET",
|
Method: "GET",
|
||||||
}
|
}
|
||||||
|
|
@ -116,8 +132,9 @@ func (z ZltxOrderStatisticsTool) getZltxOrderStatistics(number interface{}, rec
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewZltxOrderStatisticsTool(config config.ToolConfig) *ZltxOrderStatisticsTool {
|
func NewZltxOrderStatisticsTool(config *config.Config, rdb *utils.Rdb) *ZltxOrderStatisticsTool {
|
||||||
return &ZltxOrderStatisticsTool{
|
return &ZltxOrderStatisticsTool{
|
||||||
config: config,
|
config: config,
|
||||||
|
rdb: rdb,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue