package financeapplication import ( "context" "fmt" "strings" "time" "hyapp/pkg/dingtalkrobot" ) type dingTalkNotifier struct { client *dingtalkrobot.Client } func NewDingTalkNotifier(client *dingtalkrobot.Client) ApplicationNotifier { if client == nil { return nil } return &dingTalkNotifier{client: client} } func (n *dingTalkNotifier) NotifyApplicationCreated(ctx context.Context, application applicationDTO) error { if n == nil || n.client == nil { return nil } return n.client.SendMarkdown(ctx, dingtalkrobot.MarkdownMessage{ Title: "财务申请待审核", Text: financeApplicationCreatedMarkdown(application), }) } func financeApplicationCreatedMarkdown(application applicationDTO) string { lines := []string{ "### 财务申请待审核", "", fmt.Sprintf("- 申请ID:%d", application.ID), fmt.Sprintf("- APP:%s", markdownValue(application.AppCode)), fmt.Sprintf("- 操作:%s", markdownValue(operationLabel(application.Operation))), fmt.Sprintf("- 目标用户ID:%s", markdownValue(application.TargetUserID)), fmt.Sprintf("- 金币数量:%d", application.CoinAmount), fmt.Sprintf("- 充值金额 $ %s", markdownValue(application.RechargeAmount)), fmt.Sprintf("- 申请人:%s", markdownValue(actorLabel(application.ApplicantName, application.ApplicantUserID))), fmt.Sprintf("- 发起时间:%s", markdownValue(formatNotifyMillis(application.CreatedAtMS))), "- 后台地址:https://admin-acc.global-interaction.com/finance/", } if application.WalletIdentity != "" { lines = append(lines, fmt.Sprintf("- 钱包身份:%s", markdownValue(walletIdentityLabel(application.WalletIdentity)))) } if application.CredentialText != "" { lines = append(lines, fmt.Sprintf("- 凭证文字:%s", markdownValue(application.CredentialText))) } if application.CredentialImageURL != "" { imageURL := strings.TrimSpace(application.CredentialImageURL) lines = append(lines, "- 凭证图片:", fmt.Sprintf("![凭证图片](%s)", imageURL)) } return strings.Join(lines, "\n") } func operationLabel(value string) string { switch value { case "user_coin_credit": return "增加用户金币" case "user_coin_debit": return "减少用户金币" case "user_wallet_debit": return "用户钱包扣减" case "user_wallet_credit": return "用户钱包增加" case "coin_seller_coin_credit": return "增加币商金币" case "coin_seller_coin_debit": return "减少币商金币" default: return value } } func walletIdentityLabel(value string) string { switch value { case "host": return "host" case "agency": return "agency" case "bd": return "bd" default: return value } } func actorLabel(name string, userID uint) string { name = strings.TrimSpace(name) if name == "" { return fmt.Sprintf("%d", userID) } return fmt.Sprintf("%s(%d)", name, userID) } func formatNotifyMillis(value int64) string { if value <= 0 { return "-" } // 财务审批群主要按北京时间协作;数据库仍保存 Unix 毫秒,这里只在通知文本中转换展示。 return time.UnixMilli(value).In(time.FixedZone("UTC+8", 8*60*60)).Format("2006-01-02 15:04:05") } func markdownValue(value string) string { value = strings.TrimSpace(value) if value == "" { return "-" } if len([]rune(value)) > 240 { runes := []rune(value) value = string(runes[:240]) + "..." } replacer := strings.NewReplacer("\r", " ", "\n", " ", "\t", " ") return replacer.Replace(value) }