商城c端前端

This commit is contained in:
richjohnrambo
2026-10-12 23:26:36 +08:00
parent 8f3a97a54d
commit dd729cb679
17 changed files with 744 additions and 41 deletions
+4
View File
@@ -25,6 +25,10 @@ var (
ErrWithdrawalAmount = errors.New("withdrawal amount invalid")
ErrWithdrawalLimit = errors.New("withdrawal daily limit reached")
ErrWithdrawalNotFound = errors.New("withdrawal order not found")
ErrRechargeChannel = errors.New("recharge channel unavailable")
ErrRechargeAmount = errors.New("recharge amount invalid")
ErrRechargeNotFound = errors.New("recharge order not found")
ErrRechargeVoucher = errors.New("recharge voucher invalid")
ErrIdempotencyConflict = errors.New("idempotency key reused with different request")
ErrNoTaskAvailable = errors.New("no task available")
ErrOrderNotFound = errors.New("task order not found")
+4
View File
@@ -20,6 +20,8 @@ type ManualProduct struct {
CoverURL string `db:"cover_url"`
DetailHTML string `db:"detail_html"`
IsRecommended bool `db:"is_recommended"`
StartAt string `db:"start_at"`
EndAt string `db:"end_at"`
ClaimedCount int64 `db:"claimed_count"`
CreatedAt string `db:"created_at"`
UpdatedAt string `db:"updated_at"`
@@ -69,6 +71,8 @@ func manualProductSelectSQL() string {
return `SELECT p.id,p.product_no,p.category_id,c.category_code,c.name AS category_name,
p.payment_type,p.name,p.shop_name,p.price_amount,p.currency,p.cover_url,
COALESCE(p.detail_html,'') AS detail_html,(p.is_recommended=1) AS is_recommended,
COALESCE(DATE_FORMAT(p.start_at,'%Y-%m-%dT%H:%i:%sZ'),'') AS start_at,
COALESCE(DATE_FORMAT(p.end_at,'%Y-%m-%dT%H:%i:%sZ'),'') AS end_at,
(SELECT COUNT(*) FROM hg_trade_order o WHERE o.tenant_id=p.tenant_id AND o.product_id=p.id
AND o.order_type=3 AND o.order_status NOT IN (7,8)) AS claimed_count,
DATE_FORMAT(p.created_at,'%Y-%m-%dT%H:%i:%sZ') AS created_at,
+47
View File
@@ -61,6 +61,24 @@ type TaskSummary struct {
YesterdayCommissionAmount int64 `db:"yesterday_commission_amount" json:"yesterday_commission_amount"`
}
type LeaderboardMember struct {
MemberID int64 `db:"member_id"`
Username string `db:"username"`
AvatarURL string `db:"avatar_url"`
CompletedCount int64 `db:"completed_count"`
}
type CustomerService struct {
ID int64 `db:"id"`
ServiceCode string `db:"service_code"`
Name string `db:"name"`
AvatarURL string `db:"avatar_url"`
WorkTime string `db:"work_time"`
OnlineStatus int `db:"online_status"`
ServiceURL string `db:"service_url"`
BackupContact string `db:"backup_contact"`
}
func (s *Store) CurrentSiteConfig(ctx context.Context, tenantID int64) (json.RawMessage, error) {
if s == nil || s.db == nil {
return nil, errors.New("store is unavailable")
@@ -151,3 +169,32 @@ func (s *Store) MemberTaskSummary(ctx context.Context, tenantID, memberID int64)
tenantID, memberID, tenantID, memberID, tenantID, memberID)
return &row, err
}
func (s *Store) TaskLeaderboard(ctx context.Context, tenantID int64, limit int) ([]LeaderboardMember, error) {
if s == nil || s.db == nil {
return nil, errors.New("store is unavailable")
}
rows := make([]LeaderboardMember, 0)
err := s.db.SelectContext(ctx, &rows, `SELECT m.id AS member_id,m.username,
COALESCE(a.file_url,'') AS avatar_url,COUNT(o.id) AS completed_count
FROM hg_app_member m
LEFT JOIN hg_app_member_profile p ON p.tenant_id=m.tenant_id AND p.member_id=m.id
LEFT JOIN hg_sys_attachment a ON a.id=p.avatar_attachment_id AND a.status=1
JOIN hg_trade_order o ON o.tenant_id=m.tenant_id AND o.member_id=m.id
AND o.order_type=2 AND o.order_status=4
WHERE m.tenant_id=? AND m.member_status=1 AND m.deleted_at IS NULL
GROUP BY m.id,m.username,a.file_url
ORDER BY completed_count DESC,m.id ASC LIMIT ?`, tenantID, limit)
return rows, err
}
func (s *Store) ActiveCustomerServices(ctx context.Context, tenantID int64) ([]CustomerService, error) {
if s == nil || s.db == nil {
return nil, errors.New("store is unavailable")
}
rows := make([]CustomerService, 0)
err := s.db.SelectContext(ctx, &rows, `SELECT id,service_code,name,avatar_url,work_time,
online_status,service_url,backup_contact FROM hg_customer_service
WHERE tenant_id=? AND status=1 AND deleted_at IS NULL ORDER BY sort ASC,id ASC`, tenantID)
return rows, err
}
+6 -6
View File
@@ -262,10 +262,10 @@ func (s *Store) ClaimTask(ctx context.Context, input ClaimTaskInput) (*TaskOrder
result, err := tx.ExecContext(ctx, `INSERT INTO hg_trade_order
(tenant_id,order_no,member_id,task_id,product_id,product_name,order_type,quantity,
unit_price_amount,total_amount,commission_amount,currency,member_level_id,rule_snapshot,
message,order_status,freeze_status,created_by,updated_by)
VALUES(?,?,?,?,0,?,2,1,0,0,?,'CNY',?,?,?,1,1,0,0)`,
message,order_status,freeze_status,matched_at,created_by,updated_by)
VALUES(?,?,?,?,0,?,2,1,0,0,?,'CNY',?,?,?,2,1,UTC_TIMESTAMP(3),0,0)`,
input.TenantID, input.OrderNo, input.MemberID, task.ID, task.Title, task.CommissionAmount,
member.LevelID, rules, "等待系统匹配")
member.LevelID, rules, "任务匹配成功,请在截止时间前完成")
if err != nil {
if isDuplicate(err) {
return nil, ErrPendingOrderExists
@@ -281,9 +281,9 @@ func (s *Store) ClaimTask(ctx context.Context, input ClaimTaskInput) (*TaskOrder
}
return &TaskOrder{ID: orderID, OrderNo: input.OrderNo, TaskID: task.ID, ProductName: task.Title,
CoverURL: task.CoverURL, Quantity: 1, CommissionAmount: task.CommissionAmount, Currency: "CNY",
MemberLevelID: member.LevelID, RuleSnapshot: rules, Message: "等待系统匹配",
OrderStatus: orderStatusMatching, FreezeStatus: 1, DeadlineAt: input.DeadlineAt.UTC().Format(time.RFC3339),
CreatedAt: time.Now().UTC().Format(time.RFC3339)}, nil
MemberLevelID: member.LevelID, RuleSnapshot: rules, Message: "任务匹配成功,请在截止时间前完成",
OrderStatus: orderStatusPending, FreezeStatus: 1, DeadlineAt: input.DeadlineAt.UTC().Format(time.RFC3339),
MatchedAt: time.Now().UTC().Format(time.RFC3339), CreatedAt: time.Now().UTC().Format(time.RFC3339)}, nil
}
func (s *Store) TaskOrders(ctx context.Context, tenantID, memberID int64, status, offset, limit int) (*TaskOrderPage, error) {