吴树波 il y a 1 jour
Parent
commit
2f7e2af972

+ 170 - 0
fs-company/src/main/java/com/fs/company/controller/crm/CrmCustomerPropertyController.java

@@ -0,0 +1,170 @@
+package com.fs.company.controller.crm;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.crm.domain.CrmCustomerProperty;
+import com.fs.crm.service.ICrmCustomerPropertyService;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
+
+@Api(tags = "客户属性标签管理")
+@RestController
+@RequestMapping("/crm/customerProperty")
+public class CrmCustomerPropertyController extends BaseController {
+
+    @Autowired
+    private ICrmCustomerPropertyService crmCustomerPropertyService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @ApiOperation("根据客户 ID 查询属性标签列表")
+    @PreAuthorize("@ss.hasPermi('crm:customer:query')")
+    @GetMapping("/list/{customerId}")
+    public R listByCustomerId(@PathVariable("customerId") Long customerId) {
+        List<CrmCustomerProperty> list = crmCustomerPropertyService.selectCrmCustomerPropertyByCustomerId(customerId);
+        return R.ok().put("data", list);
+    }
+
+    @ApiOperation("查询单个属性标签详情")
+    @PreAuthorize("@ss.hasPermi('crm:customer:query')")
+    @GetMapping("/{id}")
+    public R getInfo(@PathVariable("id") Long id) {
+        CrmCustomerProperty property = crmCustomerPropertyService.selectCrmCustomerPropertyById(id);
+        return R.ok().put("data", property);
+    }
+
+    @ApiOperation("为客户添加属性标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody CrmCustomerProperty property) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        property.setCreateBy(loginUser.getUsername());
+        return toAjax(crmCustomerPropertyService.insertCrmCustomerProperty(property));
+    }
+
+    @ApiOperation("为客户添加或更新属性标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.UPDATE)
+    @PostMapping("/addOrUpdate")
+    public AjaxResult addOrUpdate(@RequestBody CrmCustomerProperty property) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        return toAjax(crmCustomerPropertyService.addOrUpdateCustomerPropertyWithExtra(
+                property.getCustomerId(),
+                property.getPropertyId(),
+                property.getPropertyName(),
+                property.getPropertyValue(),
+                property.getPropertyValueType(),
+                property.getTradeType(),
+                property.getIntention(),
+                property.getLikeRatio(),
+                loginUser.getUsername()
+        ));
+    }
+
+    @ApiOperation("批量为客户添加属性标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.INSERT)
+    @PostMapping("/batchAdd/{customerId}")
+    public AjaxResult batchAdd(
+            @PathVariable("customerId") Long customerId,
+            @RequestBody List<CrmCustomerProperty> properties) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        for (CrmCustomerProperty property : properties) {
+            property.setCreateBy(loginUser.getUsername());
+        }
+        return toAjax(crmCustomerPropertyService.batchAddCustomerProperties(customerId, properties));
+    }
+
+    @ApiOperation("通过属性模板 ID 为客户添加标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.INSERT)
+    @PostMapping("/addByTemplateId")
+    public AjaxResult addByTemplateId(
+            @ApiParam(required = true, name = "customerId", value = "客户 ID") @RequestParam Long customerId,
+            @ApiParam(required = true, name = "templateId", value = "属性模板 ID") @RequestParam Long templateId,
+            @ApiParam(required = true, name = "propertyValue", value = "属性值") @RequestParam String propertyValue) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        return toAjax(crmCustomerPropertyService.addPropertyByTemplateId(customerId, templateId, propertyValue, loginUser.getUsername()));
+    }
+
+    @ApiOperation("通过属性模板 ID 为客户添加或更新标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.UPDATE)
+    @PostMapping("/addOrUpdateByTemplateId")
+    public AjaxResult addOrUpdateByTemplateId(
+            @ApiParam(required = true, name = "customerId", value = "客户 ID") @RequestParam Long customerId,
+            @ApiParam(required = true, name = "templateId", value = "属性模板 ID") @RequestParam Long templateId,
+            @ApiParam(required = true, name = "propertyValue", value = "属性值") @RequestParam String propertyValue) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        return toAjax(crmCustomerPropertyService.addOrUpdatePropertyByTemplateId(customerId, templateId, propertyValue, loginUser.getUsername()));
+    }
+
+    @ApiOperation("批量通过属性模板 ID 为客户添加标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.INSERT)
+    @PostMapping("/batchAddByTemplateIds/{customerId}")
+    public AjaxResult batchAddByTemplateIds(
+            @PathVariable("customerId") Long customerId,
+            @RequestBody Map<Long, String> propertyMap) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        return toAjax(crmCustomerPropertyService.batchAddPropertiesByTemplateIds(customerId, propertyMap, loginUser.getUsername()));
+    }
+
+    @ApiOperation("修改客户属性标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CrmCustomerProperty property) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        property.setUpdateBy(loginUser.getUsername());
+        return toAjax(crmCustomerPropertyService.updateCrmCustomerProperty(property));
+    }
+
+    @ApiOperation("删除客户属性标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(crmCustomerPropertyService.deleteCrmCustomerPropertyByIds(ids));
+    }
+
+    @ApiOperation("删除客户单个属性标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签", businessType = BusinessType.DELETE)
+    @DeleteMapping("/deleteByPropertyId")
+    public AjaxResult deleteByPropertyId(
+            @ApiParam(required = true, name = "customerId", value = "客户 ID") @RequestParam Long customerId,
+            @ApiParam(required = true, name = "propertyId", value = "属性模板 ID") @RequestParam Long propertyId) {
+        return toAjax(crmCustomerPropertyService.lambdaUpdate()
+                .eq(CrmCustomerProperty::getCustomerId, customerId)
+                .eq(CrmCustomerProperty::getPropertyId, propertyId)
+                .remove());
+    }
+
+    @ApiOperation("导出客户属性标签")
+    @PreAuthorize("@ss.hasPermi('crm:customer:export')")
+    @Log(title = "客户属性标签", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CrmCustomerProperty crmCustomerProperty) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<CrmCustomerProperty> list = crmCustomerPropertyService.selectCrmCustomerPropertyList(crmCustomerProperty);
+        ExcelUtil<CrmCustomerProperty> util = new ExcelUtil<CrmCustomerProperty>(CrmCustomerProperty.class);
+        return util.exportExcel(list, "客户属性标签数据");
+    }
+}

+ 78 - 0
fs-company/src/main/java/com/fs/company/controller/crm/CrmCustomerPropertyTemplateController.java

@@ -0,0 +1,78 @@
+package com.fs.company.controller.crm;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.crm.domain.CrmCustomerPropertyTemplate;
+import com.fs.crm.service.ICrmCustomerPropertyTemplateService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@Api(tags = "客户属性标签模板管理")
+@RestController
+@RequestMapping("/crm/customerPropertyTemplate")
+public class CrmCustomerPropertyTemplateController extends BaseController {
+
+    @Autowired
+    private ICrmCustomerPropertyTemplateService crmCustomerPropertyTemplateService;
+
+    @ApiOperation("查询客户属性标签模板列表")
+    @PreAuthorize("@ss.hasPermi('crm:customer:query')")
+    @GetMapping("/list")
+    public TableDataInfo list(CrmCustomerPropertyTemplate crmCustomerPropertyTemplate) {
+        startPage();
+        List<CrmCustomerPropertyTemplate> list = crmCustomerPropertyTemplateService.selectCrmCustomerPropertyTemplateList(crmCustomerPropertyTemplate);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("查询客户属性标签模板详情")
+    @PreAuthorize("@ss.hasPermi('crm:customer:query')")
+    @GetMapping("/{id}")
+    public R getInfo(@PathVariable("id") Long id) {
+        CrmCustomerPropertyTemplate template = crmCustomerPropertyTemplateService.selectCrmCustomerPropertyTemplateById(id);
+        return R.ok().put("data", template);
+    }
+
+    @ApiOperation("添加客户属性标签模板")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CrmCustomerPropertyTemplate crmCustomerPropertyTemplate) {
+        return toAjax(crmCustomerPropertyTemplateService.insertCrmCustomerPropertyTemplate(crmCustomerPropertyTemplate));
+    }
+
+    @ApiOperation("修改客户属性标签模板")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CrmCustomerPropertyTemplate crmCustomerPropertyTemplate) {
+        return toAjax(crmCustomerPropertyTemplateService.updateCrmCustomerPropertyTemplate(crmCustomerPropertyTemplate));
+    }
+
+    @ApiOperation("删除客户属性标签模板")
+    @PreAuthorize("@ss.hasPermi('crm:customer:edit')")
+    @Log(title = "客户属性标签模板", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(crmCustomerPropertyTemplateService.deleteCrmCustomerPropertyTemplateByIds(ids));
+    }
+
+    @ApiOperation("导出客户属性标签模板")
+    @PreAuthorize("@ss.hasPermi('crm:customer:export')")
+    @Log(title = "客户属性标签模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CrmCustomerPropertyTemplate crmCustomerPropertyTemplate) {
+        List<CrmCustomerPropertyTemplate> list = crmCustomerPropertyTemplateService.selectCrmCustomerPropertyTemplateList(crmCustomerPropertyTemplate);
+        ExcelUtil<CrmCustomerPropertyTemplate> util = new ExcelUtil<CrmCustomerPropertyTemplate>(CrmCustomerPropertyTemplate.class);
+        return util.exportExcel(list, "客户属性标签模板数据");
+    }
+}

+ 6 - 0
fs-service/src/main/java/com/fs/crm/domain/CrmCustomerProperty.java

@@ -29,4 +29,10 @@ public class CrmCustomerProperty extends BaseEntityTow {
 
     @Excel(name = "内容解析")
     private String aiAnalysis;
+
+    @Excel(name = "意向登记")
+    private String intention;
+
+    @Excel(name = "喜欢占比")
+    private Integer likeRatio;
 }

+ 7 - 0
fs-service/src/main/java/com/fs/crm/mapper/CrmCustomerPropertyMapper.java

@@ -2,6 +2,7 @@ package com.fs.crm.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.crm.domain.CrmCustomerProperty;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -11,6 +12,10 @@ public interface CrmCustomerPropertyMapper extends BaseMapper<CrmCustomerPropert
 
     List<CrmCustomerProperty> selectCrmCustomerPropertyList(CrmCustomerProperty crmCustomerProperty);
 
+    List<CrmCustomerProperty> selectCrmCustomerPropertyByCustomerId(Long customerId);
+
+    CrmCustomerProperty selectByCustomerIdAndPropertyId(@Param("customerId") Long customerId, @Param("propertyId") Long propertyId);
+
     int insertCrmCustomerProperty(CrmCustomerProperty crmCustomerProperty);
 
     int updateCrmCustomerProperty(CrmCustomerProperty crmCustomerProperty);
@@ -18,4 +23,6 @@ public interface CrmCustomerPropertyMapper extends BaseMapper<CrmCustomerPropert
     int deleteCrmCustomerPropertyById(Long id);
 
     int deleteCrmCustomerPropertyByIds(Long[] ids);
+
+    int deleteByCustomerIdAndPropertyId(@Param("customerId") Long customerId, @Param("propertyId") Long propertyId);
 }

+ 17 - 0
fs-service/src/main/java/com/fs/crm/service/ICrmCustomerPropertyService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.fs.crm.domain.CrmCustomerProperty;
 
 import java.util.List;
+import java.util.Map;
 
 public interface ICrmCustomerPropertyService extends IService<CrmCustomerProperty> {
 
@@ -18,4 +19,20 @@ public interface ICrmCustomerPropertyService extends IService<CrmCustomerPropert
     int deleteCrmCustomerPropertyByIds(Long[] ids);
 
     int deleteCrmCustomerPropertyById(Long id);
+
+    List<CrmCustomerProperty> selectCrmCustomerPropertyByCustomerId(Long customerId);
+
+    int addCustomerProperty(Long customerId, Long propertyId, String propertyName, String propertyValue, String propertyValueType, String tradeType, String createBy);
+
+    int addOrUpdateCustomerProperty(Long customerId, Long propertyId, String propertyName, String propertyValue, String propertyValueType, String tradeType, String createBy);
+
+    int addOrUpdateCustomerPropertyWithExtra(Long customerId, Long propertyId, String propertyName, String propertyValue, String propertyValueType, String tradeType, String intention, Integer likeRatio, String createBy);
+
+    int batchAddCustomerProperties(Long customerId, List<CrmCustomerProperty> properties);
+
+    int addPropertyByTemplateId(Long customerId, Long propertyTemplateId, String propertyValue, String createBy);
+
+    int addOrUpdatePropertyByTemplateId(Long customerId, Long propertyTemplateId, String propertyValue, String createBy);
+
+    int batchAddPropertiesByTemplateIds(Long customerId, Map<Long, String> propertyMap, String createBy);
 }

+ 147 - 0
fs-service/src/main/java/com/fs/crm/service/impl/CrmCustomerPropertyServiceImpl.java

@@ -3,15 +3,23 @@ package com.fs.crm.service.impl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fs.common.utils.DateUtils;
 import com.fs.crm.domain.CrmCustomerProperty;
+import com.fs.crm.domain.CrmCustomerPropertyTemplate;
 import com.fs.crm.mapper.CrmCustomerPropertyMapper;
 import com.fs.crm.service.ICrmCustomerPropertyService;
+import com.fs.crm.service.ICrmCustomerPropertyTemplateService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
+import java.util.Map;
 
 @Service
 public class CrmCustomerPropertyServiceImpl extends ServiceImpl<CrmCustomerPropertyMapper, CrmCustomerProperty> implements ICrmCustomerPropertyService {
 
+    @Autowired
+    private ICrmCustomerPropertyTemplateService propertyTemplateService;
+
     @Override
     public CrmCustomerProperty selectCrmCustomerPropertyById(Long id) {
         return baseMapper.selectCrmCustomerPropertyById(id);
@@ -43,4 +51,143 @@ public class CrmCustomerPropertyServiceImpl extends ServiceImpl<CrmCustomerPrope
     public int deleteCrmCustomerPropertyById(Long id) {
         return baseMapper.deleteCrmCustomerPropertyById(id);
     }
+
+    @Override
+    public List<CrmCustomerProperty> selectCrmCustomerPropertyByCustomerId(Long customerId) {
+        return baseMapper.selectCrmCustomerPropertyByCustomerId(customerId);
+    }
+
+    @Override
+    public int addCustomerProperty(Long customerId, Long propertyId, String propertyName, String propertyValue, String propertyValueType, String tradeType, String createBy) {
+        CrmCustomerProperty property = new CrmCustomerProperty();
+        property.setCustomerId(customerId);
+        property.setPropertyId(propertyId);
+        property.setPropertyName(propertyName);
+        property.setPropertyValue(propertyValue);
+        property.setPropertyValueType(propertyValueType);
+        property.setTradeType(tradeType);
+        property.setCreateBy(createBy);
+        property.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertCrmCustomerProperty(property);
+    }
+
+    @Override
+    public int addOrUpdateCustomerProperty(Long customerId, Long propertyId, String propertyName, String propertyValue, String propertyValueType, String tradeType, String createBy) {
+        CrmCustomerProperty existProperty = baseMapper.selectByCustomerIdAndPropertyId(customerId, propertyId);
+        if (existProperty != null) {
+            existProperty.setPropertyValue(propertyValue);
+            existProperty.setPropertyName(propertyName);
+            existProperty.setPropertyValueType(propertyValueType);
+            existProperty.setTradeType(tradeType);
+            existProperty.setUpdateBy(createBy);
+            existProperty.setUpdateTime(DateUtils.getNowDate());
+            return baseMapper.updateCrmCustomerProperty(existProperty);
+        } else {
+            return addCustomerProperty(customerId, propertyId, propertyName, propertyValue, propertyValueType, tradeType, createBy);
+        }
+    }
+
+    public int addOrUpdateCustomerPropertyWithExtra(Long customerId, Long propertyId, String propertyName, String propertyValue, String propertyValueType, String tradeType, String intention, Integer likeRatio, String createBy) {
+        String autoIntention = calculateIntentionByLikeRatio(likeRatio, intention);
+        
+        CrmCustomerProperty existProperty = baseMapper.selectByCustomerIdAndPropertyId(customerId, propertyId);
+        if (existProperty != null) {
+            existProperty.setPropertyValue(propertyValue);
+            existProperty.setPropertyName(propertyName);
+            existProperty.setPropertyValueType(propertyValueType);
+            existProperty.setTradeType(tradeType);
+            existProperty.setIntention(autoIntention);
+            existProperty.setLikeRatio(likeRatio);
+            existProperty.setUpdateBy(createBy);
+            existProperty.setUpdateTime(DateUtils.getNowDate());
+            return baseMapper.updateCrmCustomerProperty(existProperty);
+        } else {
+            CrmCustomerProperty property = new CrmCustomerProperty();
+            property.setCustomerId(customerId);
+            property.setPropertyId(propertyId);
+            property.setPropertyName(propertyName);
+            property.setPropertyValue(propertyValue);
+            property.setPropertyValueType(propertyValueType);
+            property.setTradeType(tradeType);
+            property.setIntention(autoIntention);
+            property.setLikeRatio(likeRatio);
+            property.setCreateBy(createBy);
+            property.setCreateTime(DateUtils.getNowDate());
+            return baseMapper.insertCrmCustomerProperty(property);
+        }
+    }
+    
+    private String calculateIntentionByLikeRatio(Integer likeRatio, String intention) {
+        if (likeRatio == null) {
+            return intention;
+        }
+        
+        if (likeRatio >= 80) {
+            return "high";
+        } else if (likeRatio >= 50) {
+            return "medium";
+        } else if (likeRatio >= 20) {
+            return "low";
+        } else {
+            return "none";
+        }
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int batchAddCustomerProperties(Long customerId, List<CrmCustomerProperty> properties) {
+        int count = 0;
+        for (CrmCustomerProperty property : properties) {
+            property.setCustomerId(customerId);
+            property.setCreateTime(DateUtils.getNowDate());
+            if (property.getPropertyId() != null) {
+                CrmCustomerProperty existProperty = baseMapper.selectByCustomerIdAndPropertyId(customerId, property.getPropertyId());
+                if (existProperty != null) {
+                    existProperty.setPropertyValue(property.getPropertyValue());
+                    existProperty.setPropertyName(property.getPropertyName());
+                    existProperty.setPropertyValueType(property.getPropertyValueType());
+                    existProperty.setTradeType(property.getTradeType());
+                    existProperty.setUpdateBy(property.getCreateBy());
+                    existProperty.setUpdateTime(DateUtils.getNowDate());
+                    count += baseMapper.updateCrmCustomerProperty(existProperty);
+                    continue;
+                }
+            }
+            count += baseMapper.insertCrmCustomerProperty(property);
+        }
+        return count;
+    }
+
+    @Override
+    public int addPropertyByTemplateId(Long customerId, Long propertyTemplateId, String propertyValue, String createBy) {
+        CrmCustomerPropertyTemplate template = propertyTemplateService.selectCrmCustomerPropertyTemplateById(propertyTemplateId);
+        if (template == null) {
+            return 0;
+        }
+        return addCustomerProperty(customerId, propertyTemplateId, template.getName(), propertyValue, template.getValueType(), template.getTradeType(), createBy);
+    }
+
+    @Override
+    public int addOrUpdatePropertyByTemplateId(Long customerId, Long propertyTemplateId, String propertyValue, String createBy) {
+        CrmCustomerPropertyTemplate template = propertyTemplateService.selectCrmCustomerPropertyTemplateById(propertyTemplateId);
+        if (template == null) {
+            return 0;
+        }
+        return addOrUpdateCustomerProperty(customerId, propertyTemplateId, template.getName(), propertyValue, template.getValueType(), template.getTradeType(), createBy);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int batchAddPropertiesByTemplateIds(Long customerId, Map<Long, String> propertyMap, String createBy) {
+        int count = 0;
+        for (Map.Entry<Long, String> entry : propertyMap.entrySet()) {
+            Long templateId = entry.getKey();
+            String propertyValue = entry.getValue();
+            int result = addOrUpdatePropertyByTemplateId(customerId, templateId, propertyValue, createBy);
+            if (result > 0) {
+                count++;
+            }
+        }
+        return count;
+    }
 }

+ 32 - 0
fs-service/src/main/resources/db/20260317-客户属性模板菜单.sql

@@ -0,0 +1,32 @@
+-- 客户属性模板管理菜单
+-- 注意:parent_id 需要根据实际CRM模块的父菜单ID进行调整
+-- 可以通过 SELECT * FROM sys_menu WHERE menu_name LIKE '%CRM%' OR menu_name LIKE '%客户%'; 查询
+
+-- 先查询CRM模块的父菜单ID,假设CRM模块的父菜单ID需要确认
+-- 如果CRM模块不存在,需要先创建CRM模块菜单
+
+-- 方案一:如果已有CRM父菜单,请替换下面的parent_id值
+-- 方案二:如果需要新建CRM模块,先执行下面的创建CRM模块语句
+
+-- 创建CRM模块(如果不存在)
+-- INSERT INTO `sys_menu`
+--     (`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
+-- VALUES
+--     ('CRM管理', 0, 10, 'crm', NULL, NULL, 1, 0, 'M', '0', '0', '', 'peoples', 'admin', NOW(), '', NULL, 'CRM管理目录');
+
+-- 客户属性模板菜单(请根据实际情况修改parent_id)
+INSERT INTO `sys_menu`
+    (`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
+VALUES
+    ('客户属性模板', 0, 100, 'propertyTemplate', 'crm/propertyTemplate/index', NULL, 1, 0, 'C', '0', '0', 'crm:customerPropertyTemplate:list', 'edit', 'admin', NOW(), '', NULL, '客户属性模板菜单');
+
+SET @parent_id = LAST_INSERT_ID();
+
+INSERT INTO `sys_menu`
+    (`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
+VALUES
+    ('客户属性模板查询', @parent_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'crm:customerPropertyTemplate:query', '#', 'admin', NOW(), '', NULL, ''),
+    ('客户属性模板新增', @parent_id, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'crm:customerPropertyTemplate:add', '#', 'admin', NOW(), '', NULL, ''),
+    ('客户属性模板修改', @parent_id, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'crm:customerPropertyTemplate:edit', '#', 'admin', NOW(), '', NULL, ''),
+    ('客户属性模板删除', @parent_id, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'crm:customerPropertyTemplate:remove', '#', 'admin', NOW(), '', NULL, ''),
+    ('客户属性模板导出', @parent_id, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'crm:customerPropertyTemplate:export', '#', 'admin', NOW(), '', NULL, '');

+ 4 - 0
fs-service/src/main/resources/db/20260318-客户属性标签添加意向和占比.sql

@@ -0,0 +1,4 @@
+-- 为客户属性标签表添加意向登记和喜欢占比字段
+ALTER TABLE `crm_customer_property` 
+ADD COLUMN `intention` varchar(20) DEFAULT NULL COMMENT '意向登记:high-高意向,medium-中意向,low-低意向,none-无意向' AFTER `ai_analysis`,
+ADD COLUMN `like_ratio` int(3) DEFAULT NULL COMMENT '喜欢占比:0-100' AFTER `intention`;

+ 25 - 1
fs-service/src/main/resources/mapper/crm/CrmCustomerPropertyMapper.xml

@@ -13,6 +13,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="propertyValueType"    column="property_value_type"    />
         <result property="tradeType"    column="trade_type"    />
         <result property="aiAnalysis"    column="ai_analysis"    />
+        <result property="intention"    column="intention"    />
+        <result property="likeRatio"    column="like_ratio"    />
         <result property="createTime"    column="create_time"    />
         <result property="createBy"    column="create_by"    />
         <result property="updateTime"    column="update_time"    />
@@ -21,7 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 
     <sql id="selectCrmCustomerPropertyVo">
-        select id, customer_id, property_id, property_name, property_value, property_value_type, trade_type, ai_analysis, create_time, create_by, update_time, update_by, remark from crm_customer_property
+        select id, customer_id, property_id, property_name, property_value, property_value_type, trade_type, ai_analysis, intention, like_ratio, create_time, create_by, update_time, update_by, remark from crm_customer_property
     </sql>
 
     <select id="selectCrmCustomerPropertyList" parameterType="CrmCustomerProperty" resultMap="CrmCustomerPropertyResult">
@@ -52,6 +54,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="propertyValueType != null">property_value_type,</if>
             <if test="tradeType != null">trade_type,</if>
             <if test="aiAnalysis != null">ai_analysis,</if>
+            <if test="intention != null">intention,</if>
+            <if test="likeRatio != null">like_ratio,</if>
             <if test="createTime != null">create_time,</if>
             <if test="createBy != null">create_by,</if>
             <if test="updateTime != null">update_time,</if>
@@ -66,6 +70,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="propertyValueType != null">#{propertyValueType},</if>
             <if test="tradeType != null">#{tradeType},</if>
             <if test="aiAnalysis != null">#{aiAnalysis},</if>
+            <if test="intention != null">#{intention},</if>
+            <if test="likeRatio != null">#{likeRatio},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="createBy != null">#{createBy},</if>
             <if test="updateTime != null">#{updateTime},</if>
@@ -84,6 +90,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="propertyValueType != null">property_value_type = #{propertyValueType},</if>
             <if test="tradeType != null">trade_type = #{tradeType},</if>
             <if test="aiAnalysis != null">ai_analysis = #{aiAnalysis},</if>
+            <if test="intention != null">intention = #{intention},</if>
+            <if test="likeRatio != null">like_ratio = #{likeRatio},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
             <if test="createBy != null">create_by = #{createBy},</if>
             <if test="updateTime != null">update_time = #{updateTime},</if>
@@ -103,4 +111,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{id}
         </foreach>
     </delete>
+
+    <select id="selectCrmCustomerPropertyByCustomerId" parameterType="Long" resultMap="CrmCustomerPropertyResult">
+        <include refid="selectCrmCustomerPropertyVo"/>
+        where customer_id = #{customerId}
+        order by id desc
+    </select>
+
+    <select id="selectByCustomerIdAndPropertyId" resultMap="CrmCustomerPropertyResult">
+        <include refid="selectCrmCustomerPropertyVo"/>
+        where customer_id = #{customerId} and property_id = #{propertyId}
+        limit 1
+    </select>
+
+    <delete id="deleteByCustomerIdAndPropertyId">
+        delete from crm_customer_property where customer_id = #{customerId} and property_id = #{propertyId}
+    </delete>
 </mapper>