chore: 初始开源发布
iotlcm-admin-svr:管理后台服务。 - Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件) - 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、 MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位; 私网 IP → 文档地址段;库名 xiujie_admin → iotlcm - 真实手机号/邮箱 → 合法 11 位编造号 / example.com - 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、 私有依赖 go get 行、明文 registry 登录口令 - 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名 - Dockerfile 改用公共基础镜像 - 拼错的 RADEME.md → README.md,README 重写 - 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用 - 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
// Package gen
|
||||
// @Link https://github.com/xiujiecn/xiu-admin
|
||||
// @Copyright Copyright (c) 2026 LiXiujie
|
||||
// @Author Lxj <li@xiujie.cn>
|
||||
// @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE
|
||||
// @AutoGenerate Version
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/handler"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/hook"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/convert"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/excel"
|
||||
"strconv"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
type sCommonTFinCommissionDetail struct{}
|
||||
|
||||
func NewCommonTFinCommissionDetail() *sCommonTFinCommissionDetail {
|
||||
return &sCommonTFinCommissionDetail{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
service.RegisterCommonTFinCommissionDetail(NewCommonTFinCommissionDetail())
|
||||
}
|
||||
|
||||
// Model 分润明细表ORM模型
|
||||
func (s *sCommonTFinCommissionDetail) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
|
||||
if len(option) == 0 {
|
||||
option = append(option, &handler.Option{
|
||||
FilterTenant: true,
|
||||
FilterAuth: true,
|
||||
})
|
||||
}
|
||||
return handler.Model(dao.TFinCommissionDetail.Ctx(ctx), option...)
|
||||
}
|
||||
|
||||
// List 获取分润明细表列表
|
||||
func (s *sCommonTFinCommissionDetail) List(ctx context.Context, in *model.TFinCommissionDetailListParam) (list []*model.TFinCommissionDetailListModel, totalCount int, err error) {
|
||||
mod := s.Model(ctx)
|
||||
|
||||
// 字段过滤
|
||||
mod = mod.Fields(model.TFinCommissionDetailListModel{})
|
||||
|
||||
// 查询主键ID
|
||||
if in.Id > 0 {
|
||||
mod = mod.Where(dao.TFinCommissionDetail.Columns().Id, in.Id)
|
||||
}
|
||||
|
||||
// 查询分润状态:0待结算,1可提现
|
||||
if in.CommissionStatus > 0 {
|
||||
mod = mod.Where(dao.TFinCommissionDetail.Columns().CommissionStatus, in.CommissionStatus)
|
||||
}
|
||||
|
||||
// 查询创建时间
|
||||
if len(in.CreatedAt) == 2 {
|
||||
in.CreatedAt[1] = in.CreatedAt[1].EndOfDay()
|
||||
}
|
||||
if len(in.CreatedAt) == 2 {
|
||||
mod = mod.WhereBetween(dao.TFinCommissionDetail.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
|
||||
}
|
||||
|
||||
// 分页
|
||||
mod = mod.Page(in.Page, in.PageSize)
|
||||
|
||||
// 排序
|
||||
mod = mod.OrderDesc(dao.TFinCommissionDetail.Columns().Id)
|
||||
|
||||
// 操作人摘要信息
|
||||
mod = mod.Hook(hook.MemberSummary)
|
||||
|
||||
// 查询数据
|
||||
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
|
||||
err = gerror.Wrap(err, "获取分润明细表列表失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Export 导出分润明细表
|
||||
func (s *sCommonTFinCommissionDetail) Export(ctx context.Context, in *model.TFinCommissionDetailListParam) (err error) {
|
||||
list, totalCount, err := s.List(ctx, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
|
||||
tags, err := convert.GetEntityDescTags(model.TFinCommissionDetailExportModel{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
fileName = "导出分润明细表-" + gctx.CtxId(ctx)
|
||||
sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, (totalCount+in.PageSize-1)/in.PageSize, in.Page, len(list))
|
||||
exports []model.TFinCommissionDetailExportModel
|
||||
)
|
||||
|
||||
if err = gconv.Scan(list, &exports); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
|
||||
return
|
||||
}
|
||||
|
||||
// Edit 修改/新增分润明细表
|
||||
func (s *sCommonTFinCommissionDetail) Edit(ctx context.Context, in *model.TFinCommissionDetailEditParam) (err error) {
|
||||
// 验证'CommissionNo'唯一
|
||||
if err = xgorm.IsUnique(ctx, &dao.TFinCommissionDetail, g.Map{dao.TFinCommissionDetail.Columns().CommissionNo: in.CommissionNo}, "分润明细编号已存在", in.Id); err != nil {
|
||||
return
|
||||
}
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
|
||||
|
||||
// 修改
|
||||
if in.Id > 0 {
|
||||
updatedBy := contexts.GetUserId(ctx)
|
||||
in.UpdatedBy = &updatedBy
|
||||
in.UpdatedAt = gtime.Now()
|
||||
if _, err = s.Model(ctx).
|
||||
Fields(model.TFinCommissionDetailUpdateFields{}).
|
||||
WherePri(in.Id).Data(in).Update(); err != nil {
|
||||
err = gerror.Wrap(err, "修改分润明细表失败,请稍后重试!")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 新增
|
||||
tenantId := contexts.GetTenantId(ctx)
|
||||
in.TenantId = &tenantId
|
||||
createdDept := contexts.GetDeptId(ctx)
|
||||
in.CreatedDept = &createdDept
|
||||
createdBy := contexts.GetUserId(ctx)
|
||||
in.CreatedBy = &createdBy
|
||||
in.CreatedAt = gtime.Now()
|
||||
if _, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
|
||||
Fields(model.TFinCommissionDetailInsertFields{}).
|
||||
Data(in).Insert(); err != nil {
|
||||
err = gerror.Wrap(err, "新增分润明细表失败,请稍后重试!")
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// Delete 删除分润明细表
|
||||
func (s *sCommonTFinCommissionDetail) Delete(ctx context.Context, in *model.TFinCommissionDetailDeleteParam) (err error) {
|
||||
|
||||
if _, err = s.Model(ctx).WherePri(in.Id).Unscoped().Delete(); err != nil {
|
||||
err = gerror.Wrap(err, "删除分润明细表失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// View 获取分润明细表指定信息
|
||||
func (s *sCommonTFinCommissionDetail) View(ctx context.Context, in *model.TFinCommissionDetailViewParam) (res *model.TFinCommissionDetailViewModel, err error) {
|
||||
if err = s.Model(ctx).WherePri(in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil {
|
||||
err = gerror.Wrap(err, "获取分润明细表信息,请稍后重试!")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MarkSettled 批量标记分润明细为可提现状态。
|
||||
func (s *sCommonTFinCommissionDetail) MarkSettled(ctx context.Context, tx gdb.TX, in *model.TFinCommissionSettleUpdateParam) error {
|
||||
if in == nil {
|
||||
return gerror.New("分润结算更新参数不能为空")
|
||||
}
|
||||
if len(in.Ids) == 0 {
|
||||
return gerror.New("分润明细ID不能为空")
|
||||
}
|
||||
settlementTime := in.SettlementTime
|
||||
if settlementTime == nil {
|
||||
settlementTime = gtime.Now()
|
||||
}
|
||||
userId := contexts.GetUserId(ctx)
|
||||
columns := dao.TFinCommissionDetail.Columns()
|
||||
result, err := tx.Ctx(ctx).Model(dao.TFinCommissionDetail.Table()).
|
||||
WhereIn(columns.Id, in.Ids).
|
||||
Where(columns.CommissionStatus, financeCommissionStatusPending).
|
||||
Data(g.Map{
|
||||
columns.CommissionStatus: financeCommissionStatusSettled,
|
||||
columns.SettlementTime: settlementTime,
|
||||
columns.UpdatedBy: userId,
|
||||
columns.UpdatedAt: settlementTime,
|
||||
}).
|
||||
Update()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "更新分润明细结算状态失败,请稍后重试!")
|
||||
}
|
||||
affected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "获取分润明细结算状态更新结果失败")
|
||||
}
|
||||
if affected != int64(len(in.Ids)) {
|
||||
return gerror.New("部分分润明细状态已变化,请下次任务重试")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 分层分润概览 分润表
|
||||
// 一级客户收入 benefit_dept_level=1 commission_amount相加
|
||||
// 二级客户收入 benefit_dept_level=2 commission_amount相加
|
||||
// 三级客户收入 benefit_dept_level=3 commission_amount相加
|
||||
// 总收入 一级二级三级加起来总和
|
||||
func (s *sCommonTFinCommissionDetail) GetCommissionOverview(ctx context.Context, in *model.TCommissionOverviewParam) (res *model.TCommissionOverviewModel, err error) {
|
||||
res = &model.TCommissionOverviewModel{}
|
||||
deptId := contexts.GetDeptId(ctx)
|
||||
|
||||
// 解析账期参数
|
||||
var startPeriod, endPeriod string
|
||||
if in.Type == 1 { // 年
|
||||
startPeriod = in.Year + "-01"
|
||||
endPeriod = in.Year + "-12"
|
||||
} else if in.Type == 2 { // 月
|
||||
startPeriod = in.Month
|
||||
endPeriod = in.Month
|
||||
}
|
||||
|
||||
// 查询一级客户收入
|
||||
type levelRow struct {
|
||||
CommissionAmount float64 `orm:"commission_amount"`
|
||||
}
|
||||
var level1Result *levelRow
|
||||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptLevel, 1).
|
||||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount").
|
||||
Scan(&level1Result); err != nil {
|
||||
err = gerror.Wrap(err, "查询一级客户收入失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
if level1Result != nil {
|
||||
res.Level1Income = level1Result.CommissionAmount
|
||||
}
|
||||
|
||||
// 查询二级客户收入
|
||||
var level2Result *levelRow
|
||||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptLevel, 2).
|
||||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount").
|
||||
Scan(&level2Result); err != nil {
|
||||
err = gerror.Wrap(err, "查询二级客户收入失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
if level2Result != nil {
|
||||
res.Level2Income = level2Result.CommissionAmount
|
||||
}
|
||||
|
||||
// 查询三级客户收入
|
||||
var level3Result *levelRow
|
||||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptLevel, 3).
|
||||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount").
|
||||
Scan(&level3Result); err != nil {
|
||||
err = gerror.Wrap(err, "查询三级客户收入失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
if level3Result != nil {
|
||||
res.Level3Income = level3Result.CommissionAmount
|
||||
}
|
||||
|
||||
// 计算总收入
|
||||
res.TotalIncome = res.Level1Income + res.Level2Income + res.Level3Income
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetLevelSummary 获取层级汇总表
|
||||
// 客户数 根据 benefit_dept_level 收益机构层级分组
|
||||
// 收入金额 根据收益机构id去 t_profit_account_month_bill 查,dept_id=收益机构id,收入=分润结算+余额转提现
|
||||
// 分润金额 根据收益机构id去 t_profit_account_month_bill 查,commission_income
|
||||
// 顶级利润贡献 等于分润金额
|
||||
// 收入占比
|
||||
// 环比 选年与去年对比,选月与上个月对比
|
||||
func (s *sCommonTFinCommissionDetail) GetLevelSummary(ctx context.Context, in *model.TLevelSummaryParam) (res *model.TLevelSummaryModel, err error) {
|
||||
res = &model.TLevelSummaryModel{}
|
||||
deptId := contexts.GetDeptId(ctx)
|
||||
|
||||
// 解析账期参数
|
||||
var startPeriod, endPeriod string
|
||||
if in.Type == 1 { // 年
|
||||
startPeriod = in.Year + "-01"
|
||||
endPeriod = in.Year + "-12"
|
||||
} else if in.Type == 2 { // 月
|
||||
startPeriod = in.Month
|
||||
endPeriod = in.Month
|
||||
}
|
||||
|
||||
// 查询各层级的客户数和分润金额(从分润表)
|
||||
type levelData struct {
|
||||
Level int `orm:"level"`
|
||||
CustomerCount int `orm:"customer_count"`
|
||||
CommissionAmount float64 `orm:"commission_amount"`
|
||||
}
|
||||
var levelResults []*levelData
|
||||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||||
Fields("SUM(" + dao.TFinCommissionDetail.Columns().CommissionAmount + ") as commission_amount, COUNT(DISTINCT " + dao.TFinCommissionDetail.Columns().PayerDeptId + ") as customer_count, " + dao.TFinCommissionDetail.Columns().BenefitDeptLevel + " as level").
|
||||
Group(dao.TFinCommissionDetail.Columns().BenefitDeptLevel).
|
||||
Scan(&levelResults); err != nil {
|
||||
err = gerror.Wrap(err, "查询层级数据失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建层级与分润金额的映射
|
||||
levelCommissionMap := make(map[int]float64)
|
||||
for _, lr := range levelResults {
|
||||
levelCommissionMap[lr.Level] = lr.CommissionAmount
|
||||
}
|
||||
|
||||
// 查询各层级的收入金额(从盈利月账单表:total_income)
|
||||
// 先从分润表获取各层级的机构ID列表
|
||||
type deptLevelRow struct {
|
||||
Level int `orm:"level"`
|
||||
DeptId int64 `orm:"dept_id"`
|
||||
}
|
||||
var deptLevelResults []*deptLevelRow
|
||||
if err = handler.Model(dao.TFinCommissionDetail.Ctx(ctx)).
|
||||
Where(dao.TFinCommissionDetail.Columns().BenefitDeptId, deptId).
|
||||
WhereGTE(dao.TFinCommissionDetail.Columns().AccountPeriod, startPeriod).
|
||||
WhereLTE(dao.TFinCommissionDetail.Columns().AccountPeriod, endPeriod).
|
||||
Fields("DISTINCT " + dao.TFinCommissionDetail.Columns().BenefitDeptLevel + " as level, " + dao.TFinCommissionDetail.Columns().BenefitDeptId + " as dept_id").
|
||||
Scan(&deptLevelResults); err != nil {
|
||||
err = gerror.Wrap(err, "查询层级机构失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
|
||||
// 根据层级汇总机构ID
|
||||
levelDeptMap := make(map[int][]int64)
|
||||
for _, dlr := range deptLevelResults {
|
||||
levelDeptMap[dlr.Level] = append(levelDeptMap[dlr.Level], dlr.DeptId)
|
||||
}
|
||||
|
||||
// 构建收入金额映射
|
||||
incomeMap := make(map[int]float64)
|
||||
for level, deptIds := range levelDeptMap {
|
||||
if len(deptIds) == 0 {
|
||||
continue
|
||||
}
|
||||
incomeResult, err := s.getProfitAccountIncome(ctx, &model.IncomeQueryParams{
|
||||
DeptIds: deptIds,
|
||||
StartPeriod: startPeriod,
|
||||
EndPeriod: endPeriod,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
incomeMap[level] = incomeResult
|
||||
}
|
||||
|
||||
// 计算总收入
|
||||
var totalIncome float64
|
||||
for _, item := range levelResults {
|
||||
totalIncome += item.CommissionAmount
|
||||
}
|
||||
|
||||
// 构建结果
|
||||
for level := 1; level <= 3; level++ {
|
||||
item := model.TLevelSummaryItem{
|
||||
Level: level,
|
||||
}
|
||||
|
||||
// 设置客户数、分润金额
|
||||
for _, lr := range levelResults {
|
||||
if lr.Level == level {
|
||||
item.CustomerCount = lr.CustomerCount
|
||||
item.CommissionAmount = lr.CommissionAmount
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 设置收入金额
|
||||
item.IncomeAmount = incomeMap[level]
|
||||
|
||||
// 计算收入占比
|
||||
if totalIncome > 0 {
|
||||
item.IncomeRatio = item.CommissionAmount / totalIncome * 100
|
||||
}
|
||||
|
||||
res.Items = append(res.Items, item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// getProfitAccountIncome 查询盈利账户收入
|
||||
func (s *sCommonTFinCommissionDetail) getProfitAccountIncome(ctx context.Context, params *model.IncomeQueryParams) (float64, error) {
|
||||
type incomeRow struct {
|
||||
TotalIncome float64 `orm:"total_income"`
|
||||
}
|
||||
var row *incomeRow
|
||||
if err := handler.Model(dao.TProfitAccountMonthBill.Ctx(ctx)).
|
||||
WhereIn(dao.TProfitAccountMonthBill.Columns().DeptId, params.DeptIds).
|
||||
WhereGTE(dao.TProfitAccountMonthBill.Columns().AccountPeriod, params.StartPeriod).
|
||||
WhereLTE(dao.TProfitAccountMonthBill.Columns().AccountPeriod, params.EndPeriod).
|
||||
Fields("SUM(" + dao.TProfitAccountMonthBill.Columns().TotalIncome + ") as total_income").
|
||||
Scan(&row); err != nil {
|
||||
return 0, gerror.Wrap(err, "查询盈利账户收入失败")
|
||||
}
|
||||
if row == nil {
|
||||
return 0, nil
|
||||
}
|
||||
return row.TotalIncome, nil
|
||||
}
|
||||
|
||||
// mustAtoi 安全转换字符串为int
|
||||
func mustAtoi(s string) int {
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
||||
Reference in New Issue
Block a user