fix: resolve admin acceptance defects
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
package crons
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"hotgo/internal/library/cron"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cron.Register(DashboardDailySummary)
|
||||
}
|
||||
|
||||
var DashboardDailySummary = &cDashboardDailySummary{name: "dashboard_daily_summary"}
|
||||
|
||||
type cDashboardDailySummary struct{ name string }
|
||||
|
||||
func (c *cDashboardDailySummary) GetName() string { return c.name }
|
||||
|
||||
func (c *cDashboardDailySummary) Execute(ctx context.Context, parser *cron.Parser) error {
|
||||
days := 2
|
||||
if len(parser.Args) > 0 {
|
||||
if value, err := strconv.Atoi(parser.Args[0]); err == nil {
|
||||
days = value
|
||||
}
|
||||
}
|
||||
if err := service.SysDashboard().RefreshDaily(ctx, days); err != nil {
|
||||
parser.Logger.Warningf(ctx, "dashboard daily summary failed days:%d err:%+v", days, err)
|
||||
return err
|
||||
}
|
||||
parser.Logger.Infof(ctx, "dashboard daily summary completed days:%d", days)
|
||||
return nil
|
||||
}
|
||||
@@ -21,54 +21,70 @@ type AppMemberPaymentAccountDao struct {
|
||||
|
||||
// AppMemberPaymentAccountColumns defines and stores column names for the table hg_app_member_payment_account.
|
||||
type AppMemberPaymentAccountColumns struct {
|
||||
Id string // 主键
|
||||
TenantId string // 租户ID
|
||||
MemberId string // 会员ID
|
||||
AccountType string // 账户类型
|
||||
BankCode string // 银行编码
|
||||
BankName string // 银行名称
|
||||
HolderCipher string // 持有人密文
|
||||
HolderMask string // 持有人脱敏值
|
||||
MobileCipher string // 预留手机号密文
|
||||
MobileMask string // 预留手机号脱敏值
|
||||
AccountNoCipher string // 账号密文
|
||||
AccountNoHash string // 账号检索哈希
|
||||
AccountNoMask string // 账号脱敏值
|
||||
QrAttachmentId string // 收款码附件ID
|
||||
VerifyStatus string // 核验状态
|
||||
IsDefault string // 默认账户
|
||||
CreatedBy string // 创建者
|
||||
UpdatedBy string // 更新者
|
||||
DeletedBy string // 删除者
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
DeletedAt string // 删除时间
|
||||
Id string // 主键
|
||||
TenantId string // 租户ID
|
||||
MemberId string // 会员ID
|
||||
AccountType string // 账户类型
|
||||
BankCode string // 银行编码
|
||||
BankName string // 银行名称
|
||||
HolderCipher string // 持有人密文
|
||||
HolderMask string // 持有人脱敏值
|
||||
IdentityNoCipher string // 身份证号密文
|
||||
IdentityNoHash string // 身份证号检索哈希
|
||||
IdentityNoMask string // 身份证号脱敏值
|
||||
MobileCipher string // 预留手机号密文
|
||||
MobileMask string // 预留手机号脱敏值
|
||||
AccountNoCipher string // 账号密文
|
||||
AccountNoHash string // 账号检索哈希
|
||||
AccountNoMask string // 账号脱敏值
|
||||
DigitalRmbCodeCipher string // 数字人民币编码密文
|
||||
DigitalRmbCodeHash string // 数字人民币编码检索哈希
|
||||
DigitalRmbCodeMask string // 数字人民币编码脱敏值
|
||||
QrAttachmentId string // 收款码附件ID
|
||||
WechatQrAttachmentId string // 微信二维码附件ID
|
||||
AlipayQrAttachmentId string // 支付宝二维码附件ID
|
||||
VerifyStatus string // 核验状态
|
||||
IsDefault string // 默认账户
|
||||
CreatedBy string // 创建者
|
||||
UpdatedBy string // 更新者
|
||||
DeletedBy string // 删除者
|
||||
CreatedAt string // 创建时间
|
||||
UpdatedAt string // 更新时间
|
||||
DeletedAt string // 删除时间
|
||||
}
|
||||
|
||||
// appMemberPaymentAccountColumns holds the columns for the table hg_app_member_payment_account.
|
||||
var appMemberPaymentAccountColumns = AppMemberPaymentAccountColumns{
|
||||
Id: "id",
|
||||
TenantId: "tenant_id",
|
||||
MemberId: "member_id",
|
||||
AccountType: "account_type",
|
||||
BankCode: "bank_code",
|
||||
BankName: "bank_name",
|
||||
HolderCipher: "holder_cipher",
|
||||
HolderMask: "holder_mask",
|
||||
MobileCipher: "mobile_cipher",
|
||||
MobileMask: "mobile_mask",
|
||||
AccountNoCipher: "account_no_cipher",
|
||||
AccountNoHash: "account_no_hash",
|
||||
AccountNoMask: "account_no_mask",
|
||||
QrAttachmentId: "qr_attachment_id",
|
||||
VerifyStatus: "verify_status",
|
||||
IsDefault: "is_default",
|
||||
CreatedBy: "created_by",
|
||||
UpdatedBy: "updated_by",
|
||||
DeletedBy: "deleted_by",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
DeletedAt: "deleted_at",
|
||||
Id: "id",
|
||||
TenantId: "tenant_id",
|
||||
MemberId: "member_id",
|
||||
AccountType: "account_type",
|
||||
BankCode: "bank_code",
|
||||
BankName: "bank_name",
|
||||
HolderCipher: "holder_cipher",
|
||||
HolderMask: "holder_mask",
|
||||
IdentityNoCipher: "identity_no_cipher",
|
||||
IdentityNoHash: "identity_no_hash",
|
||||
IdentityNoMask: "identity_no_mask",
|
||||
MobileCipher: "mobile_cipher",
|
||||
MobileMask: "mobile_mask",
|
||||
AccountNoCipher: "account_no_cipher",
|
||||
AccountNoHash: "account_no_hash",
|
||||
AccountNoMask: "account_no_mask",
|
||||
DigitalRmbCodeCipher: "digital_rmb_code_cipher",
|
||||
DigitalRmbCodeHash: "digital_rmb_code_hash",
|
||||
DigitalRmbCodeMask: "digital_rmb_code_mask",
|
||||
QrAttachmentId: "qr_attachment_id",
|
||||
WechatQrAttachmentId: "wechat_qr_attachment_id",
|
||||
AlipayQrAttachmentId: "alipay_qr_attachment_id",
|
||||
VerifyStatus: "verify_status",
|
||||
IsDefault: "is_default",
|
||||
CreatedBy: "created_by",
|
||||
UpdatedBy: "updated_by",
|
||||
DeletedBy: "deleted_by",
|
||||
CreatedAt: "created_at",
|
||||
UpdatedAt: "updated_at",
|
||||
DeletedAt: "deleted_at",
|
||||
}
|
||||
|
||||
// NewAppMemberPaymentAccountDao creates and returns a new DAO object for table data access.
|
||||
|
||||
@@ -25,6 +25,7 @@ type TaskColumns struct {
|
||||
TenantId string // 租户ID
|
||||
TaskNo string // 任务编号
|
||||
HallId string // 任务大厅ID
|
||||
ProductId string // 关联商品ID
|
||||
Title string // 标题
|
||||
Description string // 描述
|
||||
DetailHtml string // 清洗后的任务详情
|
||||
@@ -54,6 +55,7 @@ var taskColumns = TaskColumns{
|
||||
TenantId: "tenant_id",
|
||||
TaskNo: "task_no",
|
||||
HallId: "hall_id",
|
||||
ProductId: "product_id",
|
||||
Title: "title",
|
||||
Description: "description",
|
||||
DetailHtml: "detail_html",
|
||||
|
||||
@@ -321,7 +321,12 @@ func (s *sSysAppMember) Category(ctx context.Context, in *sysin.AppMemberCategor
|
||||
|
||||
func (s *sSysAppMember) PaymentList(ctx context.Context, in *sysin.AppMemberPaymentListInp) (list []*sysin.AppMemberPaymentModel, err error) {
|
||||
c := dao.AppMemberPaymentAccount.Columns()
|
||||
err = s.paymentModel(ctx).Fields(c.Id, c.MemberId, c.AccountType, c.BankCode, c.BankName, c.HolderMask, c.MobileMask, c.AccountNoMask, c.QrAttachmentId, c.VerifyStatus, c.IsDefault, c.CreatedAt, c.UpdatedAt).Where(c.MemberId, in.MemberId).OrderDesc(c.IsDefault).OrderDesc(c.Id).Scan(&list)
|
||||
ac := dao.SysAttachment.Columns()
|
||||
err = s.paymentModel(ctx).As("p").
|
||||
LeftJoin(dao.SysAttachment.Table()+" wq", col("wq", ac.Id)+"="+col("p", c.WechatQrAttachmentId)).
|
||||
LeftJoin(dao.SysAttachment.Table()+" aq", col("aq", ac.Id)+"="+col("p", c.AlipayQrAttachmentId)).
|
||||
Fields(col("p", c.Id), col("p", c.MemberId), col("p", c.AccountType), col("p", c.BankCode), col("p", c.BankName), col("p", c.HolderMask), col("p", c.IdentityNoMask), col("p", c.MobileMask), col("p", c.AccountNoMask), col("p", c.DigitalRmbCodeMask), col("p", c.QrAttachmentId), col("p", c.WechatQrAttachmentId), col("p", c.AlipayQrAttachmentId), fmt.Sprintf("COALESCE(%s,'') wechat_qr_url", col("wq", ac.FileUrl)), fmt.Sprintf("COALESCE(%s,'') alipay_qr_url", col("aq", ac.FileUrl)), col("p", c.VerifyStatus), col("p", c.IsDefault), col("p", c.CreatedAt), col("p", c.UpdatedAt)).
|
||||
Where(col("p", c.MemberId), in.MemberId).OrderDesc(col("p", c.IsDefault)).OrderDesc(col("p", c.Id)).Scan(&list)
|
||||
if err != nil {
|
||||
err = gerror.Wrap(err, "获取收款账户失败")
|
||||
}
|
||||
@@ -330,7 +335,23 @@ func (s *sSysAppMember) PaymentList(ctx context.Context, in *sysin.AppMemberPaym
|
||||
|
||||
func (s *sSysAppMember) PaymentEdit(ctx context.Context, in *sysin.AppMemberPaymentEditInp) error {
|
||||
c := dao.AppMemberPaymentAccount.Columns()
|
||||
data := g.Map{c.MemberId: in.MemberId, c.AccountType: in.AccountType, c.BankCode: in.BankCode, c.BankName: in.BankName, c.QrAttachmentId: in.QrAttachmentId, c.VerifyStatus: in.VerifyStatus, c.IsDefault: in.IsDefault, c.UpdatedBy: contexts.GetUserId(ctx)}
|
||||
attachmentColumns := dao.SysAttachment.Columns()
|
||||
if in.WechatQrAttachmentId == 0 && in.WechatQrUrl != "" {
|
||||
_ = dao.SysAttachment.Ctx(ctx).Fields(attachmentColumns.Id).Where(attachmentColumns.FileUrl, in.WechatQrUrl).OrderDesc(attachmentColumns.Id).Limit(1).Scan(&in.WechatQrAttachmentId)
|
||||
}
|
||||
if in.AlipayQrAttachmentId == 0 && in.AlipayQrUrl != "" {
|
||||
_ = dao.SysAttachment.Ctx(ctx).Fields(attachmentColumns.Id).Where(attachmentColumns.FileUrl, in.AlipayQrUrl).OrderDesc(attachmentColumns.Id).Limit(1).Scan(&in.AlipayQrAttachmentId)
|
||||
}
|
||||
data := g.Map{c.MemberId: in.MemberId, c.AccountType: in.AccountType, c.BankCode: in.BankCode, c.BankName: in.BankName, c.VerifyStatus: in.VerifyStatus, c.IsDefault: in.IsDefault, c.UpdatedBy: contexts.GetUserId(ctx)}
|
||||
if in.QrAttachmentId > 0 {
|
||||
data[c.QrAttachmentId] = in.QrAttachmentId
|
||||
}
|
||||
if in.WechatQrAttachmentId > 0 {
|
||||
data[c.WechatQrAttachmentId] = in.WechatQrAttachmentId
|
||||
}
|
||||
if in.AlipayQrAttachmentId > 0 {
|
||||
data[c.AlipayQrAttachmentId] = in.AlipayQrAttachmentId
|
||||
}
|
||||
if in.Holder != "" {
|
||||
v, e := encrypt.EncryptField(ctx, in.Holder)
|
||||
if e != nil {
|
||||
@@ -347,6 +368,19 @@ func (s *sSysAppMember) PaymentEdit(ctx context.Context, in *sysin.AppMemberPaym
|
||||
data[c.MobileCipher] = v
|
||||
data[c.MobileMask] = encrypt.MaskMobile(in.Mobile)
|
||||
}
|
||||
if in.IdentityNo != "" {
|
||||
v, e := encrypt.EncryptField(ctx, in.IdentityNo)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
h, e := encrypt.HashField(ctx, in.IdentityNo)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
data[c.IdentityNoCipher] = v
|
||||
data[c.IdentityNoHash] = h
|
||||
data[c.IdentityNoMask] = encrypt.MaskAccount(in.IdentityNo)
|
||||
}
|
||||
if in.AccountNo != "" {
|
||||
v, e := encrypt.EncryptField(ctx, in.AccountNo)
|
||||
if e != nil {
|
||||
@@ -360,6 +394,19 @@ func (s *sSysAppMember) PaymentEdit(ctx context.Context, in *sysin.AppMemberPaym
|
||||
data[c.AccountNoHash] = h
|
||||
data[c.AccountNoMask] = encrypt.MaskAccount(in.AccountNo)
|
||||
}
|
||||
if in.DigitalRMBCode != "" {
|
||||
v, e := encrypt.EncryptField(ctx, in.DigitalRMBCode)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
h, e := encrypt.HashField(ctx, in.DigitalRMBCode)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
data[c.DigitalRmbCodeCipher] = v
|
||||
data[c.DigitalRmbCodeHash] = h
|
||||
data[c.DigitalRmbCodeMask] = encrypt.MaskAccount(in.DigitalRMBCode)
|
||||
}
|
||||
if in.IsDefault == 1 {
|
||||
_, _ = s.paymentModel(ctx).Where(c.MemberId, in.MemberId).Data(g.Map{c.IsDefault: 2}).Update()
|
||||
}
|
||||
@@ -370,7 +417,7 @@ func (s *sSysAppMember) PaymentEdit(ctx context.Context, in *sysin.AppMemberPaym
|
||||
}
|
||||
} else {
|
||||
data[c.CreatedBy] = contexts.GetUserId(ctx)
|
||||
_, err := s.paymentModel(ctx).Fields(c.MemberId, c.AccountType, c.BankCode, c.BankName, c.HolderCipher, c.HolderMask, c.MobileCipher, c.MobileMask, c.AccountNoCipher, c.AccountNoHash, c.AccountNoMask, c.QrAttachmentId, c.VerifyStatus, c.IsDefault, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(data).Insert()
|
||||
_, err := s.paymentModel(ctx).Fields(c.MemberId, c.AccountType, c.BankCode, c.BankName, c.HolderCipher, c.HolderMask, c.IdentityNoCipher, c.IdentityNoHash, c.IdentityNoMask, c.MobileCipher, c.MobileMask, c.AccountNoCipher, c.AccountNoHash, c.AccountNoMask, c.DigitalRmbCodeCipher, c.DigitalRmbCodeHash, c.DigitalRmbCodeMask, c.QrAttachmentId, c.WechatQrAttachmentId, c.AlipayQrAttachmentId, c.VerifyStatus, c.IsDefault, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(data).Insert()
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "创建收款账户失败")
|
||||
}
|
||||
@@ -465,8 +512,25 @@ func (s *sSysAppMember) Sensitive(ctx context.Context, in *sysin.AppMemberSensit
|
||||
var row *entity.AppMemberPaymentAccount
|
||||
if err = s.paymentModel(ctx).WherePri(in.TargetId).Scan(&row); err == nil && row != nil {
|
||||
res.Fields["holder"], _ = encrypt.DecryptField(ctx, row.HolderCipher)
|
||||
res.Fields["identityNo"], _ = encrypt.DecryptField(ctx, row.IdentityNoCipher)
|
||||
res.Fields["mobile"], _ = encrypt.DecryptField(ctx, row.MobileCipher)
|
||||
res.Fields["accountNo"], err = encrypt.DecryptField(ctx, row.AccountNoCipher)
|
||||
res.Fields["accountNo"], _ = encrypt.DecryptField(ctx, row.AccountNoCipher)
|
||||
res.Fields["digitalRmbCode"], _ = encrypt.DecryptField(ctx, row.DigitalRmbCodeCipher)
|
||||
if res.Fields["holder"] == "" {
|
||||
res.Fields["holder"] = row.HolderMask
|
||||
}
|
||||
if res.Fields["identityNo"] == "" {
|
||||
res.Fields["identityNo"] = row.IdentityNoMask
|
||||
}
|
||||
if res.Fields["mobile"] == "" {
|
||||
res.Fields["mobile"] = row.MobileMask
|
||||
}
|
||||
if res.Fields["accountNo"] == "" {
|
||||
res.Fields["accountNo"] = row.AccountNoMask
|
||||
}
|
||||
if res.Fields["digitalRmbCode"] == "" {
|
||||
res.Fields["digitalRmbCode"] = row.DigitalRmbCodeMask
|
||||
}
|
||||
}
|
||||
case "address":
|
||||
var row *entity.AppMemberAddress
|
||||
|
||||
@@ -2,6 +2,8 @@ package sys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/library/hgorm/handler"
|
||||
"hotgo/internal/model/entity"
|
||||
@@ -11,10 +13,20 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"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/gtime"
|
||||
)
|
||||
|
||||
type dashboardAggregateSpec struct {
|
||||
DimensionType string
|
||||
DimensionValue string
|
||||
MetricCode string
|
||||
SQL string
|
||||
Args []interface{}
|
||||
}
|
||||
|
||||
const (
|
||||
dashboardDimensionGlobal = "global"
|
||||
dashboardDimensionChannel = "channel"
|
||||
@@ -54,6 +66,97 @@ func NewSysDashboard() *sSysDashboard { return &sSysDashboard{} }
|
||||
|
||||
func init() { service.RegisterSysDashboard(NewSysDashboard()) }
|
||||
|
||||
// RefreshDaily rebuilds recent dashboard snapshots from business source tables.
|
||||
func (s *sSysDashboard) RefreshDaily(ctx context.Context, days int) error {
|
||||
if days < 1 {
|
||||
days = 1
|
||||
}
|
||||
if days > 90 {
|
||||
days = 90
|
||||
}
|
||||
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
||||
for offset := days - 1; offset >= 0; offset-- {
|
||||
day := time.Now().AddDate(0, 0, -offset)
|
||||
start := time.Date(day.Year(), day.Month(), day.Day(), 0, 0, 0, 0, day.Location())
|
||||
end := start.AddDate(0, 0, 1)
|
||||
if err := s.refreshDashboardDay(ctx, start, end); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *sSysDashboard) refreshDashboardDay(ctx context.Context, start, end time.Time) error {
|
||||
dc := dao.DashboardDailyStat.Columns()
|
||||
if _, err := dao.DashboardDailyStat.Ctx(ctx).Where(dc.StatDate, start.Format("2006-01-02")).Delete(); err != nil {
|
||||
return gerror.Wrap(err, "清理看板日汇总失败")
|
||||
}
|
||||
mc, pc, oc := dao.AppMember.Columns(), dao.Product.Columns(), dao.TradeOrder.Columns()
|
||||
rc, wc, lc := dao.RechargeOrder.Columns(), dao.WithdrawalOrder.Columns(), dao.WalletLedger.Columns()
|
||||
wac, cc := dao.WalletAccount.Columns(), dao.PaymentChannel.Columns()
|
||||
specs := []dashboardAggregateSpec{
|
||||
{dashboardDimensionGlobal, "all", "member_total", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,0 metric_amount FROM %s WHERE %s IS NULL AND %s<? GROUP BY %s", mc.TenantId, dao.AppMember.Table(), mc.DeletedAt, mc.CreatedAt, mc.TenantId), []interface{}{end}},
|
||||
{dashboardDimensionGlobal, "all", "member_new", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,0 metric_amount FROM %s WHERE %s IS NULL AND %s>=? AND %s<? GROUP BY %s", mc.TenantId, dao.AppMember.Table(), mc.DeletedAt, mc.CreatedAt, mc.CreatedAt, mc.TenantId), []interface{}{start, end}},
|
||||
{dashboardDimensionGlobal, "all", "product_total", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,0 metric_amount FROM %s WHERE %s IS NULL AND %s<? GROUP BY %s", pc.TenantId, dao.Product.Table(), pc.DeletedAt, pc.CreatedAt, pc.TenantId), []interface{}{end}},
|
||||
{dashboardDimensionGlobal, "all", "trade_order", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s>=? AND %s<? GROUP BY %s", oc.TenantId, oc.TotalAmount, dao.TradeOrder.Table(), oc.CreatedAt, oc.CreatedAt, oc.TenantId), []interface{}{start, end}},
|
||||
{dashboardDimensionGlobal, "all", "recharge_member", fmt.Sprintf("SELECT %s tenant_id,COUNT(DISTINCT %s) metric_count,0 metric_amount FROM %s WHERE %s=? AND %s>=? AND %s<? GROUP BY %s", rc.TenantId, rc.MemberId, dao.RechargeOrder.Table(), rc.RechargeStatus, rc.CreditedAt, rc.CreditedAt, rc.TenantId), []interface{}{consts.RechargeSuccess, start, end}},
|
||||
{dashboardDimensionGlobal, "all", "recharge_success", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s=? AND %s>=? AND %s<? GROUP BY %s", rc.TenantId, rc.PaidAmount, dao.RechargeOrder.Table(), rc.RechargeStatus, rc.CreditedAt, rc.CreditedAt, rc.TenantId), []interface{}{consts.RechargeSuccess, start, end}},
|
||||
{dashboardDimensionGlobal, "all", "recharge_pending", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s IN (?,?) AND %s<? GROUP BY %s", rc.TenantId, rc.RequestAmount, dao.RechargeOrder.Table(), rc.RechargeStatus, rc.CreatedAt, rc.TenantId), []interface{}{consts.RechargeUnpaid, consts.RechargeReview, end}},
|
||||
{dashboardDimensionGlobal, "all", "withdrawal_success", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s=? AND %s>=? AND %s<? GROUP BY %s", wc.TenantId, wc.ActualAmount, dao.WithdrawalOrder.Table(), wc.WithdrawalStatus, wc.CompletedAt, wc.CompletedAt, wc.TenantId), []interface{}{consts.WithdrawalSuccess, start, end}},
|
||||
{dashboardDimensionGlobal, "all", "withdrawal_pending", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s IN (?,?,?) AND %s<? GROUP BY %s", wc.TenantId, wc.ActualAmount, dao.WithdrawalOrder.Table(), wc.WithdrawalStatus, wc.CreatedAt, wc.TenantId), []interface{}{consts.WithdrawalPending, consts.WithdrawalReviewing, consts.WithdrawalProcessing, end}},
|
||||
{dashboardDimensionGlobal, "all", "commission", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s='commission' AND %s>=? AND %s<? GROUP BY %s", lc.TenantId, lc.Amount, dao.WalletLedger.Table(), lc.BizType, lc.OccurredAt, lc.OccurredAt, lc.TenantId), []interface{}{start, end}},
|
||||
{dashboardDimensionGlobal, "all", "referral_commission", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s='referral_commission' AND %s>=? AND %s<? GROUP BY %s", lc.TenantId, lc.Amount, dao.WalletLedger.Table(), lc.BizType, lc.OccurredAt, lc.OccurredAt, lc.TenantId), []interface{}{start, end}},
|
||||
{dashboardDimensionGlobal, "all", "interest_transfer", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s='interest_transfer' AND %s>=? AND %s<? GROUP BY %s", lc.TenantId, lc.Amount, dao.WalletLedger.Table(), lc.BizType, lc.OccurredAt, lc.OccurredAt, lc.TenantId), []interface{}{start, end}},
|
||||
{dashboardDimensionGlobal, "all", "wallet_available", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s='CNY' GROUP BY %s", wac.TenantId, wac.AvailableAmount, dao.WalletAccount.Table(), wac.Currency, wac.TenantId), nil},
|
||||
{dashboardDimensionGlobal, "all", "wallet_frozen", fmt.Sprintf("SELECT %s tenant_id,COUNT(*) metric_count,COALESCE(SUM(%s),0) metric_amount FROM %s WHERE %s='CNY' GROUP BY %s", wac.TenantId, wac.FrozenAmount, dao.WalletAccount.Table(), wac.Currency, wac.TenantId), nil},
|
||||
}
|
||||
for _, spec := range specs {
|
||||
if err := s.insertDashboardAggregate(ctx, start, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
channelSpecs := []dashboardAggregateSpec{
|
||||
{dashboardDimensionChannel, "", "recharge_success", fmt.Sprintf("SELECT r.%s tenant_id,COUNT(*) metric_count,COALESCE(SUM(r.%s),0) metric_amount,c.%s dimension_value FROM %s r LEFT JOIN %s c ON c.%s=r.%s WHERE r.%s=? AND r.%s>=? AND r.%s<? GROUP BY r.%s,c.%s", rc.TenantId, rc.PaidAmount, cc.ChannelCode, dao.RechargeOrder.Table(), dao.PaymentChannel.Table(), cc.Id, rc.ChannelId, rc.RechargeStatus, rc.CreditedAt, rc.CreditedAt, rc.TenantId, cc.ChannelCode), []interface{}{consts.RechargeSuccess, start, end}},
|
||||
{dashboardDimensionChannel, "", "withdrawal_success", fmt.Sprintf("SELECT w.%s tenant_id,COUNT(*) metric_count,COALESCE(SUM(w.%s),0) metric_amount,c.%s dimension_value FROM %s w LEFT JOIN %s c ON c.%s=w.%s WHERE w.%s=? AND w.%s>=? AND w.%s<? GROUP BY w.%s,c.%s", wc.TenantId, wc.ActualAmount, cc.ChannelCode, dao.WithdrawalOrder.Table(), dao.PaymentChannel.Table(), cc.Id, wc.ChannelId, wc.WithdrawalStatus, wc.CompletedAt, wc.CompletedAt, wc.TenantId, cc.ChannelCode), []interface{}{consts.WithdrawalSuccess, start, end}},
|
||||
}
|
||||
for _, spec := range channelSpecs {
|
||||
if err := s.insertDashboardAggregate(ctx, start, spec); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sSysDashboard) insertDashboardAggregate(ctx context.Context, day time.Time, spec dashboardAggregateSpec) error {
|
||||
type row struct {
|
||||
TenantId uint64 `orm:"tenant_id"`
|
||||
MetricCount int64 `orm:"metric_count"`
|
||||
MetricAmount int64 `orm:"metric_amount"`
|
||||
DimensionValue string `orm:"dimension_value"`
|
||||
}
|
||||
var rows []*row
|
||||
if err := g.DB().Ctx(ctx).Raw(spec.SQL, spec.Args...).Scan(&rows); err != nil {
|
||||
return gerror.Wrapf(err, "汇总看板指标失败 metric:%s", spec.MetricCode)
|
||||
}
|
||||
c := dao.DashboardDailyStat.Columns()
|
||||
now := gtime.Now()
|
||||
for _, item := range rows {
|
||||
dimensionValue := spec.DimensionValue
|
||||
if item.DimensionValue != "" {
|
||||
dimensionValue = item.DimensionValue
|
||||
}
|
||||
if dimensionValue == "" {
|
||||
dimensionValue = "unknown"
|
||||
}
|
||||
_, err := dao.DashboardDailyStat.Ctx(ctx).Fields(c.TenantId, c.StatDate, c.DimensionType, c.DimensionValue, c.MetricCode, c.MetricCount, c.MetricAmount, c.CalculatedAt, c.CreatedAt, c.UpdatedAt).Data(g.Map{c.TenantId: item.TenantId, c.StatDate: day.Format("2006-01-02"), c.DimensionType: spec.DimensionType, c.DimensionValue: dimensionValue, c.MetricCode: spec.MetricCode, c.MetricCount: item.MetricCount, c.MetricAmount: item.MetricAmount, c.CalculatedAt: now, c.CreatedAt: now, c.UpdatedAt: now}).Insert()
|
||||
if err != nil {
|
||||
return gerror.Wrapf(err, "写入看板指标失败 metric:%s", spec.MetricCode)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sSysDashboard) Summary(ctx context.Context, in *sysin.DashboardSummaryInp) (res *sysin.DashboardSummaryModel, err error) {
|
||||
start, end := normalizeDashboardRange(in)
|
||||
days := int(end.Sub(start).Hours()/24) + 1
|
||||
|
||||
@@ -498,7 +498,6 @@ func (s *sSysPortal) ManualProductEdit(ctx context.Context, in *sysin.ManualProd
|
||||
c.PriceAmount: in.PriceAmount,
|
||||
c.CoverAttachmentId: in.CoverAttachmentId,
|
||||
c.CoverUrl: in.CoverUrl,
|
||||
c.PublishStatus: consts.BizPublishPublished,
|
||||
c.UpdatedBy: userId,
|
||||
c.Version: gdb.Raw(c.Version + "+1"),
|
||||
}).Update()
|
||||
@@ -512,7 +511,7 @@ func (s *sSysPortal) ManualProductEdit(ctx context.Context, in *sysin.ManualProd
|
||||
return in.Id, nil
|
||||
}
|
||||
in.ProductNo = "MP" + gtime.Now().Format("YmdHis") + grand.S(5)
|
||||
in.PublishStatus = consts.BizPublishPublished
|
||||
in.PublishStatus = consts.BizPublishDraft
|
||||
in.CreatedBy = userId
|
||||
in.UpdatedBy = userId
|
||||
result, e := s.productModel(ctx).Fields(c.ProductNo, c.CategoryId, c.ProductType, c.PaymentType, c.Name, c.ShopName, c.PriceAmount, c.Currency, c.CoverAttachmentId, c.CoverUrl, c.DetailHtml, c.IsRecommended, c.PublishStatus, c.StartAt, c.EndAt, c.Sort, c.Version, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(in).Insert()
|
||||
|
||||
@@ -40,8 +40,10 @@ func (s *sSysRechargeOrder) baseModel(ctx context.Context) *gdb.Model {
|
||||
|
||||
func (s *sSysRechargeOrder) listModel(ctx context.Context) *gdb.Model {
|
||||
rc, mc, pc, wc, cc := dao.RechargeOrder.Columns(), dao.AppMember.Columns(), dao.AppMemberProfile.Columns(), dao.WalletAccount.Columns(), dao.PaymentChannel.Columns()
|
||||
ac := dao.AppMemberPaymentAccount.Columns()
|
||||
realName := fmt.Sprintf("COALESCE(NULLIF(%s,''),(SELECT %s FROM %s pa WHERE pa.%s=%s AND pa.%s IS NULL ORDER BY pa.%s ASC,pa.%s DESC LIMIT 1),'') real_name_mask", col("p", pc.RealNameMask), ac.HolderMask, dao.AppMemberPaymentAccount.Table(), ac.MemberId, col("r", rc.MemberId), ac.DeletedAt, ac.IsDefault, ac.Id)
|
||||
return s.baseModel(ctx).
|
||||
Fields(col("r", rc.Id), col("r", rc.RechargeNo), col("r", rc.MemberId), col("m", mc.Username), col("m", mc.Mobile), col("p", pc.RealNameMask), fmt.Sprintf("COALESCE(%s,0) available_amount", col("w", wc.AvailableAmount)), col("r", rc.ChannelId), fmt.Sprintf("COALESCE(%s,'') channel_name", col("c", cc.Name)), col("r", rc.RequestAmount), col("r", rc.PaidAmount), col("r", rc.Currency), col("r", rc.ExternalNo), col("r", rc.VoucherAttachmentIds), col("r", rc.RechargeType), col("r", rc.RechargeStatus), col("r", rc.Remark), col("r", rc.ReviewReasonCode), col("r", rc.ReviewReason), col("r", rc.ApprovalRequestId), col("r", rc.LedgerId), col("r", rc.PaidAt), col("r", rc.ReviewedAt), col("r", rc.CreditedAt), col("r", rc.CreatedAt))
|
||||
Fields(col("r", rc.Id), col("r", rc.RechargeNo), col("r", rc.MemberId), col("m", mc.Username), col("m", mc.Mobile), realName, fmt.Sprintf("COALESCE(%s,0) available_amount", col("w", wc.AvailableAmount)), col("r", rc.ChannelId), fmt.Sprintf("COALESCE(%s,'') channel_name", col("c", cc.Name)), col("r", rc.RequestAmount), col("r", rc.PaidAmount), col("r", rc.Currency), col("r", rc.ExternalNo), col("r", rc.VoucherAttachmentIds), col("r", rc.RechargeType), col("r", rc.RechargeStatus), col("r", rc.Remark), col("r", rc.ReviewReasonCode), col("r", rc.ReviewReason), col("r", rc.ApprovalRequestId), col("r", rc.LedgerId), col("r", rc.PaidAt), col("r", rc.ReviewedAt), col("r", rc.CreditedAt), col("r", rc.CreatedAt))
|
||||
}
|
||||
|
||||
func (s *sSysRechargeOrder) filter(ctx context.Context, mod *gdb.Model, in *sysin.RechargeOrderListInp) (*gdb.Model, error) {
|
||||
|
||||
@@ -31,8 +31,11 @@ func (s *sSysTask) relationModel(ctx context.Context) *gdb.Model {
|
||||
return handler.Model(dao.TaskLevel.Ctx(ctx), &handler.Option{FilterTenant: true})
|
||||
}
|
||||
func (s *sSysTask) listModel(ctx context.Context) *gdb.Model {
|
||||
tc, hc := dao.Task.Columns(), dao.TaskHall.Columns()
|
||||
return s.Model(ctx).As("t").LeftJoin(dao.TaskHall.Table()+" h", col("h", hc.Id)+"="+col("t", tc.HallId)).Fields("t.*", fmt.Sprintf("COALESCE(%s,'') hall_name", col("h", hc.Name)))
|
||||
tc, hc, pc := dao.Task.Columns(), dao.TaskHall.Columns(), dao.Product.Columns()
|
||||
return s.Model(ctx).As("t").
|
||||
LeftJoin(dao.TaskHall.Table()+" h", col("h", hc.Id)+"="+col("t", tc.HallId)).
|
||||
LeftJoin(dao.Product.Table()+" p", col("p", pc.Id)+"="+col("t", tc.ProductId)).
|
||||
Fields("t.*", fmt.Sprintf("COALESCE(%s,'') hall_name", col("h", hc.Name)), fmt.Sprintf("COALESCE(%s,'') product_name", col("p", pc.Name)))
|
||||
}
|
||||
func (s *sSysTask) List(ctx context.Context, in *sysin.TaskListInp) (list []*sysin.TaskListModel, total int, err error) {
|
||||
tc := dao.Task.Columns()
|
||||
@@ -106,6 +109,14 @@ func (s *sSysTask) Edit(ctx context.Context, in *sysin.TaskEditInp) (id uint64,
|
||||
if hallCount == 0 {
|
||||
return 0, gerror.New("任务大厅不存在")
|
||||
}
|
||||
pc := dao.Product.Columns()
|
||||
productCount, err := handler.Model(dao.Product.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(in.ProductId).WhereIn(pc.PublishStatus, []int{consts.BizPublishPublished, consts.BizPublishOffline, consts.BizPublishDraft}).Count()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if productCount == 0 {
|
||||
return 0, gerror.New("关联商品不存在")
|
||||
}
|
||||
lc := dao.AppMemberLevel.Columns()
|
||||
levelCount, err := handler.Model(dao.AppMemberLevel.Ctx(ctx), &handler.Option{FilterTenant: true}).WhereIn(lc.Id, in.LevelIds).Where(lc.Status, consts.StatusEnabled).Count()
|
||||
if err != nil {
|
||||
@@ -125,7 +136,7 @@ func (s *sSysTask) Edit(ctx context.Context, in *sysin.TaskEditInp) (id uint64,
|
||||
if before == nil {
|
||||
return gerror.New("任务不存在")
|
||||
}
|
||||
result, e := s.Model(ctx).WherePri(in.Id).Where(c.Version, in.Version).Fields(sysin.TaskUpdateFields{}).Data(g.Map{c.HallId: in.HallId, c.Title: in.Title, c.Description: in.Description, c.DetailHtml: in.DetailHtml, c.CoverAttachmentId: in.CoverAttachmentId, c.CoverUrl: in.CoverUrl, c.CommissionAmount: in.CommissionAmount, c.CommissionRate: in.CommissionRate, c.DailyLimit: in.DailyLimit, c.PerMemberLimit: in.PerMemberLimit, c.StartAt: in.StartAt, c.EndAt: in.EndAt, c.Sort: in.Sort, c.Remark: in.Remark, c.UpdatedBy: uid, c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||||
result, e := s.Model(ctx).WherePri(in.Id).Where(c.Version, in.Version).Fields(sysin.TaskUpdateFields{}).Data(g.Map{c.HallId: in.HallId, c.ProductId: in.ProductId, c.Title: in.Title, c.Description: in.Description, c.DetailHtml: in.DetailHtml, c.CoverAttachmentId: in.CoverAttachmentId, c.CoverUrl: in.CoverUrl, c.CommissionAmount: in.CommissionAmount, c.CommissionRate: in.CommissionRate, c.DailyLimit: in.DailyLimit, c.PerMemberLimit: in.PerMemberLimit, c.StartAt: in.StartAt, c.EndAt: in.EndAt, c.Sort: in.Sort, c.Remark: in.Remark, c.UpdatedBy: uid, c.Version: gdb.Raw(c.Version + "+1")}).Update()
|
||||
if e != nil {
|
||||
return gerror.Wrap(e, "更新任务失败")
|
||||
}
|
||||
@@ -136,7 +147,7 @@ func (s *sSysTask) Edit(ctx context.Context, in *sysin.TaskEditInp) (id uint64,
|
||||
id = in.Id
|
||||
} else {
|
||||
taskNo := "TK" + gtime.Now().Format("YmdHis") + grand.S(5)
|
||||
result, e := s.Model(ctx).Fields(c.TaskNo, c.HallId, c.Title, c.Description, c.DetailHtml, c.CoverAttachmentId, c.CoverUrl, c.CommissionAmount, c.CommissionRate, c.DailyLimit, c.PerMemberLimit, c.StartAt, c.EndAt, c.PublishStatus, c.Sort, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(g.Map{c.TaskNo: taskNo, c.HallId: in.HallId, c.Title: in.Title, c.Description: in.Description, c.DetailHtml: in.DetailHtml, c.CoverAttachmentId: in.CoverAttachmentId, c.CoverUrl: in.CoverUrl, c.CommissionAmount: in.CommissionAmount, c.CommissionRate: in.CommissionRate, c.DailyLimit: in.DailyLimit, c.PerMemberLimit: in.PerMemberLimit, c.StartAt: in.StartAt, c.EndAt: in.EndAt, c.PublishStatus: consts.BizPublishDraft, c.Sort: in.Sort, c.Remark: in.Remark, c.CreatedBy: uid, c.UpdatedBy: uid}).Insert()
|
||||
result, e := s.Model(ctx).Fields(c.TaskNo, c.HallId, c.ProductId, c.Title, c.Description, c.DetailHtml, c.CoverAttachmentId, c.CoverUrl, c.CommissionAmount, c.CommissionRate, c.DailyLimit, c.PerMemberLimit, c.StartAt, c.EndAt, c.PublishStatus, c.Sort, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(g.Map{c.TaskNo: taskNo, c.HallId: in.HallId, c.ProductId: in.ProductId, c.Title: in.Title, c.Description: in.Description, c.DetailHtml: in.DetailHtml, c.CoverAttachmentId: in.CoverAttachmentId, c.CoverUrl: in.CoverUrl, c.CommissionAmount: in.CommissionAmount, c.CommissionRate: in.CommissionRate, c.DailyLimit: in.DailyLimit, c.PerMemberLimit: in.PerMemberLimit, c.StartAt: in.StartAt, c.EndAt: in.EndAt, c.PublishStatus: consts.BizPublishDraft, c.Sort: in.Sort, c.Remark: in.Remark, c.CreatedBy: uid, c.UpdatedBy: uid}).Insert()
|
||||
if e != nil {
|
||||
return gerror.Wrap(e, "创建任务失败")
|
||||
}
|
||||
@@ -152,7 +163,7 @@ func (s *sSysTask) Edit(ctx context.Context, in *sysin.TaskEditInp) (id uint64,
|
||||
return gerror.Wrap(e, "保存任务等级失败")
|
||||
}
|
||||
}
|
||||
return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "task", Action: "task.edit", TargetType: "task", TargetId: id, Before: before, After: g.Map{"title": in.Title, "commissionAmount": in.CommissionAmount, "levelIds": in.LevelIds}})
|
||||
return service.SysBizAudit().Record(ctx, &sysin.BizAuditRecordInp{Module: "task", Action: "task.edit", TargetType: "task", TargetId: id, Before: before, After: g.Map{"title": in.Title, "productId": in.ProductId, "commissionAmount": in.CommissionAmount, "levelIds": in.LevelIds}})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ func (s *sSysTaskHall) Edit(ctx context.Context, in *sysin.TaskHallEditInp) erro
|
||||
return gerror.New("大厅数据已更新,请刷新后重试")
|
||||
}
|
||||
} else {
|
||||
data[c.PublishStatus] = consts.BizPublishPublished
|
||||
data[c.PublishStatus] = consts.BizPublishDraft
|
||||
data[c.CreatedBy] = userId
|
||||
result, err := s.model(ctx).Fields(c.HallCode, c.Name, c.IconAttachmentId, c.IconUrl, c.Summary, c.CommissionRate, c.RateUnit, c.ClientRoute, c.PublishStatus, c.Sort, c.Remark, c.CreatedBy, c.UpdatedBy).Hook(hook.SaveTenant).Data(data).Insert()
|
||||
if err != nil {
|
||||
|
||||
@@ -28,8 +28,13 @@ func (s *sSysTaskSubmission) Model(ctx context.Context) *gdb.Model {
|
||||
return handler.Model(dao.TaskSubmission.Ctx(ctx), &handler.Option{FilterTenant: true})
|
||||
}
|
||||
func (s *sSysTaskSubmission) listModel(ctx context.Context) *gdb.Model {
|
||||
sc, tc, mc, lc := dao.TaskSubmission.Columns(), dao.Task.Columns(), dao.AppMember.Columns(), dao.AppMemberLevel.Columns()
|
||||
return s.Model(ctx).As("s").LeftJoin(dao.Task.Table()+" t", col("t", tc.Id)+"="+col("s", sc.TaskId)).LeftJoin(dao.AppMember.Table()+" m", col("m", mc.Id)+"="+col("s", sc.MemberId)).LeftJoin(dao.AppMemberLevel.Table()+" l", col("l", lc.Id)+"="+col("s", sc.MemberLevelId)).Fields(col("s", sc.Id), col("s", sc.SubmissionNo), col("s", sc.TradeOrderId), col("s", sc.TaskId), fmt.Sprintf("COALESCE(%s,'') task_title", col("t", tc.Title)), col("s", sc.MemberId), col("m", mc.Username), col("m", mc.Mobile), fmt.Sprintf("COALESCE(%s,'') level_name", col("l", lc.Name)), col("s", sc.EvidenceText), col("s", sc.EvidenceAttachmentIds), col("s", sc.SubmissionStatus), col("s", sc.CommissionAmount), col("s", sc.SuccessRate), col("s", sc.ReviewReasonCode), col("s", sc.ReviewReason), col("s", sc.AllowResubmit), col("s", sc.LedgerId), col("s", sc.ReviewedAt), col("s", sc.SettledAt), col("s", sc.CreatedAt))
|
||||
sc, tc, oc, mc, lc := dao.TaskSubmission.Columns(), dao.Task.Columns(), dao.TradeOrder.Columns(), dao.AppMember.Columns(), dao.AppMemberLevel.Columns()
|
||||
return s.Model(ctx).As("s").
|
||||
LeftJoin(dao.Task.Table()+" t", col("t", tc.Id)+"="+col("s", sc.TaskId)).
|
||||
LeftJoin(dao.TradeOrder.Table()+" o", col("o", oc.Id)+"="+col("s", sc.TradeOrderId)).
|
||||
LeftJoin(dao.AppMember.Table()+" m", col("m", mc.Id)+"="+col("s", sc.MemberId)).
|
||||
LeftJoin(dao.AppMemberLevel.Table()+" l", col("l", lc.Id)+"="+col("s", sc.MemberLevelId)).
|
||||
Fields(col("s", sc.Id), col("s", sc.SubmissionNo), col("s", sc.TradeOrderId), fmt.Sprintf("COALESCE(%s,'') trade_order_no", col("o", oc.OrderNo)), fmt.Sprintf("COALESCE(%s,'') product_name", col("o", oc.ProductName)), col("s", sc.TaskId), fmt.Sprintf("COALESCE(NULLIF(%s,''),NULLIF(%s,''),'') task_title", col("t", tc.Title), col("o", oc.ProductName)), col("s", sc.MemberId), col("m", mc.Username), col("m", mc.Mobile), fmt.Sprintf("COALESCE(%s,'') level_name", col("l", lc.Name)), col("s", sc.EvidenceText), col("s", sc.EvidenceAttachmentIds), col("s", sc.SubmissionStatus), col("s", sc.CommissionAmount), col("s", sc.SuccessRate), col("s", sc.ReviewReasonCode), col("s", sc.ReviewReason), col("s", sc.AllowResubmit), col("s", sc.LedgerId), col("s", sc.ReviewedAt), col("s", sc.SettledAt), col("s", sc.CreatedAt))
|
||||
}
|
||||
func (s *sSysTaskSubmission) filter(ctx context.Context, mod *gdb.Model, in *sysin.TaskSubmissionListInp) (*gdb.Model, error) {
|
||||
sc, mc := dao.TaskSubmission.Columns(), dao.AppMember.Columns()
|
||||
@@ -82,12 +87,27 @@ func (s *sSysTaskSubmission) Review(ctx context.Context, in *sysin.TaskSubmissio
|
||||
if submission.SubmissionStatus != consts.TaskSubmissionPending {
|
||||
return gerror.New("该记录已审核,请勿重复操作")
|
||||
}
|
||||
var task *entity.Task
|
||||
if err := handler.Model(dao.Task.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(submission.TaskId).Scan(&task); err != nil {
|
||||
return err
|
||||
if submission.TaskId > 0 {
|
||||
var task *entity.Task
|
||||
if err := handler.Model(dao.Task.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(submission.TaskId).Scan(&task); err != nil {
|
||||
return err
|
||||
}
|
||||
if task == nil {
|
||||
return gerror.New("关联任务不存在")
|
||||
}
|
||||
}
|
||||
if task == nil {
|
||||
return gerror.New("关联任务不存在")
|
||||
if submission.TradeOrderId > 0 {
|
||||
oc := dao.TradeOrder.Columns()
|
||||
count, err := handler.Model(dao.TradeOrder.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(submission.TradeOrderId).Where(oc.MemberId, submission.MemberId).Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count == 0 {
|
||||
return gerror.New("关联订单不存在或不属于该会员")
|
||||
}
|
||||
}
|
||||
if submission.TaskId == 0 && submission.TradeOrderId == 0 {
|
||||
return gerror.New("提交记录缺少任务和订单关联")
|
||||
}
|
||||
var member *entity.AppMember
|
||||
if err := handler.Model(dao.AppMember.Ctx(ctx), &handler.Option{FilterTenant: true}).WherePri(submission.MemberId).Scan(&member); err != nil {
|
||||
|
||||
@@ -56,6 +56,12 @@ func (s *sSysTradeOrder) List(ctx context.Context, in *sysin.TradeOrderListInp)
|
||||
if in.Mobile != "" {
|
||||
mod = mod.Where(col("m", mc.Mobile), in.Mobile)
|
||||
}
|
||||
if in.AutoDispatch == consts.TradeAutoDispatchEnabled {
|
||||
mod = mod.Where("COALESCE(JSON_UNQUOTE(JSON_EXTRACT("+col("o", oc.RuleSnapshot)+",'$.dispatch_mode')),'') = ?", "auto")
|
||||
}
|
||||
if in.AutoDispatch == consts.TradeAutoDispatchDisabled {
|
||||
mod = mod.Where("COALESCE(JSON_UNQUOTE(JSON_EXTRACT("+col("o", oc.RuleSnapshot)+",'$.dispatch_mode')),'') = ?", "manual")
|
||||
}
|
||||
if in.OrderStatus > 0 {
|
||||
mod = mod.Where(col("o", oc.OrderStatus), in.OrderStatus)
|
||||
}
|
||||
@@ -92,7 +98,27 @@ func (s *sSysTradeOrder) View(ctx context.Context, in *sysin.TradeOrderViewInp)
|
||||
if err = s.model(ctx).WherePri(in.Id).Scan(&order); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = &sysin.TradeOrderViewModel{TradeOrderListModel: *base, TaskId: order.TaskId, ProductId: order.ProductId, MemberLevelId: order.MemberLevelId, RuleSnapshot: order.RuleSnapshot}
|
||||
res = &sysin.TradeOrderViewModel{TradeOrderListModel: *base, TaskId: order.TaskId, ProductId: order.ProductId, MemberLevelId: order.MemberLevelId, RuleSnapshot: order.RuleSnapshot, UpdatedAt: order.UpdatedAt}
|
||||
res.Timeline = []*sysin.TradeOrderTimelineModel{{Title: "订单创建", Time: order.CreatedAt}}
|
||||
if order.MatchedAt != nil {
|
||||
res.Timeline = append(res.Timeline, &sysin.TradeOrderTimelineModel{Title: "订单匹配", Time: order.MatchedAt})
|
||||
}
|
||||
if order.CompletedAt != nil {
|
||||
res.Timeline = append(res.Timeline, &sysin.TradeOrderTimelineModel{Title: "订单完成", Time: order.CompletedAt})
|
||||
}
|
||||
if order.UnfrozenAt != nil {
|
||||
res.Timeline = append(res.Timeline, &sysin.TradeOrderTimelineModel{Title: "订单解冻", Time: order.UnfrozenAt})
|
||||
}
|
||||
lc := dao.WalletLedger.Columns()
|
||||
if err = handler.Model(dao.WalletLedger.Ctx(ctx), &handler.Option{FilterTenant: true}).Fields(lc.LedgerNo, lc.BizType, lc.Direction, lc.Amount, lc.BeforeAmount, lc.AfterAmount, lc.Remark, lc.OccurredAt).Where(lc.BizNo, order.OrderNo).OrderAsc(lc.Id).Scan(&res.Ledgers); err != nil {
|
||||
return nil, gerror.Wrap(err, "获取订单资金流水失败")
|
||||
}
|
||||
if order.ApprovalRequestId > 0 {
|
||||
ac := dao.ApprovalAction.Columns()
|
||||
if err = handler.Model(dao.ApprovalAction.Ctx(ctx), &handler.Option{FilterTenant: true}).Fields(ac.StepNo, ac.ActorId, ac.Action, ac.Comment, ac.CreatedAt).Where(ac.ApprovalRequestId, order.ApprovalRequestId).OrderAsc(ac.StepNo).OrderAsc(ac.Id).Scan(&res.ApprovalActions); err != nil {
|
||||
return nil, gerror.Wrap(err, "获取订单审批记录失败")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -11,27 +11,35 @@ import (
|
||||
|
||||
// AppMemberPaymentAccount is the golang structure of table hg_app_member_payment_account for DAO operations like Where/Data.
|
||||
type AppMemberPaymentAccount struct {
|
||||
g.Meta `orm:"table:hg_app_member_payment_account, do:true"`
|
||||
Id any // 主键
|
||||
TenantId any // 租户ID
|
||||
MemberId any // 会员ID
|
||||
AccountType any // 账户类型
|
||||
BankCode any // 银行编码
|
||||
BankName any // 银行名称
|
||||
HolderCipher any // 持有人密文
|
||||
HolderMask any // 持有人脱敏值
|
||||
MobileCipher any // 预留手机号密文
|
||||
MobileMask any // 预留手机号脱敏值
|
||||
AccountNoCipher any // 账号密文
|
||||
AccountNoHash any // 账号检索哈希
|
||||
AccountNoMask any // 账号脱敏值
|
||||
QrAttachmentId any // 收款码附件ID
|
||||
VerifyStatus any // 核验状态
|
||||
IsDefault any // 默认账户
|
||||
CreatedBy any // 创建者
|
||||
UpdatedBy any // 更新者
|
||||
DeletedBy any // 删除者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
DeletedAt *gtime.Time // 删除时间
|
||||
g.Meta `orm:"table:hg_app_member_payment_account, do:true"`
|
||||
Id any // 主键
|
||||
TenantId any // 租户ID
|
||||
MemberId any // 会员ID
|
||||
AccountType any // 账户类型
|
||||
BankCode any // 银行编码
|
||||
BankName any // 银行名称
|
||||
HolderCipher any // 持有人密文
|
||||
HolderMask any // 持有人脱敏值
|
||||
IdentityNoCipher any // 身份证号密文
|
||||
IdentityNoHash any // 身份证号检索哈希
|
||||
IdentityNoMask any // 身份证号脱敏值
|
||||
MobileCipher any // 预留手机号密文
|
||||
MobileMask any // 预留手机号脱敏值
|
||||
AccountNoCipher any // 账号密文
|
||||
AccountNoHash any // 账号检索哈希
|
||||
AccountNoMask any // 账号脱敏值
|
||||
DigitalRmbCodeCipher any // 数字人民币编码密文
|
||||
DigitalRmbCodeHash any // 数字人民币编码检索哈希
|
||||
DigitalRmbCodeMask any // 数字人民币编码脱敏值
|
||||
QrAttachmentId any // 收款码附件ID
|
||||
WechatQrAttachmentId any // 微信二维码附件ID
|
||||
AlipayQrAttachmentId any // 支付宝二维码附件ID
|
||||
VerifyStatus any // 核验状态
|
||||
IsDefault any // 默认账户
|
||||
CreatedBy any // 创建者
|
||||
UpdatedBy any // 更新者
|
||||
DeletedBy any // 删除者
|
||||
CreatedAt *gtime.Time // 创建时间
|
||||
UpdatedAt *gtime.Time // 更新时间
|
||||
DeletedAt *gtime.Time // 删除时间
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ type Task struct {
|
||||
TenantId any // 租户ID
|
||||
TaskNo any // 任务编号
|
||||
HallId any // 任务大厅ID
|
||||
ProductId any // 关联商品ID
|
||||
Title any // 标题
|
||||
Description any // 描述
|
||||
DetailHtml any // 清洗后的任务详情
|
||||
|
||||
@@ -10,26 +10,34 @@ import (
|
||||
|
||||
// AppMemberPaymentAccount is the golang structure for table app_member_payment_account.
|
||||
type AppMemberPaymentAccount struct {
|
||||
Id uint64 `json:"id" orm:"id" description:"主键"`
|
||||
TenantId uint64 `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
MemberId uint64 `json:"memberId" orm:"member_id" description:"会员ID"`
|
||||
AccountType int `json:"accountType" orm:"account_type" description:"账户类型"`
|
||||
BankCode string `json:"bankCode" orm:"bank_code" description:"银行编码"`
|
||||
BankName string `json:"bankName" orm:"bank_name" description:"银行名称"`
|
||||
HolderCipher string `json:"holderCipher" orm:"holder_cipher" description:"持有人密文"`
|
||||
HolderMask string `json:"holderMask" orm:"holder_mask" description:"持有人脱敏值"`
|
||||
MobileCipher string `json:"mobileCipher" orm:"mobile_cipher" description:"预留手机号密文"`
|
||||
MobileMask string `json:"mobileMask" orm:"mobile_mask" description:"预留手机号脱敏值"`
|
||||
AccountNoCipher string `json:"accountNoCipher" orm:"account_no_cipher" description:"账号密文"`
|
||||
AccountNoHash string `json:"accountNoHash" orm:"account_no_hash" description:"账号检索哈希"`
|
||||
AccountNoMask string `json:"accountNoMask" orm:"account_no_mask" description:"账号脱敏值"`
|
||||
QrAttachmentId uint64 `json:"qrAttachmentId" orm:"qr_attachment_id" description:"收款码附件ID"`
|
||||
VerifyStatus int `json:"verifyStatus" orm:"verify_status" description:"核验状态"`
|
||||
IsDefault int `json:"isDefault" orm:"is_default" description:"默认账户"`
|
||||
CreatedBy uint64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
UpdatedBy uint64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
DeletedBy uint64 `json:"deletedBy" orm:"deleted_by" description:"删除者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"删除时间"`
|
||||
Id uint64 `json:"id" orm:"id" description:"主键"`
|
||||
TenantId uint64 `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
MemberId uint64 `json:"memberId" orm:"member_id" description:"会员ID"`
|
||||
AccountType int `json:"accountType" orm:"account_type" description:"账户类型"`
|
||||
BankCode string `json:"bankCode" orm:"bank_code" description:"银行编码"`
|
||||
BankName string `json:"bankName" orm:"bank_name" description:"银行名称"`
|
||||
HolderCipher string `json:"holderCipher" orm:"holder_cipher" description:"持有人密文"`
|
||||
HolderMask string `json:"holderMask" orm:"holder_mask" description:"持有人脱敏值"`
|
||||
IdentityNoCipher string `json:"identityNoCipher" orm:"identity_no_cipher" description:"身份证号密文"`
|
||||
IdentityNoHash string `json:"identityNoHash" orm:"identity_no_hash" description:"身份证号检索哈希"`
|
||||
IdentityNoMask string `json:"identityNoMask" orm:"identity_no_mask" description:"身份证号脱敏值"`
|
||||
MobileCipher string `json:"mobileCipher" orm:"mobile_cipher" description:"预留手机号密文"`
|
||||
MobileMask string `json:"mobileMask" orm:"mobile_mask" description:"预留手机号脱敏值"`
|
||||
AccountNoCipher string `json:"accountNoCipher" orm:"account_no_cipher" description:"账号密文"`
|
||||
AccountNoHash string `json:"accountNoHash" orm:"account_no_hash" description:"账号检索哈希"`
|
||||
AccountNoMask string `json:"accountNoMask" orm:"account_no_mask" description:"账号脱敏值"`
|
||||
DigitalRmbCodeCipher string `json:"digitalRmbCodeCipher" orm:"digital_rmb_code_cipher" description:"数字人民币编码密文"`
|
||||
DigitalRmbCodeHash string `json:"digitalRmbCodeHash" orm:"digital_rmb_code_hash" description:"数字人民币编码检索哈希"`
|
||||
DigitalRmbCodeMask string `json:"digitalRmbCodeMask" orm:"digital_rmb_code_mask" description:"数字人民币编码脱敏值"`
|
||||
QrAttachmentId uint64 `json:"qrAttachmentId" orm:"qr_attachment_id" description:"收款码附件ID"`
|
||||
WechatQrAttachmentId uint64 `json:"wechatQrAttachmentId" orm:"wechat_qr_attachment_id" description:"微信二维码附件ID"`
|
||||
AlipayQrAttachmentId uint64 `json:"alipayQrAttachmentId" orm:"alipay_qr_attachment_id" description:"支付宝二维码附件ID"`
|
||||
VerifyStatus int `json:"verifyStatus" orm:"verify_status" description:"核验状态"`
|
||||
IsDefault int `json:"isDefault" orm:"is_default" description:"默认账户"`
|
||||
CreatedBy uint64 `json:"createdBy" orm:"created_by" description:"创建者"`
|
||||
UpdatedBy uint64 `json:"updatedBy" orm:"updated_by" description:"更新者"`
|
||||
DeletedBy uint64 `json:"deletedBy" orm:"deleted_by" description:"删除者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"删除时间"`
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ type Task struct {
|
||||
TenantId uint64 `json:"tenantId" orm:"tenant_id" description:"租户ID"`
|
||||
TaskNo string `json:"taskNo" orm:"task_no" description:"任务编号"`
|
||||
HallId uint64 `json:"hallId" orm:"hall_id" description:"任务大厅ID"`
|
||||
ProductId uint64 `json:"productId" orm:"product_id" description:"关联商品ID"`
|
||||
Title string `json:"title" orm:"title" description:"标题"`
|
||||
Description string `json:"description" orm:"description" description:"描述"`
|
||||
DetailHtml string `json:"detailHtml" orm:"detail_html" description:"清洗后的任务详情"`
|
||||
|
||||
@@ -164,32 +164,44 @@ type AppMemberPaymentListInp struct {
|
||||
func (in *AppMemberPaymentListInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type AppMemberPaymentModel struct {
|
||||
Id uint64 `json:"id"`
|
||||
MemberId uint64 `json:"memberId"`
|
||||
AccountType int `json:"accountType"`
|
||||
BankCode string `json:"bankCode"`
|
||||
BankName string `json:"bankName"`
|
||||
HolderMask string `json:"holderMask"`
|
||||
MobileMask string `json:"mobileMask"`
|
||||
AccountNoMask string `json:"accountNoMask"`
|
||||
QrAttachmentId uint64 `json:"qrAttachmentId"`
|
||||
VerifyStatus int `json:"verifyStatus"`
|
||||
IsDefault int `json:"isDefault"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt"`
|
||||
Id uint64 `json:"id"`
|
||||
MemberId uint64 `json:"memberId"`
|
||||
AccountType int `json:"accountType"`
|
||||
BankCode string `json:"bankCode"`
|
||||
BankName string `json:"bankName"`
|
||||
HolderMask string `json:"holderMask"`
|
||||
IdentityNoMask string `json:"identityNoMask"`
|
||||
MobileMask string `json:"mobileMask"`
|
||||
AccountNoMask string `json:"accountNoMask"`
|
||||
DigitalRMBCodeMask string `json:"digitalRmbCodeMask"`
|
||||
QrAttachmentId uint64 `json:"qrAttachmentId"`
|
||||
WechatQrAttachmentId uint64 `json:"wechatQrAttachmentId"`
|
||||
AlipayQrAttachmentId uint64 `json:"alipayQrAttachmentId"`
|
||||
WechatQrUrl string `json:"wechatQrUrl"`
|
||||
AlipayQrUrl string `json:"alipayQrUrl"`
|
||||
VerifyStatus int `json:"verifyStatus"`
|
||||
IsDefault int `json:"isDefault"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt"`
|
||||
}
|
||||
type AppMemberPaymentEditInp struct {
|
||||
Id uint64 `json:"id"`
|
||||
MemberId uint64 `json:"memberId" v:"required|min:1#会员ID不能为空|会员ID不能为空"`
|
||||
AccountType int `json:"accountType" v:"required#账户类型不能为空"`
|
||||
BankCode string `json:"bankCode" v:"max-length:32#银行编码不能超过32个字符"`
|
||||
BankName string `json:"bankName" v:"max-length:100#银行名称不能超过100个字符"`
|
||||
Holder string `json:"holder"`
|
||||
Mobile string `json:"mobile" v:"phone-loose#手机号格式不正确"`
|
||||
AccountNo string `json:"accountNo"`
|
||||
QrAttachmentId uint64 `json:"qrAttachmentId"`
|
||||
VerifyStatus int `json:"verifyStatus" d:"1"`
|
||||
IsDefault int `json:"isDefault" d:"2"`
|
||||
Id uint64 `json:"id"`
|
||||
MemberId uint64 `json:"memberId" v:"required|min:1#会员ID不能为空|会员ID不能为空"`
|
||||
AccountType int `json:"accountType" v:"required#账户类型不能为空"`
|
||||
BankCode string `json:"bankCode" v:"max-length:32#银行编码不能超过32个字符"`
|
||||
BankName string `json:"bankName" v:"max-length:100#银行名称不能超过100个字符"`
|
||||
Holder string `json:"holder"`
|
||||
IdentityNo string `json:"identityNo"`
|
||||
Mobile string `json:"mobile" v:"phone-loose#手机号格式不正确"`
|
||||
AccountNo string `json:"accountNo"`
|
||||
DigitalRMBCode string `json:"digitalRmbCode"`
|
||||
QrAttachmentId uint64 `json:"qrAttachmentId"`
|
||||
WechatQrAttachmentId uint64 `json:"wechatQrAttachmentId"`
|
||||
AlipayQrAttachmentId uint64 `json:"alipayQrAttachmentId"`
|
||||
WechatQrUrl string `json:"wechatQrUrl"`
|
||||
AlipayQrUrl string `json:"alipayQrUrl"`
|
||||
VerifyStatus int `json:"verifyStatus" d:"1"`
|
||||
IsDefault int `json:"isDefault" d:"2"`
|
||||
}
|
||||
|
||||
func (in *AppMemberPaymentEditInp) Filter(ctx context.Context) error {
|
||||
|
||||
@@ -55,14 +55,12 @@ func (in *SiteConfigSaveInp) Filter(ctx context.Context) error {
|
||||
if strings.TrimSpace(in.Config.SiteName) == "" {
|
||||
return gerror.New("站点名称不能为空")
|
||||
}
|
||||
if in.Config.PrivacyPolicyUrl != "" {
|
||||
u, err := url.Parse(in.Config.PrivacyPolicyUrl)
|
||||
if err != nil || u.Scheme != "https" || u.Host == "" {
|
||||
return gerror.New("隐私政策地址必须是有效的 HTTPS 地址")
|
||||
}
|
||||
u, err := url.Parse(in.Config.PrivacyPolicyUrl)
|
||||
if err != nil || u.Scheme != "https" || u.Host == "" {
|
||||
return gerror.New("隐私政策地址不能为空且必须是有效的 HTTPS 地址")
|
||||
}
|
||||
if in.Config.TradeWaitSeconds < 0 || in.Config.DailyTradeLimit < 0 || in.Config.DailyRewardLimit < 0 {
|
||||
return gerror.New("交易等待时间和每日次数不能为负数")
|
||||
if in.Config.TradeBalanceAmount <= 0 || in.Config.TradeWaitSeconds <= 0 || in.Config.DailyTradeLimit <= 0 || in.Config.DailyRewardLimit <= 0 || in.Config.MinimumRechargeAmount <= 0 {
|
||||
return gerror.New("交易余额、支付等待时长、每日次数和最低充值金额必须大于0")
|
||||
}
|
||||
if len(in.Config.CommissionRates) != 6 {
|
||||
return gerror.New("必须配置 0 至 5 级共 6 个佣金比例")
|
||||
@@ -77,11 +75,11 @@ func (in *SiteConfigSaveInp) Filter(ctx context.Context) error {
|
||||
if total > 1 {
|
||||
return gerror.New("各级佣金比例总和不能超过 100%")
|
||||
}
|
||||
if in.Config.AutoOrderDelaySeconds < 0 {
|
||||
return gerror.New("自动派单时间不能为负数")
|
||||
if in.Config.AutoOrderDelaySeconds <= 0 {
|
||||
return gerror.New("自动派单时间必须大于0")
|
||||
}
|
||||
if in.Config.AutoOrderMinAmount < 0 || in.Config.AutoOrderMaxAmount < in.Config.AutoOrderMinAmount {
|
||||
return gerror.New("自动派单最大金额不能小于最小金额")
|
||||
if in.Config.AutoOrderMinAmount <= 0 || in.Config.AutoOrderMaxAmount < in.Config.AutoOrderMinAmount {
|
||||
return gerror.New("自动派单金额必须大于0,且最大金额不能小于最小金额")
|
||||
}
|
||||
for _, ranges := range [][]string{in.Config.WithdrawTimeRanges, in.Config.RechargeTimeRanges, in.Config.TradeTimeRanges, in.Config.SignTimeRanges} {
|
||||
for _, value := range ranges {
|
||||
|
||||
@@ -123,6 +123,7 @@ func (in *ProductDeleteInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type TaskUpdateFields struct {
|
||||
HallId uint64
|
||||
ProductId uint64
|
||||
Title string
|
||||
Description string
|
||||
DetailHtml string
|
||||
@@ -157,10 +158,11 @@ func (in *TaskListInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type TaskListModel struct {
|
||||
entity.Task
|
||||
HallName string `json:"hallName"`
|
||||
LevelIds []uint64 `json:"levelIds"`
|
||||
LevelNames []string `json:"levelNames"`
|
||||
Referenced bool `json:"referenced"`
|
||||
HallName string `json:"hallName"`
|
||||
ProductName string `json:"productName"`
|
||||
LevelIds []uint64 `json:"levelIds"`
|
||||
LevelNames []string `json:"levelNames"`
|
||||
Referenced bool `json:"referenced"`
|
||||
}
|
||||
type TaskViewInp struct {
|
||||
Id uint64 `json:"id" v:"required|min:1#任务ID不能为空|任务ID不能为空"`
|
||||
@@ -178,8 +180,8 @@ func (in *TaskEditInp) Filter(ctx context.Context) error {
|
||||
if strings.TrimSpace(in.Title) == "" || strings.TrimSpace(in.Description) == "" || strings.TrimSpace(in.CoverUrl) == "" {
|
||||
return gerror.New("任务标题、描述和封面不能为空")
|
||||
}
|
||||
if in.HallId == 0 || len(in.LevelIds) == 0 {
|
||||
return gerror.New("请选择任务大厅和会员等级")
|
||||
if in.HallId == 0 || in.ProductId == 0 || len(in.LevelIds) == 0 {
|
||||
return gerror.New("请选择关联商品、任务大厅和会员等级")
|
||||
}
|
||||
if in.PerMemberLimit == 0 {
|
||||
return gerror.New("单会员任务限制必须大于0")
|
||||
@@ -231,6 +233,8 @@ type TaskSubmissionListModel struct {
|
||||
Id uint64 `json:"id"`
|
||||
SubmissionNo string `json:"submissionNo"`
|
||||
TradeOrderId uint64 `json:"tradeOrderId"`
|
||||
TradeOrderNo string `json:"tradeOrderNo"`
|
||||
ProductName string `json:"productName"`
|
||||
TaskId uint64 `json:"taskId"`
|
||||
TaskTitle string `json:"taskTitle"`
|
||||
MemberId uint64 `json:"memberId"`
|
||||
|
||||
@@ -16,11 +16,12 @@ import (
|
||||
|
||||
type TradeOrderListInp struct {
|
||||
form.PageReq
|
||||
OrderNo string `json:"orderNo"`
|
||||
Username string `json:"username"`
|
||||
Mobile string `json:"mobile"`
|
||||
OrderStatus int `json:"orderStatus"`
|
||||
CreatedAt []*gtime.Time `json:"createdAt"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
Username string `json:"username"`
|
||||
Mobile string `json:"mobile"`
|
||||
AutoDispatch int `json:"autoDispatch"`
|
||||
OrderStatus int `json:"orderStatus"`
|
||||
CreatedAt []*gtime.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
func (in *TradeOrderListInp) Filter(ctx context.Context) error { return nil }
|
||||
@@ -70,10 +71,36 @@ func (in *TradeOrderViewInp) Filter(ctx context.Context) error { return nil }
|
||||
|
||||
type TradeOrderViewModel struct {
|
||||
TradeOrderListModel
|
||||
TaskId uint64 `json:"taskId"`
|
||||
ProductId uint64 `json:"productId"`
|
||||
MemberLevelId uint64 `json:"memberLevelId"`
|
||||
RuleSnapshot *gjson.Json `json:"ruleSnapshot"`
|
||||
TaskId uint64 `json:"taskId"`
|
||||
ProductId uint64 `json:"productId"`
|
||||
MemberLevelId uint64 `json:"memberLevelId"`
|
||||
RuleSnapshot *gjson.Json `json:"ruleSnapshot"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt"`
|
||||
Timeline []*TradeOrderTimelineModel `json:"timeline"`
|
||||
Ledgers []*TradeOrderLedgerModel `json:"ledgers"`
|
||||
ApprovalActions []*TradeOrderApprovalActionModel `json:"approvalActions"`
|
||||
}
|
||||
|
||||
type TradeOrderTimelineModel struct {
|
||||
Title string `json:"title"`
|
||||
Time *gtime.Time `json:"time"`
|
||||
}
|
||||
type TradeOrderLedgerModel struct {
|
||||
LedgerNo string `json:"ledgerNo"`
|
||||
BizType string `json:"bizType"`
|
||||
Direction int `json:"direction"`
|
||||
Amount int64 `json:"amount"`
|
||||
BeforeAmount int64 `json:"beforeAmount"`
|
||||
AfterAmount int64 `json:"afterAmount"`
|
||||
Remark string `json:"remark"`
|
||||
OccurredAt *gtime.Time `json:"occurredAt"`
|
||||
}
|
||||
type TradeOrderApprovalActionModel struct {
|
||||
StepNo uint `json:"stepNo"`
|
||||
ActorId uint64 `json:"actorId"`
|
||||
Action int `json:"action"`
|
||||
Comment string `json:"comment"`
|
||||
CreatedAt *gtime.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
type TradeOrderApplyInp struct {
|
||||
|
||||
@@ -167,6 +167,7 @@ type (
|
||||
}
|
||||
ISysDashboard interface {
|
||||
Summary(ctx context.Context, in *sysin.DashboardSummaryInp) (res *sysin.DashboardSummaryModel, err error)
|
||||
RefreshDaily(ctx context.Context, days int) (err error)
|
||||
}
|
||||
ISysBizAudit interface {
|
||||
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 360" role="img" aria-label="Olons 平台横幅">
|
||||
<defs><linearGradient id="g" x1="0" x2="1"><stop stop-color="#1ba8ee"/><stop offset="1" stop-color="#3136dc"/></linearGradient></defs>
|
||||
<rect width="1200" height="360" rx="28" fill="url(#g)"/>
|
||||
<circle cx="1010" cy="70" r="180" fill="#fff" opacity=".10"/><circle cx="1120" cy="320" r="220" fill="#fff" opacity=".08"/>
|
||||
<text x="90" y="160" fill="#fff" font-size="66" font-family="Arial, sans-serif" font-weight="700">OLONS</text>
|
||||
<text x="92" y="230" fill="#fff" font-size="34" font-family="Arial, sans-serif" opacity=".9">精选商品 · 安心服务</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 680 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" role="img" aria-label="Olons 商品占位图">
|
||||
<defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#eaf7ff"/><stop offset="1" stop-color="#dfe3ff"/></linearGradient></defs>
|
||||
<rect width="800" height="800" rx="48" fill="url(#g)"/>
|
||||
<path d="M220 300h360l-28 300H248z" fill="#fff" stroke="#2878e8" stroke-width="22"/>
|
||||
<path d="M310 315c0-118 180-118 180 0" fill="none" stroke="#2878e8" stroke-width="22" stroke-linecap="round"/>
|
||||
<text x="400" y="690" text-anchor="middle" fill="#2878e8" font-size="54" font-family="Arial, sans-serif" font-weight="700">OLONS</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 663 B |
@@ -0,0 +1,15 @@
|
||||
-- 任务明确关联一个已发布商品,便于创建、审核和订单追溯。
|
||||
ALTER TABLE `hg_task`
|
||||
ADD COLUMN `product_id` bigint unsigned NOT NULL DEFAULT 0 COMMENT '关联商品ID' AFTER `hall_id`,
|
||||
ADD INDEX `idx_task_product_id` (`product_id`);
|
||||
|
||||
-- 历史任务从已生成的交易订单中回填最常用的商品,无法判断的保持 0 并在后台补录。
|
||||
UPDATE `hg_task` t
|
||||
LEFT JOIN (
|
||||
SELECT `task_id`, MAX(`product_id`) AS `product_id`
|
||||
FROM `hg_trade_order`
|
||||
WHERE `task_id` > 0 AND `product_id` > 0
|
||||
GROUP BY `task_id`
|
||||
) o ON o.`task_id` = t.`id`
|
||||
SET t.`product_id` = COALESCE(o.`product_id`, 0)
|
||||
WHERE t.`product_id` = 0;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- 使用 HotGo 自带定时任务管理,每 10 分钟重算今天和昨天的经营看板。
|
||||
INSERT INTO `hg_sys_cron`
|
||||
(`group_id`,`title`,`name`,`params`,`pattern`,`policy`,`count`,`sort`,`remark`,`status`,`created_at`,`updated_at`)
|
||||
SELECT 1,'经营看板日汇总','dashboard_daily_summary','2','0 */10 * * * *',2,1,20,
|
||||
'汇总会员、商品、订单、充值、提现和钱包数据;参数为重算天数',1,NOW(),NOW()
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `hg_sys_cron` WHERE `name`='dashboard_daily_summary');
|
||||
@@ -0,0 +1,17 @@
|
||||
-- 补全历史站点配置中的无效空值;金额单位均为分。
|
||||
UPDATE `hg_site_config_version`
|
||||
SET `config_json` = JSON_SET(
|
||||
`config_json`,
|
||||
'$.siteName', IF(COALESCE(JSON_UNQUOTE(JSON_EXTRACT(`config_json`,'$.siteName')),'')='' OR JSON_UNQUOTE(JSON_EXTRACT(`config_json`,'$.siteName')) LIKE '演示站点%', 'Olons', JSON_UNQUOTE(JSON_EXTRACT(`config_json`,'$.siteName'))),
|
||||
'$.privacyPolicyUrl', IF(COALESCE(JSON_UNQUOTE(JSON_EXTRACT(`config_json`,'$.privacyPolicyUrl')),'')='', 'https://olns-web.118im.com/admin/#/app/content/privacy_policy', JSON_UNQUOTE(JSON_EXTRACT(`config_json`,'$.privacyPolicyUrl'))),
|
||||
'$.tradeBalanceAmount', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.tradeBalanceAmount'),0)<=0,10000,JSON_EXTRACT(`config_json`,'$.tradeBalanceAmount')),
|
||||
'$.tradeWaitSeconds', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.tradeWaitSeconds'),0)<=0,1200,JSON_EXTRACT(`config_json`,'$.tradeWaitSeconds')),
|
||||
'$.dailyTradeLimit', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.dailyTradeLimit'),0)<=0,30,JSON_EXTRACT(`config_json`,'$.dailyTradeLimit')),
|
||||
'$.dailyRewardLimit', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.dailyRewardLimit'),0)<=0,3,JSON_EXTRACT(`config_json`,'$.dailyRewardLimit')),
|
||||
'$.minimumRechargeAmount', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.minimumRechargeAmount'),0)<=0,10000,JSON_EXTRACT(`config_json`,'$.minimumRechargeAmount')),
|
||||
'$.autoOrderDelaySeconds', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.autoOrderDelaySeconds'),0)<=0,10,JSON_EXTRACT(`config_json`,'$.autoOrderDelaySeconds')),
|
||||
'$.autoOrderMinAmount', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.autoOrderMinAmount'),0)<=0,100,JSON_EXTRACT(`config_json`,'$.autoOrderMinAmount')),
|
||||
'$.autoOrderMaxAmount', IF(COALESCE(JSON_EXTRACT(`config_json`,'$.autoOrderMaxAmount'),0)<=0,10000000,JSON_EXTRACT(`config_json`,'$.autoOrderMaxAmount')),
|
||||
'$.commissionRates', IF(JSON_LENGTH(COALESCE(JSON_EXTRACT(`config_json`,'$.commissionRates'),JSON_ARRAY()))<>6,JSON_ARRAY(0.10,0.05,0.03,0.02,0.01,0),JSON_EXTRACT(`config_json`,'$.commissionRates'))
|
||||
), `updated_at`=NOW()
|
||||
WHERE `config_group`='portal';
|
||||
@@ -0,0 +1,8 @@
|
||||
-- 为历史空图片记录提供可随服务部署的本地占位资源,后续运营可正常替换。
|
||||
UPDATE `hg_banner`
|
||||
SET `image_url`='/images/olons-banner.svg', `updated_at`=NOW()
|
||||
WHERE `deleted_at` IS NULL AND COALESCE(`image_url`,'')='';
|
||||
|
||||
UPDATE `hg_product`
|
||||
SET `cover_url`='/images/olons-product.svg', `updated_at`=NOW()
|
||||
WHERE `deleted_at` IS NULL AND COALESCE(`cover_url`,'')='';
|
||||
Reference in New Issue
Block a user