Files
web_template/internal/handler/customer.go
Geliebte 3580066a13 feat: 导航页文案可后台配置 + webhook修复 + 企业微信通知可用
- 导航页所有文案(标题/副标题/标签/咨询区/页脚/工作室名称)均可在后台「导航页设置」页配置
- 新增公开API GET /api/v1/nav-settings,导航页加载时自动拉取配置覆盖默认值
- CustomerHandler改为从数据库读取webhook URL,不再依赖config.yaml
- 新增默认企业微信webhook地址,开箱即用
- 后台新增webhook测试专用接口 POST /api/v1/admin/webhook/test
- 后台新增批量配置保存接口 PUT /api/v1/admin/config-batch
- 后台新增「导航页设置」管理页面,支持分组编辑保存
- 页脚添加工作室名称展示位
2026-09-09 02:49:39 +08:00

158 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handler
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"gotest/internal/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// CustomerHandler 客户信息收集处理器
type CustomerHandler struct {
db *gorm.DB
}
// NewCustomerHandler 创建客户信息收集处理器
func NewCustomerHandler(db *gorm.DB) *CustomerHandler {
return &CustomerHandler{db: db}
}
// CustomerRequest 客户信息请求
type CustomerRequest struct {
Name string `json:"name" binding:"required"`
Phone string `json:"phone" binding:"required"`
Company string `json:"company"`
Email string `json:"email"`
Needs string `json:"needs" binding:"required"`
}
// Submit 提交客户信息 POST /api/v1/customer/submit
func (h *CustomerHandler) Submit(c *gin.Context) {
var req CustomerRequest
if err := c.ShouldBindJSON(&req); err != nil {
FailBadRequest(c, "请填写完整的联系信息")
return
}
// 构建企业微信消息内容
content := fmt.Sprintf("【新客户咨询】\n"+
"━━━━━━━━━━━━━━━━━━━━\n"+
"👤 姓名:%s\n"+
"📱 电话:%s\n"+
"📧 邮箱:%s\n"+
"🏢 公司:%s\n"+
"💼 需求:%s\n"+
"⏰ 时间:%s\n"+
"━━━━━━━━━━━━━━━━━━━━",
req.Name, req.Phone, req.Email, req.Company, req.Needs, time.Now().Format("2006-01-02 15:04:05"))
// 发送到企业微信webhook
if err := h.sendToWechatWebhook(content); err != nil {
fmt.Printf("发送企业微信webhook失败: %v\n", err)
}
Success(c, gin.H{
"message": "提交成功,我们会尽快联系您!",
})
}
// getWebhookURL 从数据库获取webhook URL
func (h *CustomerHandler) getWebhookURL() string {
var cfg model.Config
if err := h.db.Where("`key` = ?", "wechat_webhook_url").First(&cfg).Error; err == nil && cfg.Value != "" {
return cfg.Value
}
return "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=71110fd5-9f51-4695-88dc-85ca34385d66"
}
// sendToWechatWebhook 发送消息到企业微信群机器人
func (h *CustomerHandler) sendToWechatWebhook(content string) error {
webhookURL := h.getWebhookURL()
message := map[string]interface{}{
"msgtype": "text",
"text": map[string]string{
"content": content,
},
}
jsonData, err := json.Marshal(message)
if err != nil {
return fmt.Errorf("序列化消息失败: %w", err)
}
resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
return fmt.Errorf("发送请求失败: %w", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("读取响应失败: %w", err)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("请求失败,状态码: %d,响应: %s", resp.StatusCode, string(body))
}
var result map[string]interface{}
if err := json.Unmarshal(body, &result); err != nil {
return fmt.Errorf("解析响应失败: %w", err)
}
if errcode, ok := result["errcode"].(float64); ok && errcode != 0 {
errmsg, _ := result["errmsg"].(string)
return fmt.Errorf("企业微信返回错误: %v - %s", errcode, errmsg)
}
return nil
}
// TestWebhook 测试webhook POST /api/v1/admin/webhook/test
func (h *CustomerHandler) TestWebhook(c *gin.Context) {
webhookURL := h.getWebhookURL()
content := fmt.Sprintf("✅ Webhook 测试成功\n⏰ 时间:%s", time.Now().Format("2006-01-02 15:04:05"))
message := map[string]interface{}{
"msgtype": "text",
"text": map[string]string{
"content": content,
},
}
jsonData, err := json.Marshal(message)
if err != nil {
FailInternal(c, "序列化失败: "+err.Error())
return
}
resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
FailInternal(c, "发送失败: "+err.Error())
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
if errcode, ok := result["errcode"].(float64); ok && errcode != 0 {
errmsg, _ := result["errmsg"].(string)
FailInternal(c, fmt.Sprintf("企业微信返回错误: %v - %s", errcode, errmsg))
return
}
SuccessMsg(c, "测试消息发送成功!请检查企业微信群")
}