Compare commits

..

3 Commits

15 changed files with 400 additions and 187 deletions

View File

@ -12,6 +12,7 @@ import (
func main() {
configPath := flag.String("config", "./config/config_test.yaml", "Path to configuration file")
onBot := flag.String("bot", "", "bot start")
cron := flag.String("cron", "", "close")
flag.Parse()
ctx := context.Background()
bc, err := config.LoadConfig(*configPath)
@ -29,7 +30,7 @@ func main() {
//钉钉机器人
app.DingBotServer.Run(ctx, *onBot)
//定时任务 - 测试环境不启用
if configPath != nil && *configPath == "./config/config.yaml" {
if *cron == "start" {
app.Cron.Run(ctx)
}

View File

@ -108,6 +108,8 @@ tools:
base_url: "https://api.coze.cn"
api_key: "7583905168607100978"
api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ"
zltxResellerAuthProductToManagerAndDefaultLossReason:
base_url: "https://revcl.1688sup.com/api/admin/resellerAuthProductToManagerAndDefaultLossReason"
# eino tool 配置
eino_tools:

View File

@ -26,14 +26,12 @@ coze:
lsxd:
# 统一登录
login_url: "http://api.test.user.1688sup.com/v1/login/phone"
phone: "OFJ8UpqOlI7+w3Qklf36ZA=="
password: "tEbFegH/DRRh6LutFb7o3g=="
code: "123456"
check_token_url: "http://api.test.user.1688sup.com/v1/user/welcome"
login_url: "https://api.user.1688sup.com/v1/login/phone"
phone: "ORlviZN7N06W2+WKLe76xg=="
password: "V5Uh8C4bamEM6UQZh4TCeQ=="
code: "456789"
check_token_url: "https://api.user.1688sup.com/v1/user/welcome"
zltx:
req_url: "https://gateway.dev.cdlsxd.cn/zltx_api"
sys:
session_len: 6
@ -106,6 +104,8 @@ tools:
base_url: "https://api.coze.cn"
api_key: "7583905168607100978"
api_secret: "pat_eEN0BdLNDughEtABjJJRYTW71olvDU0qUbfQUeaPc2NnYWO8HeyNoui5aR9z0sSZ"
zltxResellerAuthProductToManagerAndDefaultLossReason:
base_url: "https://revcl.1688sup.com/api/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason"
# eino tool 配置
eino_tools:

View File

@ -16,10 +16,12 @@ fi
CONFIG_FILE="config/config.yaml"
BRANCH="master"
BOT="All"
CRON="start"
if [ "$MODE" = "dev" ]; then
CONFIG_FILE="config/config_test.yaml"
BOT="zltx"
BRANCH="test"
CRON="close"
fi
git fetch origin
@ -47,6 +49,8 @@ docker run -itd \
-v ./cache:/app/cache \
-v ./tmpl:/app/tmpl \
-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}

View File

@ -19,7 +19,6 @@ import (
"fmt"
"strings"
"time"
"unicode"
"gitea.cdlsxd.cn/self-tools/l-dingtalk-stream-sdk-go/chatbot"
@ -45,6 +44,7 @@ type DingTalkBotBiz struct {
qywxGroupHandle *qywx.Group
groupConfigBiz *GroupConfigBiz
reportDailyCacheImpl *impl.ReportDailyCacheImpl
macro *do.Macro
}
// NewDingTalkBotBiz
@ -60,6 +60,7 @@ func NewDingTalkBotBiz(
conf *config.Config,
cardSend *dingtalk.SendCardClient,
groupConfigBiz *GroupConfigBiz,
macro *do.Macro,
) *DingTalkBotBiz {
return &DingTalkBotBiz{
do: do,
@ -74,6 +75,7 @@ func NewDingTalkBotBiz(
conf: conf,
cardSend: cardSend,
reportDailyCacheImpl: reportDailyCacheImpl,
macro: macro,
}
}
@ -148,10 +150,14 @@ func (d *DingTalkBotBiz) handleGroupChat(ctx context.Context, requireData *entit
return
}
//宏
err, isFinal := d.Macro(ctx, requireData, groupConfig)
sucMsg, err, isFinal := d.macro.Router(ctx, requireData.Req.Text.Content, groupConfig)
if err != nil {
entitys.ResText(requireData.Ch, "", err.Error())
return
}
if len(sucMsg) > 0 {
entitys.ResText(requireData.Ch, "", sucMsg)
}
if isFinal {
return
}
@ -168,102 +174,6 @@ func (d *DingTalkBotBiz) handleGroupChat(ctx context.Context, requireData *entit
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) {
group, err = d.botGroupImpl.GetByConversationIdAndRobotCode(conversationId, robotCode)
if err != nil {

288
internal/biz/do/macro.go Normal file
View File

@ -0,0 +1,288 @@
package do
import (
"ai_scheduler/internal/data/impl"
"ai_scheduler/internal/data/model"
"ai_scheduler/internal/pkg"
"ai_scheduler/internal/tools/bbxt"
"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
}
func NewMacro(
botGroupImpl *impl.BotGroupImpl,
reportDailyCacheImpl *impl.ReportDailyCacheImpl,
) *Macro {
return &Macro{
botGroupImpl: botGroupImpl,
reportDailyCacheImpl: reportDailyCacheImpl,
}
}
type MacroFunc func(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (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, groupConfig)
default:
}
return
}
func (m *Macro) NegativeProfitUpdate(ctx context.Context, content string, groupConfig *model.AiBotGroupConfig) (successMsg string, err error, isFinish bool) {
//newContent := strings.ReplaceAll(strings.TrimSpace(content), "[负利润分析]更新:", "")
jsonData, err := ParseLossData(content)
if err != nil {
err = fmt.Errorf("解析失败:%v", err)
return
}
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})
err = m.reportDailyCacheImpl.UpdateByCond(&cond, &model.AiReportDailyCache{
Value: pkg.JsonStringIgonErr(jsonData),
})
if err != nil {
err = fmt.Errorf("解析失败:%v", err)
return
}
isFinish = true
successMsg = "更新成功"
return
}
func (m *Macro) NegativeProfitGet(ctx context.Context) (successMsg string, err error, isFinish bool) {
var (
data model.AiReportDailyCache
value map[int32]*bbxt.ResellerLossSumProductRelation
)
isFinish = true
cond := builder.NewCond()
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
cond = cond.And(builder.Eq{"cache_key": time.Now().Format(time.DateOnly)})
err = m.reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &data)
if err != nil {
err = fmt.Errorf("获取失败:%v", err)
return
}
if data.ID == 0 {
successMsg = "暂未获取今日负利润分析数据,请先呼出报表数据"
return
}
err = json.Unmarshal([]byte(data.Value), &value)
if err != nil {
err = fmt.Errorf("获取失败,格式解析错误:%v", err)
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()
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
}

View File

@ -17,7 +17,6 @@ import (
"ai_scheduler/internal/tools/bbxt"
"ai_scheduler/utils"
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
@ -189,11 +188,11 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
if _err != nil {
return _err
}
reports = append(reports, repo...)
rechargeReport, _err := g.rechargeDailyReport(ctx, t, product, nil)
if _err != nil || len(repo) == 0 {
if _err != nil {
return _err
}
reports = append(reports, repo...)
reports = append(reports, rechargeReport...)
case "report_daily_recharge":
product := strings.Split(groupConfig.ProductName, ",")
@ -224,7 +223,6 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz
}
entitys.ResText(rec.Ch, "", fmt.Sprintf("%s![图片](%s)", report.Title, report.Url))
}
return nil
}
@ -421,26 +419,28 @@ func (g *GroupConfigBiz) GetReportCache(ctx context.Context, day time.Time, tota
dayDate := day.Format(time.DateOnly)
cond := builder.NewCond()
cond = cond.And(builder.Eq{"index": bbxt.IndexLossSumDetail})
cond = cond.And(builder.Eq{"key": dayDate})
cond = cond.And(builder.Eq{"cache_index": bbxt.IndexLossSumDetail})
cond = cond.And(builder.Eq{"cache_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)
return err
}
if cache.ID == 0 {
ResellerProductRelation, err = bbxtObj.GetResellerLossMannagerAndLossReasonFromApi(ctx, totalDetail)
if err != nil {
return err
}
cache = model.AiReportDailyCache{
CacheKey: dayDate,
CacheIndex: bbxt.IndexLossSumDetail,
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
}
_, err = g.reportDailyCacheImpl.Add(&cache)
} else {
err = json.Unmarshal([]byte(cache.Value), &ResellerProductRelation)
}
if err != nil {
return err
}

View File

@ -20,4 +20,5 @@ var ProviderSetBiz = wire.NewSet(
NewDingTalkBotBiz,
NewQywxAppBiz,
NewGroupConfigBiz,
do.NewMacro,
)

View File

@ -27,7 +27,6 @@ type Config struct {
LLM LLM `mapstructure:"llm"`
Dingtalk DingtalkConfig `mapstructure:"dingtalk"`
Qywx QywxConfig `mapstructure:"qywx"`
ZLTX ZLTX `mapstructure:"zltx"`
}
type ZLTX struct {
@ -196,7 +195,8 @@ type ToolsConfig struct {
// Coze 快递查询工具
CozeExpress ToolConfig `mapstructure:"cozeExpress"`
// Coze 公司查询工具
CozeCompany ToolConfig `mapstructure:"cozeCompany"`
CozeCompany ToolConfig `mapstructure:"cozeCompany"`
ZltxResellerAuthProductToManagerAndDefaultLossReason ToolConfig `mapstructure:"zltxResellerAuthProductToManagerAndDefaultLossReason"`
}
// ToolConfig 单个工具配置

View File

@ -8,10 +8,10 @@ const TableNameAiReportDailyCache = "ai_report_daily_cache"
// AiReportDailyCache mapped from table <ai_report_daily_cache>
type AiReportDailyCache struct {
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
Key string `gorm:"column:key;not null;default:1;comment:索引方式,可以是任意类型" json:"key"` // 索引方式,可以是任意类型
Value string `gorm:"column:value;comment:类型下所需路由以及参数" json:"value"` // 类型下所需路由以及参数
Index string `gorm:"column:index;not null;comment:类型" json:"index"` // 类型
ID int32 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
CacheKey string `gorm:"column:cache_key;not null;default:1;comment:索引方式,可以是任意类型" json:"cache_key"` // 索引方式,可以是任意类型
Value string `gorm:"column:value;comment:类型下所需路由以及参数" json:"value"` // 类型下所需路由以及参数
CacheIndex string `gorm:"column:cache_index;not null;comment:类型" json:"cache_index"` // 类型
}
// TableName AiReportDailyCache's table name

View File

@ -195,48 +195,49 @@ type GetManagerAndDefaultLossReasonResponse struct {
}
type GetManagerAndDefaultLossReasonResponseList struct {
ResellerInfo *GetManagerAndDefaultLossReasonResponse_ResellerInfo `json:"GetManagerAndDefaultLossReasonResponse_ResellerInfo,omitempty"`
ProductList []*GetManagerAndDefaultLossReasonResponse_ProductList `json:"GetManagerAndDefaultLossReasonResponse_ProductList,omitempty"`
ResellerInfo *GetManagerAndDefaultLossReasonResponse_ResellerInfo `json:"resellerInfo,omitempty"`
ProductList []*GetManagerAndDefaultLossReasonResponse_ProductList `json:"productList,omitempty"`
}
type GetManagerAndDefaultLossReasonResponse_ResellerInfo struct {
ResellerId int32 `json:"reseller_id,omitempty"`
AfterSaleName string `json:"after_sale_name,omitempty"`
ResellerId int32 `json:"resellerId,omitempty"`
AfterSaleName string `json:"AfterSaleName,omitempty"`
}
type GetManagerAndDefaultLossReasonResponse_ProductList struct {
ProductId int32 `json:"product_id,omitempty"`
LossReason string `json:"loss_reason,omitempty"`
ProductId int32 `json:"productId,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 官方商品列表
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)
if err != nil {
@ -244,7 +245,7 @@ func GetManagerAndDefaultLossReasonApi(param *GetManagerAndDefaultLossReasonRequ
}
req := &l_request.Request{
Url: reqUrl + "/admin/reseller/resellerAuthProduct/getManagerAndDefaultLossReason",
Url: reqUrl,
Method: http.MethodPost,
Json: reqParam,
Headers: map[string]string{

View File

@ -218,24 +218,24 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time,
}
}
//if len(totalDetail) > 0 {
// err = initFunc(ctx, now, totalDetail, b)
// if err != nil {
// return
// }
// filePath := b.cacheDir + "/kshj_total_ana" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
// title := "截至" + timeCh + "亏损100以上的分销商&产品负利润原因"
// err = b.resellerDetailFillExcelAna(b.excelTempDir+"/"+"kshj_total_ana.xlsx", filePath, totalDetail, title)
// if err != nil {
// return
// }
// report[2] = &ReportRes{
// ReportName: "负利润分析(亏损100以上)",
// Title: "截至" + timeCh + "亏损100以上利润原因",
// Path: filePath,
// Data: total,
// }
//}
if len(totalDetail) > 0 {
err = initFunc(ctx, now, totalDetail, b)
if err != nil {
return
}
filePath := b.cacheDir + "/kshj_total_ana" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx"
title := "截至" + timeCh + "亏损100以上的分销商&产品负利润原因"
err = b.resellerDetailFillExcelAna(b.excelTempDir+"/"+"kshj_total_ana.xlsx", filePath, totalDetail, title)
if err != nil {
return
}
report[2] = &ReportRes{
ReportName: "负利润分析(亏损100以上)",
Title: "截至" + timeCh + "亏损100以上利润原因",
Path: filePath,
Data: total,
}
}
return report, nil
}
@ -269,7 +269,7 @@ func (b *BbxtTools) GetResellerLossMannagerAndLossReasonFromApi(ctx context.Cont
}
res, err := GetManagerAndDefaultLossReasonApi(&GetManagerAndDefaultLossReasonRequest{
Param: resellerMap,
}, b.login.GetToken(ctx), b.config.ZLTX.ReqUrl)
}, b.login.GetToken(ctx), b.config.Tools.ZltxResellerAuthProductToManagerAndDefaultLossReason.BaseURL)
if err != nil {
return nil, err
}
@ -283,6 +283,12 @@ func (b *BbxtTools) GetResellerLossMannagerAndLossReasonFromApi(ctx context.Cont
relationMap[v.ResellerInfo.ResellerId].AfterSaleName = v.ResellerInfo.AfterSaleName
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
}
}

View File

@ -111,8 +111,8 @@ func GetReportCache(ctx context.Context, day time.Time, totalDetail []*ResellerL
var ResellerProductRelation map[int32]*ResellerLossSumProductRelation
dayDate := day.Format(time.DateOnly)
cond := builder.NewCond()
cond = cond.And(builder.Eq{"`index`": IndexLossSumDetail})
cond = cond.And(builder.Eq{"`key`": dayDate})
cond = cond.And(builder.Eq{"cache_index": IndexLossSumDetail})
cond = cond.And(builder.Eq{"cache_key": dayDate})
var cache model.AiReportDailyCache
err := reportDailyCacheImpl.GetOneBySearchToStrut(&cond, &cache)
@ -125,9 +125,9 @@ func GetReportCache(ctx context.Context, day time.Time, totalDetail []*ResellerL
return err
}
cache = model.AiReportDailyCache{
Key: dayDate,
Index: IndexLossSumDetail,
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
CacheKey: dayDate,
CacheIndex: IndexLossSumDetail,
Value: pkg.JsonStringIgonErr(ResellerProductRelation),
}
_, err = reportDailyCacheImpl.Add(&cache)
if err != nil {

Binary file not shown.

Binary file not shown.