This commit is contained in:
Vinjor 2025-12-02 15:07:54 +08:00
parent de82af1869
commit 7a8ac4cfe6
13 changed files with 333 additions and 59 deletions

View File

@ -35,8 +35,7 @@ import com.ruoyi.common.core.page.TableDataInfo;
*/
@RestController
@RequestMapping("/cus/contacts")
public class CusContactsController extends BaseController
{
public class CusContactsController extends BaseController {
@Autowired
private ICusContactsService cusContactsService;
@Autowired
@ -129,4 +128,22 @@ public class CusContactsController extends BaseController
List<Long> list = new ArrayList<>(Arrays.asList(ids));
return toAjax(cusContactsService.removeByIds(list));
}
/**
* 校验重复客户
* @author vinjor-M
* @date 11:21 2025/12/2
* @param cusContacts TODO
* @return com.ruoyi.common.core.domain.AjaxResult
**/
@Log(title = "校验重复客户", businessType = BusinessType.INSERT)
@PostMapping("/checkCus")
public AjaxResult checkCus(@RequestBody CusContacts cusContacts) {
try {
cusContactsService.checkCus(cusContacts);
return success();
}catch (Exception e){
return error(e.getMessage());
}
}
}

View File

@ -17,9 +17,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.cus.domain.CusMainSeas;
import com.ruoyi.cus.domain.CusManager;
import com.ruoyi.cus.domain.CusTimeAxis;
import com.ruoyi.cus.domain.*;
import com.ruoyi.cus.service.*;
import com.ruoyi.cus.vo.CusMainVO;
import com.ruoyi.cus.vo.MainVO;
@ -40,7 +38,6 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.cus.domain.CusMain;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
@ -171,6 +168,14 @@ public class CusMainController extends BaseController {
@PostMapping
public AjaxResult add(@RequestBody CusMainVO cusMainVO) {
if (StringUtils.isEmpty(cusMainVO.getMainInfo().getId())) {
//新增客户需要根据联系人姓名电话邮箱验证是否重复
try {
//直接取第一个联系人
CusContacts cusContacts = cusMainVO.getContact().get(0);
cusContactsService.checkCus(cusContacts);
}catch (Exception e){
return error(e.getMessage());
}
cusMainVO.getMainInfo().setCusCode(codeGenerator.generate());
}
cusMainService.saveNewCus(cusMainVO);

View File

@ -48,4 +48,12 @@ public interface ICusContactsService extends IService<CusContacts> {
* @param cusId 客户id
**/
void deleteCusData(String cusId);
/**
* 校验重复客户
* @author vinjor-M
* @date 11:22 2025/12/2
* @param cusContacts 客户联系人信息对象
**/
void checkCus(CusContacts cusContacts);
}

View File

@ -13,6 +13,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.DlBaseEntity;
import com.ruoyi.common.utils.StringUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -132,4 +133,24 @@ public class CusContactsServiceImpl extends ServiceImpl<CusContactsMapper,CusCon
public void deleteCusData(String cusId) {
cusContactsMapper.deleteCusData(cusId);
}
/**
* 校验重复客户
*
* @param cusContacts 客户联系人信息对象
* @author vinjor-M
* @date 11:22 2025/12/2
**/
@SneakyThrows
@Override
public void checkCus(CusContacts cusContacts) {
LambdaQueryWrapper<CusContacts> queryWrapper = new LambdaQueryWrapper<CusContacts>()
.apply("UPPER(name) = UPPER({0})", cusContacts.getName())
.eq(CusContacts::getEmail, cusContacts.getEmail())
.eq(CusContacts::getTelephone, cusContacts.getTelephone());
List<CusContacts> contacts = this.list(queryWrapper);
if(!contacts.isEmpty()){
throw new Exception("存在重复的客户!");
}
}
}

View File

@ -70,28 +70,30 @@ public class CusMainServiceImpl extends ServiceImpl<CusMainMapper,CusMain> impl
@DataScope(deptAlias = "cm", userAlias = "cm")
public IPage<MainVO> queryListPage(MainVO pageReqVO, Page<CusMain> page) {
IPage<MainVO> list = cusMainMapper.queryListPage(pageReqVO, page);
List<String> cusIdList = list.getRecords().stream().map(MainVO::getId).collect(Collectors.toList());
//公司信息
List<CusCompany> companyList = cusCompanyService.list(new LambdaQueryWrapper<CusCompany>().in(CusCompany::getCusId, cusIdList).eq(DlBaseEntity::getDelFlag,'0'));
Map<String, CusCompany> companyMap = companyList.stream().collect(Collectors.toMap(CusCompany::getCusId, Function.identity()));
//联系人信息
List<CusContacts> contacts = cusContactsService.list(new LambdaQueryWrapper<CusContacts>().in(CusContacts::getCusId, cusIdList).eq(DlBaseEntity::getDelFlag,'0').eq(CusContacts::getIfDefault,true));
Map<String, CusContacts> contactsMap = contacts.stream().collect(Collectors.toMap(CusContacts::getCusId, Function.identity()));
list.getRecords().forEach(item->{
if(StringUtils.isNotEmpty(item.getCusLabels())){
item.setCusLabelList(JSON.parseArray(item.getCusLabels()));
}
if(companyMap.containsKey(item.getId())){
CusCompany company = companyMap.get(item.getId());
item.setCusFrom(company.getCusFrom());
item.setCusLevel(company.getCusLevel());
item.setBusiType(company.getBusiType());
item.setContactAddress(company.getContactAddress());
}
if(contactsMap.containsKey(item.getId())){
item.setContactName(contactsMap.get(item.getId()).getName());
}
});
if(!list.getRecords().isEmpty()){
List<String> cusIdList = list.getRecords().stream().map(MainVO::getId).collect(Collectors.toList());
//公司信息
List<CusCompany> companyList = cusCompanyService.list(new LambdaQueryWrapper<CusCompany>().in(CusCompany::getCusId, cusIdList).eq(DlBaseEntity::getDelFlag,'0'));
Map<String, CusCompany> companyMap = companyList.stream().collect(Collectors.toMap(CusCompany::getCusId, Function.identity()));
//联系人信息
List<CusContacts> contacts = cusContactsService.list(new LambdaQueryWrapper<CusContacts>().in(CusContacts::getCusId, cusIdList).eq(DlBaseEntity::getDelFlag,'0').eq(CusContacts::getIfDefault,true));
Map<String, CusContacts> contactsMap = contacts.stream().collect(Collectors.toMap(CusContacts::getCusId, Function.identity()));
list.getRecords().forEach(item->{
if(StringUtils.isNotEmpty(item.getCusLabels())){
item.setCusLabelList(JSON.parseArray(item.getCusLabels()));
}
if(companyMap.containsKey(item.getId())){
CusCompany company = companyMap.get(item.getId());
item.setCusFrom(company.getCusFrom());
item.setCusLevel(company.getCusLevel());
item.setBusiType(company.getBusiType());
item.setContactAddress(company.getContactAddress());
}
if(contactsMap.containsKey(item.getId())){
item.setContactName(contactsMap.get(item.getId()).getName());
}
});
}
return list;
}

View File

@ -6,7 +6,7 @@ spring:
druid:
# 主库数据源
master:
url: jdbc:mysql://rm-bp1msd0a4kq4t7a66lo.mysql.rds.aliyuncs.com:3306/dl_crm_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
url: jdbc:mysql://rm-bp1msd0a4kq4t7a66lo.mysql.rds.aliyuncs.com:3306/dl_crm_system?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: csd_rw
password: Csd2025#123
# 从库数据源

View File

@ -50,3 +50,12 @@ export function delContacts(id) {
method: 'delete'
})
}
// 校验重复客户
export function checkCus(data) {
return request({
url: '/cus/contacts/checkCus',
method: 'post',
data: data
})
}

View File

@ -109,6 +109,12 @@ import { listAll } from "@/api/base/country";
export default {
name: 'editForm',
dicts: ['sys_user_sex'],
props: {
country: {
type: String,
default: ""
},
},
data() {
return {
title: '',
@ -188,18 +194,24 @@ export default {
this.reset(cusId);
this.open = true;
this.title = "添加客户联系人";
let that=this
if(this.country){
let chooseItem = this.originalCountryAreaCodeList.filter(item =>{return item.nameCn.toLowerCase().includes(that.country)})
this.form.telephonePre = chooseItem[0].areaCode;
this.form.whatsAppPre = chooseItem[0].areaCode;
}
},
/** 修改按钮操作 */
handleUpdate(row) {
this.form = JSON.parse(JSON.stringify( row));
if(this.form.telephone && this.form.telephone.length>0){
let arr = this.form.telephone.split(" ");
let arr = this.form.telephone.split(" ");
// 使$set
this.$set(this.form, 'telephonePre', arr[0] || '');
this.$set(this.form, 'telephone', arr[1] || '');
}
if (this.form.whatsApp && this.form.whatsApp.length>0){
let arr = this.form.whatsApp.split(" ");
let arr = this.form.whatsApp.split(" ");
this.$set(this.form, 'whatsAppPre', arr[0] || '');
this.$set(this.form, 'whatsApp', arr[1] || '');
}
@ -238,10 +250,10 @@ export default {
if (valid) {
let dataObj = JSON.parse(JSON.stringify(this.form))
if(dataObj.telephone && dataObj.telephonePre){
dataObj.telephone = dataObj.telephonePre+" "+ dataObj.telephone
dataObj.telephone = dataObj.telephonePre+" "+ dataObj.telephone
}
if(dataObj.whatsApp && dataObj.whatsAppPre){
dataObj.whatsApp = dataObj.whatsAppPre +" "+ dataObj.whatsApp
dataObj.whatsApp = dataObj.whatsAppPre +" "+ dataObj.whatsApp
}
if (dataObj.id != null) {
dataObj.id = dataObj.idStr

View File

@ -0,0 +1,154 @@
<template>
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="联系人姓名" prop="name">
<el-input v-model="form.name" placeholder="请输入联系人姓名"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入联系人邮箱"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机" prop="telephone">
<el-input v-model="form.telephone" placeholder="请输入手机">
<el-select filterable :filter-method="filterCountry" v-model="form.telephonePre" slot="prepend" placeholder="区号">
<el-option v-for="(country,index) in countryAreaCodeList" :key="country.areaCode" :label="country.areaCode" :value="country.areaCode">{{country.nameCn}} | {{country.nameEn}} | {{country.areaCode}}</el-option>
</el-select>
</el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</template>
<script>
import { listAll } from "@/api/base/country";
import { checkCus } from "@/api/cus/contacts";
export default {
name: 'checkCus',
data() {
return {
title: '',
open: false,
//
countryAreaCodeList:[],
//--
originalCountryAreaCodeList:[],
//
form: {
name: '',
email: '',
telephone: '',
telephonePre: '',
},
//
rules: {
name: [
{ required: true, message: '请输入联系人姓名', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' }
],
telephone: [
{ required: true, message: '请输入手机', trigger: 'blur' }
],
}
}
},
mounted() {
this.getCountryList()
},
methods: {
// nameCn nameEn
filterCountry(query) {
// query
if (!query) {
//
this.countryAreaCodeList = this.originalCountryAreaCodeList;
return;
}
//
const lowerQuery = query.toLowerCase();
// nameCn nameEn
this.countryAreaCodeList = this.originalCountryAreaCodeList.filter(country => {
const nameCnMatch = country.nameCn.toLowerCase().includes(lowerQuery);
const nameEnMatch = country.nameEn.toLowerCase().includes(lowerQuery);
return nameCnMatch || nameEnMatch; //
});
},
/**
* 获取所有国家列表
*/
getCountryList() {
listAll().then(res => {
if (res.code == 200) {
this.countryAreaCodeList = res.data
this.originalCountryAreaCodeList = res.data
} else {
this.countryAreaCodeList = []
this.originalCountryAreaCodeList = []
}
})
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "客户重复校验";
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
name: '',
email: '',
telephone: '',
telephonePre: '',
};
this.resetForm("form");
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
let dataObj = JSON.parse(JSON.stringify(this.form))
if(dataObj.telephone && dataObj.telephonePre){
dataObj.telephone = dataObj.telephonePre+" "+ dataObj.telephone
}
//
checkCus(dataObj).then(res=>{
if(res.code==200){
this.$modal.msgSuccess("未查询到重复客户信息")
}else{
this.$modal.msgError(res.msg)
}
})
}
});
},
}
}
</script>
<style scoped>
::v-deep .el-select .el-input {
min-width: 80px;
}
</style>

View File

@ -397,6 +397,12 @@ export default {
} else {
this.formData.mainInfo.zoneName = null;
}
//WhatsApp
let chooseItem = this.originalCountryAreaCodeList.filter(item =>{return item.nameCn.toLowerCase().includes(selectedCountry.nameCn)})
this.formData.contact.forEach(item => {
item.telephonePre = chooseItem[0].areaCode;
item.whatsAppPre = chooseItem[0].areaCode;
});
},
remoteMethod(query){
@ -427,6 +433,14 @@ export default {
* 新增联系人
*/
addNewContact(){
let that = this
let telephonePre=''
let whatsAppPre=''
if(this.formData.mainInfo.country){
let chooseItem = this.originalCountryAreaCodeList.filter(item =>{return item.nameCn.toLowerCase().includes(that.formData.mainInfo.country)})
telephonePre = chooseItem[0].areaCode;
whatsAppPre = chooseItem[0].areaCode;
}
this.formData.contact.push({
name: '',
ifDefault: false,
@ -436,9 +450,9 @@ export default {
contactAddress: '',
email: '',
telephone: '',
telephonePre: '',
telephonePre: telephonePre,
whatsApp: '',
whatsAppPre: '',
whatsAppPre: whatsAppPre,
wechat: '',
qq: '',
})
@ -544,10 +558,10 @@ export default {
if(dataObj.contact.length>0){
dataObj.contact.map((item)=>{
if(item.telephone && item.telephonePre){
item.telephone = item.telephonePre +" "+ item.telephone
item.telephone = item.telephonePre +" "+ item.telephone
}
if(item.whatsApp && item.whatsAppPre){
item.whatsApp = item.whatsAppPre +" "+ item.whatsApp
item.whatsApp = item.whatsAppPre +" "+ item.whatsApp
}
})
}else{

View File

@ -53,17 +53,17 @@
</el-dropdown-menu>
</el-dropdown>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['cus:main:export']"
>导出
</el-button>
</el-col>
<!-- <el-col :span="1.5">-->
<!-- <el-button-->
<!-- type="warning"-->
<!-- plain-->
<!-- icon="el-icon-download"-->
<!-- size="mini"-->
<!-- @click="handleExport"-->
<!-- v-hasPermi="['cus:main:export']"-->
<!-- >导出-->
<!-- </el-button>-->
<!-- </el-col>-->
<el-col :span="1.5">
<el-button
type="info"
@ -74,7 +74,17 @@
v-hasPermi="['cus:main:import']"
>导入
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-document-checked"
size="mini"
@click="checkCus"
v-hasPermi="['cus:main:check']"
>重复校验
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -281,6 +291,8 @@
<label-form ref="labelForm" @ok="handleQuery"/>
<!-- 转移客户-->
<select-all-user :multiple="false" ref="selectAllUser" @ok="chooseUserFun"/>
<!-- 客户重复校验-->
<check-cus ref="checkCus" />
</div>
</template>
@ -292,10 +304,11 @@ import { getToken } from '@/utils/auth'
import FollowForm from '../follow/followForm'
import LabelForm from './labelForm'
import SelectAllUser from '../../system/user/selectAllUser'
import CheckCus from './checkCus'
export default {
name: 'Main',
components: { SelectAllUser, LabelForm, DrawForm, FollowForm },
components: { CheckCus, SelectAllUser, LabelForm, DrawForm, FollowForm },
dicts: ['cus_main_product', 'cus_label', 'cus_type', 'sys_user_sex', 'cus_from', 'cus_level', 'cus_busi_type', 'cus_follow_step'],
data() {
return {
@ -391,6 +404,12 @@ export default {
this.upload.title = '客户导入'
this.upload.open = true
},
/**
* 校验客户是否重复
*/
checkCus(){
this.$refs.checkCus.handleAdd()
},
/**
* 给客户设置标签
*/

View File

@ -733,10 +733,8 @@ export default {
this.countryAreaCodeList = this.originalCountryAreaCodeList;
return;
}
//
const lowerQuery = query.toLowerCase();
// nameCn nameEn
this.countryAreaCodeList = this.originalCountryAreaCodeList.filter(country => {
const nameCnMatch = country.nameCn.toLowerCase().includes(lowerQuery);
@ -765,6 +763,12 @@ export default {
} else {
this.formData.mainInfo.zoneName = null;
}
//WhatsApp
let chooseItem = this.originalCountryAreaCodeList.filter(item =>{return item.nameCn.toLowerCase().includes(selectedCountry.nameCn)})
this.formData.contact.forEach(item => {
item.telephonePre = chooseItem[0].areaCode;
item.whatsAppPre = chooseItem[0].areaCode;
});
},
remoteMethod(query){
@ -817,13 +821,13 @@ export default {
//
this.formData.contact.forEach((item,index) => {
if(item.telephone && item.telephone.length>0){
let arr = item.telephone.split(" ");
let arr = item.telephone.split(" ");
// 使$set
this.$set(item, 'telephonePre', arr[0] || '');
this.$set(item, 'telephone', arr[1] || '');
}
if (item.whatsApp && item.whatsApp.length>0){
let arr = item.whatsApp.split(" ");
let arr = item.whatsApp.split(" ");
this.$set(item, 'whatsAppPre', arr[0] || '');
this.$set(item, 'whatsApp', arr[1] || '');
}
@ -902,6 +906,14 @@ export default {
* 新增联系人
*/
addNewContact(){
let that = this
let telephonePre=''
let whatsAppPre=''
if(this.formData.mainInfo.country){
let chooseItem = this.originalCountryAreaCodeList.filter(item =>{return item.nameCn.toLowerCase().includes(that.formData.mainInfo.country)})
telephonePre = chooseItem[0].areaCode;
whatsAppPre = chooseItem[0].areaCode;
}
this.formData.contact.push({
id: '',
cusId: '',
@ -913,9 +925,9 @@ export default {
contactAddress: '',
email: '',
telephone: '',
telephonePre: '',
telephonePre: telephonePre,
whatsApp: '',
whatsAppPre: '',
whatsAppPre: whatsAppPre,
wechat: '',
qq: '',
})
@ -977,10 +989,10 @@ export default {
if(dataObj.contact.length>0){
dataObj.contact.map((item)=>{
if(item.telephone && item.telephonePre){
item.telephone = item.telephonePre +" "+ item.telephone
item.telephone = item.telephonePre +" "+ item.telephone
}
if(item.whatsApp && item.whatsAppPre){
item.whatsApp = item.whatsAppPre +" "+ item.whatsApp
item.whatsApp = item.whatsAppPre +" "+ item.whatsApp
}
})
}else{

View File

@ -211,7 +211,7 @@
<!-- 新建跟进-->
<follow-form @ok="refreshFollow" ref="followForm" :cusId="id" :cusName="mainInfo.cusMain.fullName+'('+mainInfo.cusMain.cusCode+')'" :contactList="contactList"/>
<!-- 联系人-->
<edit-form @ok="getMainInfo" ref="contactForm" />
<edit-form :country="mainInfo.cusMain.country" @ok="getMainInfo" ref="contactForm" />
<!-- 给客户打标签-->
<label-form ref="labelForm" @ok="getMainInfo"/>
<!-- 选择用户组件-->
@ -253,6 +253,7 @@ export default {
cusMain:{
fullName:"",
cusCode:"",
country:""
}
},
contactList:[],