From df7a41f3c49963db550678f074ed748027268fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Mon, 30 Mar 2026 11:08:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(contact):=20=E6=B7=BB=E5=8A=A0=E8=81=94?= =?UTF-8?q?=E7=B3=BB=E8=A1=A8=E5=8D=95=E9=94=80=E5=94=AE=E7=BA=BF=E7=B4=A2?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增联系表单数据库表结构设计与实体类定义 - 实现联系表单提交接口,支持公开访问无需登录验证 - 添加后台管理接口,支持线索查询、状态更新和删除操作 - 集成企业微信和飞书机器人通知功能,实时推送新线索 - 在安全配置中开放联系表单提交接口访问权限 - 添加应用配置中的通知机器人Webhook配置项 --- .../controller/CmsContactLeadController.java | 142 ++++++++++++ .../gxwebsoft/cms/entity/CmsContactLead.java | 83 +++++++ .../cms/mapper/CmsContactLeadMapper.java | 36 +++ .../cms/mapper/xml/CmsContactLeadMapper.xml | 66 ++++++ .../cms/param/CmsContactLeadParam.java | 56 +++++ .../cms/service/CmsContactLeadService.java | 42 ++++ .../impl/CmsContactLeadServiceImpl.java | 209 ++++++++++++++++++ .../gxwebsoft/cms/sql/cms_contact_lead.sql | 25 +++ .../common/core/security/SecurityConfig.java | 3 +- src/main/resources/application.yml | 15 +- 10 files changed, 670 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/gxwebsoft/cms/controller/CmsContactLeadController.java create mode 100644 src/main/java/com/gxwebsoft/cms/entity/CmsContactLead.java create mode 100644 src/main/java/com/gxwebsoft/cms/mapper/CmsContactLeadMapper.java create mode 100644 src/main/java/com/gxwebsoft/cms/mapper/xml/CmsContactLeadMapper.xml create mode 100644 src/main/java/com/gxwebsoft/cms/param/CmsContactLeadParam.java create mode 100644 src/main/java/com/gxwebsoft/cms/service/CmsContactLeadService.java create mode 100644 src/main/java/com/gxwebsoft/cms/service/impl/CmsContactLeadServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/cms/sql/cms_contact_lead.sql diff --git a/src/main/java/com/gxwebsoft/cms/controller/CmsContactLeadController.java b/src/main/java/com/gxwebsoft/cms/controller/CmsContactLeadController.java new file mode 100644 index 0000000..2b7d6d9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/controller/CmsContactLeadController.java @@ -0,0 +1,142 @@ +package com.gxwebsoft.cms.controller; + +import com.gxwebsoft.cms.entity.CmsContactLead; +import com.gxwebsoft.cms.param.CmsContactLeadParam; +import com.gxwebsoft.cms.service.CmsContactLeadService; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.BatchParam; +import com.gxwebsoft.common.core.web.PageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; + +/** + * 联系表单/销售线索控制器 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Slf4j +@Validated +@Tag(name = "联系表单/销售线索管理") +@RestController +@RequestMapping("/api/cms/cms-contact-lead") +public class CmsContactLeadController extends BaseController { + + @Resource + private CmsContactLeadService cmsContactLeadService; + + // ------------------------- + // 公开接口(无需登录) + // ------------------------- + + /** + * 提交联系表单(官网 /contact 页调用,不需要登录) + */ + @Operation(summary = "提交联系表单") + @PostMapping("/submit") + public ApiResult submit(@RequestBody @Valid CmsContactLead lead, HttpServletRequest request) { + // 获取客户端真实IP + String ip = getClientIp(request); + if (cmsContactLeadService.submit(lead, ip)) { + return success("提交成功,我们将尽快与您联系!"); + } + return fail("提交失败,请稍后重试"); + } + + // ------------------------- + // 后台管理接口(需要权限) + // ------------------------- + + @Operation(summary = "分页查询线索列表") + @PreAuthorize("hasAuthority('cms:contactLead:list')") + @GetMapping("/page") + public ApiResult> page(CmsContactLeadParam param) { + return success(cmsContactLeadService.pageRel(param)); + } + + @Operation(summary = "查询全部线索") + @PreAuthorize("hasAuthority('cms:contactLead:list')") + @GetMapping() + public ApiResult> list(CmsContactLeadParam param) { + return success(cmsContactLeadService.listRel(param)); + } + + @Operation(summary = "根据ID查询线索") + @PreAuthorize("hasAuthority('cms:contactLead:list')") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { + return success(cmsContactLeadService.getById(id)); + } + + @Operation(summary = "更新跟进状态/备注") + @PreAuthorize("hasAuthority('cms:contactLead:update')") + @PutMapping() + public ApiResult update(@RequestBody CmsContactLead lead) { + if (cmsContactLeadService.updateById(lead)) { + return success("更新成功"); + } + return fail("更新失败"); + } + + @Operation(summary = "删除线索") + @PreAuthorize("hasAuthority('cms:contactLead:remove')") + @DeleteMapping("/{id}") + public ApiResult remove(@PathVariable("id") Integer id) { + if (cmsContactLeadService.removeById(id)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + @Operation(summary = "批量修改") + @PreAuthorize("hasAuthority('cms:contactLead:update')") + @PutMapping("/batch") + public ApiResult updateBatch(@RequestBody BatchParam batchParam) { + if (batchParam.update(cmsContactLeadService, "lead_id")) { + return success("批量修改成功"); + } + return fail("批量修改失败"); + } + + @Operation(summary = "批量删除") + @PreAuthorize("hasAuthority('cms:contactLead:remove')") + @DeleteMapping("/batch") + public ApiResult removeBatch(@RequestBody List ids) { + if (cmsContactLeadService.removeByIds(ids)) { + return success("删除成功"); + } + return fail("删除失败"); + } + + // ------------------------- + // 工具方法 + // ------------------------- + + /** + * 获取客户端真实IP(兼容反向代理) + */ + private String getClientIp(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("X-Real-IP"); + } + if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + // X-Forwarded-For 多个IP取第一个 + if (ip != null && ip.contains(",")) { + ip = ip.split(",")[0].trim(); + } + return ip; + } +} diff --git a/src/main/java/com/gxwebsoft/cms/entity/CmsContactLead.java b/src/main/java/com/gxwebsoft/cms/entity/CmsContactLead.java new file mode 100644 index 0000000..7e6f604 --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/entity/CmsContactLead.java @@ -0,0 +1,83 @@ +package com.gxwebsoft.cms.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 联系表单/销售线索 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "CmsContactLead对象", description = "联系表单/销售线索") +public class CmsContactLead implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "线索ID") + @TableId(value = "lead_id", type = IdType.AUTO) + private Integer leadId; + + @Schema(description = "联系人姓名") + private String name; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "单位/公司名称") + private String company; + + @Schema(description = "交付方式: saas/private/hybrid") + private String delivery; + + @Schema(description = "需求描述") + private String need; + + @Schema(description = "来源渠道: web/miniapp/app") + private String source; + + @Schema(description = "提交IP") + private String ip; + + @Schema(description = "跟进状态: 0待跟进 1跟进中 2已成交 3无效") + private Integer status; + + @Schema(description = "销售备注") + private String remarks; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + public String getStatusText() { + if (this.status == null) return ""; + return switch (this.status) { + case 0 -> "待跟进"; + case 1 -> "跟进中"; + case 2 -> "已成交"; + case 3 -> "无效"; + default -> ""; + }; + } +} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/CmsContactLeadMapper.java b/src/main/java/com/gxwebsoft/cms/mapper/CmsContactLeadMapper.java new file mode 100644 index 0000000..d8cc641 --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/mapper/CmsContactLeadMapper.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.cms.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.cms.entity.CmsContactLead; +import com.gxwebsoft.cms.param.CmsContactLeadParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 联系表单/销售线索Mapper + * + * @author 科技小王子 + * @since 2026-03-30 + */ +public interface CmsContactLeadMapper extends BaseMapper { + + /** + * 分页查询 + * + * @param page 分页对象 + * @param param 查询参数 + * @return List + */ + List selectPageRel(@Param("page") IPage page, + @Param("param") CmsContactLeadParam param); + + /** + * 查询全部 + * + * @param param 查询参数 + * @return List + */ + List selectListRel(@Param("param") CmsContactLeadParam param); +} diff --git a/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsContactLeadMapper.xml b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsContactLeadMapper.xml new file mode 100644 index 0000000..d1fabdf --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/mapper/xml/CmsContactLeadMapper.xml @@ -0,0 +1,66 @@ + + + + + + + SELECT a.* + FROM cms_contact_lead a + + + AND a.lead_id = #{param.leadId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.phone LIKE CONCAT('%', #{param.phone}, '%') + + + AND a.company LIKE CONCAT('%', #{param.company}, '%') + + + AND a.delivery = #{param.delivery} + + + AND a.source = #{param.source} + + + AND a.status = #{param.status} + + + AND ( + a.name LIKE CONCAT('%', #{param.keywords}, '%') + OR a.phone LIKE CONCAT('%', #{param.keywords}, '%') + OR a.company LIKE CONCAT('%', #{param.keywords}, '%') + OR a.need LIKE CONCAT('%', #{param.keywords}, '%') + ) + + + AND a.deleted = #{param.deleted} + + + AND a.deleted = 0 + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/cms/param/CmsContactLeadParam.java b/src/main/java/com/gxwebsoft/cms/param/CmsContactLeadParam.java new file mode 100644 index 0000000..4855dc9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/param/CmsContactLeadParam.java @@ -0,0 +1,56 @@ +package com.gxwebsoft.cms.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 联系表单/销售线索查询参数 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "CmsContactLeadParam对象", description = "联系表单/销售线索查询参数") +public class CmsContactLeadParam extends BaseParam { + + private static final long serialVersionUID = 1L; + + @Schema(description = "线索ID") + @QueryField(type = QueryType.EQ) + private Integer leadId; + + @Schema(description = "联系人姓名") + @QueryField(type = QueryType.LIKE) + private String name; + + @Schema(description = "手机号") + @QueryField(type = QueryType.LIKE) + private String phone; + + @Schema(description = "单位/公司名称") + @QueryField(type = QueryType.LIKE) + private String company; + + @Schema(description = "交付方式: saas/private/hybrid") + @QueryField(type = QueryType.EQ) + private String delivery; + + @Schema(description = "来源渠道") + @QueryField(type = QueryType.EQ) + private String source; + + @Schema(description = "跟进状态: 0待跟进 1跟进中 2已成交 3无效") + @QueryField(type = QueryType.EQ) + private Integer status; + + @Schema(description = "是否删除, 0否, 1是") + @QueryField(type = QueryType.EQ) + private Integer deleted; +} diff --git a/src/main/java/com/gxwebsoft/cms/service/CmsContactLeadService.java b/src/main/java/com/gxwebsoft/cms/service/CmsContactLeadService.java new file mode 100644 index 0000000..e1c5e02 --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/service/CmsContactLeadService.java @@ -0,0 +1,42 @@ +package com.gxwebsoft.cms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.cms.entity.CmsContactLead; +import com.gxwebsoft.cms.param.CmsContactLeadParam; +import com.gxwebsoft.common.core.web.PageResult; + +import java.util.List; + +/** + * 联系表单/销售线索Service + * + * @author 科技小王子 + * @since 2026-03-30 + */ +public interface CmsContactLeadService extends IService { + + /** + * 分页关联查询 + * + * @param param 查询参数 + * @return PageResult + */ + PageResult pageRel(CmsContactLeadParam param); + + /** + * 关联查询全部 + * + * @param param 查询参数 + * @return List + */ + List listRel(CmsContactLeadParam param); + + /** + * 提交联系表单(不需要登录) + * + * @param lead 表单数据 + * @param ip 客户端IP + * @return boolean + */ + boolean submit(CmsContactLead lead, String ip); +} diff --git a/src/main/java/com/gxwebsoft/cms/service/impl/CmsContactLeadServiceImpl.java b/src/main/java/com/gxwebsoft/cms/service/impl/CmsContactLeadServiceImpl.java new file mode 100644 index 0000000..6fe172e --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/service/impl/CmsContactLeadServiceImpl.java @@ -0,0 +1,209 @@ +package com.gxwebsoft.cms.service.impl; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.cms.entity.CmsContactLead; +import com.gxwebsoft.cms.mapper.CmsContactLeadMapper; +import com.gxwebsoft.cms.param.CmsContactLeadParam; +import com.gxwebsoft.cms.service.CmsContactLeadService; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 联系表单/销售线索Service实现 + * + * @author 科技小王子 + * @since 2026-03-30 + */ +@Slf4j +@Service +public class CmsContactLeadServiceImpl extends ServiceImpl + implements CmsContactLeadService { + + /** 企业微信群机器人 Webhook,留空则不发送 */ + @Value("${notify.wecom-webhook:}") + private String wecomWebhook; + + /** 飞书群机器人 Webhook,留空则不发送 */ + @Value("${notify.feishu-webhook:}") + private String feishuWebhook; + + // -------------------------------------------------------- + // 分页 / 列表 + // -------------------------------------------------------- + + @Override + public PageResult pageRel(CmsContactLeadParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("create_time desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(CmsContactLeadParam param) { + return baseMapper.selectListRel(param); + } + + // -------------------------------------------------------- + // 公开提交接口 + // -------------------------------------------------------- + + @Override + public boolean submit(CmsContactLead lead, String ip) { + // 补充默认值 + if (StrUtil.isBlank(lead.getSource())) { + lead.setSource("web"); + } + lead.setIp(ip); + lead.setStatus(0); // 默认待跟进 + + boolean result = save(lead); + if (result) { + log.info("[联系表单] 新线索提交成功,name={}, phone={}", lead.getName(), lead.getPhone()); + // 异步推送通知,不阻塞接口响应 + sendNotifyAsync(lead); + } + return result; + } + + // -------------------------------------------------------- + // 异步通知(企业微信 + 飞书) + // -------------------------------------------------------- + + @Async + public void sendNotifyAsync(CmsContactLead lead) { + String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("MM-dd HH:mm")); + String deliveryLabel = deliveryLabel(lead.getDelivery()); + + if (StrUtil.isNotBlank(wecomWebhook)) { + try { + sendWecom(lead, deliveryLabel, now); + } catch (Exception e) { + log.warn("[联系表单] 企业微信通知发送失败: {}", e.getMessage()); + } + } + + if (StrUtil.isNotBlank(feishuWebhook)) { + try { + sendFeishu(lead, deliveryLabel, now); + } catch (Exception e) { + log.warn("[联系表单] 飞书通知发送失败: {}", e.getMessage()); + } + } + } + + /** + * 企业微信群机器人 - markdown 消息 + * 文档:https://developer.work.weixin.qq.com/document/path/91770 + */ + private void sendWecom(CmsContactLead lead, String deliveryLabel, String now) { + String content = String.format( + "## 📋 新销售线索(%s)\n" + + "> **姓名:** %s\n" + + "> **手机:** %s\n" + + "> **公司:** %s\n" + + "> **交付:** %s\n" + + "> **需求:** %s\n" + + "> **来源:** %s", + now, + nullSafe(lead.getName()), + nullSafe(lead.getPhone()), + nullSafe(lead.getCompany()), + deliveryLabel, + truncate(lead.getNeed(), 100), + nullSafe(lead.getSource()) + ); + + Map textMap = new HashMap<>(); + textMap.put("content", content); + + Map payload = new HashMap<>(); + payload.put("msgtype", "markdown"); + payload.put("markdown", textMap); + + String body = JSON.toJSONString(payload); + String resp = HttpUtil.post(wecomWebhook, body); + log.info("[联系表单] 企业微信通知结果: {}", resp); + } + + /** + * 飞书群机器人 - 富文本(post)消息 + * 文档:https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot + */ + private void sendFeishu(CmsContactLead lead, String deliveryLabel, String now) { + // 标题行 + String title = "📋 新销售线索(" + now + ")"; + + // 正文每行:[{"tag":"text","text":"xxx"}] + List>> content = List.of( + line("姓 名:" + nullSafe(lead.getName())), + line("手 机:" + nullSafe(lead.getPhone())), + line("公 司:" + nullSafe(lead.getCompany())), + line("交 付:" + deliveryLabel), + line("需 求:" + truncate(lead.getNeed(), 100)), + line("来 源:" + nullSafe(lead.getSource())) + ); + + Map zhCn = new HashMap<>(); + zhCn.put("title", title); + zhCn.put("content", content); + + Map postContent = new HashMap<>(); + postContent.put("zh_cn", zhCn); + + Map post = new HashMap<>(); + post.put("content", postContent); + + Map payload = new HashMap<>(); + payload.put("msg_type", "post"); + payload.put("content", post); + + String body = JSON.toJSONString(payload); + String resp = HttpUtil.post(feishuWebhook, body); + log.info("[联系表单] 飞书通知结果: {}", resp); + } + + // -------------------------------------------------------- + // 工具方法 + // -------------------------------------------------------- + + private String deliveryLabel(String delivery) { + if (delivery == null) return "未选择"; + return switch (delivery) { + case "saas" -> "SaaS(云端)"; + case "private" -> "私有化部署"; + case "hybrid" -> "混合部署"; + default -> delivery; + }; + } + + private String nullSafe(String s) { + return StrUtil.isBlank(s) ? "—" : s; + } + + private String truncate(String s, int max) { + if (StrUtil.isBlank(s)) return "—"; + return s.length() > max ? s.substring(0, max) + "…" : s; + } + + /** 飞书 post 消息单行 */ + private List> line(String text) { + Map node = new HashMap<>(); + node.put("tag", "text"); + node.put("text", text); + return List.of(node); + } +} diff --git a/src/main/java/com/gxwebsoft/cms/sql/cms_contact_lead.sql b/src/main/java/com/gxwebsoft/cms/sql/cms_contact_lead.sql new file mode 100644 index 0000000..45d6154 --- /dev/null +++ b/src/main/java/com/gxwebsoft/cms/sql/cms_contact_lead.sql @@ -0,0 +1,25 @@ +-- ---------------------------- +-- 联系表单/销售线索表 +-- 存放官网 /contact 页面提交的咨询需求 +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `cms_contact_lead` ( + `lead_id` INT NOT NULL AUTO_INCREMENT COMMENT '线索ID', + `name` VARCHAR(50) NOT NULL COMMENT '联系人姓名', + `phone` VARCHAR(20) NOT NULL COMMENT '手机号', + `company` VARCHAR(100) DEFAULT NULL COMMENT '单位/公司名称', + `delivery` VARCHAR(20) DEFAULT NULL COMMENT '交付方式: saas/private/hybrid', + `need` TEXT DEFAULT NULL COMMENT '需求描述', + `source` VARCHAR(50) DEFAULT 'web' COMMENT '来源渠道: web/miniapp/app', + `ip` VARCHAR(50) DEFAULT NULL COMMENT '提交IP', + `status` TINYINT NOT NULL DEFAULT 0 COMMENT '跟进状态: 0待跟进 1跟进中 2已成交 3无效', + `remarks` VARCHAR(500) DEFAULT NULL COMMENT '销售备注', + `deleted` TINYINT NOT NULL DEFAULT 0 COMMENT '是否删除: 0否 1是', + `tenant_id` INT DEFAULT NULL COMMENT '租户ID', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`lead_id`), + KEY `idx_tenant_id` (`tenant_id`), + KEY `idx_phone` (`phone`), + KEY `idx_status` (`status`), + KEY `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='联系表单/销售线索'; diff --git a/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java index 8cd95a0..c9d1463 100644 --- a/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java +++ b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java @@ -80,7 +80,8 @@ public class SecurityConfig { "/api/shop/getShopInfo", "/api/shop/shop-order/test", "/api/qr-code/**", - "/api/shop/order-delivery/notify" + "/api/shop/order-delivery/notify", + "/api/cms/cms-contact-lead/submit" ) .permitAll() .anyRequest() diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ada4ffe..10fe6e9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -258,9 +258,12 @@ payment: # 开发环境是否启用环境感知 environment-aware: true - # 生产环境配置 - prod: - # 生产环境回调地址 - notify-url: "https://cms-api.websoft.top/api/shop/shop-order/notify" - # 生产环境是否启用环境感知 - environment-aware: false + +# 通知配置(企业微信/飞书机器人 Webhook) +notify: + # 企业微信群机器人 Webhook,格式:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY + # 不启用时留空或删除此行 + wecom-webhook: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=aa0d2f30-b785-44a2-ad19-05834569b7c5" + # 飞书群机器人 Webhook,格式:https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_TOKEN + feishu-webhook: "" +