# Conflicts:
#	dl_admin/ruoyi-admin/src/main/java/com/ruoyi/cus/service/ICusMainSeasService.java
#	dl_admin/ruoyi-admin/src/main/java/com/ruoyi/cus/service/impl/CusMainSeasServiceImpl.java
This commit is contained in:
Vinjor 2025-11-24 15:36:54 +08:00
commit 2fa5bb9257
6 changed files with 360 additions and 11 deletions

View File

@ -124,7 +124,7 @@ public class CusMainController extends BaseController {
/**
* 客户信息导入
*
* @param file TODO
* @param file {@link MultipartFile}
* @return com.ruoyi.common.core.domain.AjaxResult
* @author PQZ
* @date 14:29 2025/11/19
@ -138,6 +138,23 @@ public class CusMainController extends BaseController {
return cusImportService.importCusAndContacts(file);
}
/**
* 公海客户信息导入
*
* @param file {@link MultipartFile}
* @return com.ruoyi.common.core.domain.AjaxResult
* @author PQZ
* @date 14:40 2025/11/24
**/
@Log(title = "公海客户信息导入", businessType = BusinessType.IMPORT)
@PostMapping("/importCusSeas")
public AjaxResult importCusSeasAndContacts(@RequestParam("file") MultipartFile file) throws IOException {
if (file.isEmpty()) {
return AjaxResult.error("上传文件不能为空");
}
return cusImportService.importCusAndContacts(file);
}
/**
* 获取客户信息详细信息--编辑
*/
@ -174,7 +191,7 @@ public class CusMainController extends BaseController {
* 更新客户标签
*/
@PostMapping("/setLabels")
public AjaxResult setLabels(@RequestBody MainVO cusMainVO){
public AjaxResult setLabels(@RequestBody MainVO cusMainVO) {
CusMain cusMain = new CusMain();
cusMain.setId(cusMainVO.getId());
cusMain.setCusLabels(JSON.toJSONString(cusMainVO.getCusLabelList()));
@ -187,7 +204,7 @@ public class CusMainController extends BaseController {
List<String> cusLabelList = new ArrayList<>();
JSONArray cusLabelArray = JSON.parseArray(cusMain.getCusLabels());
for(int i = 0; i < cusLabelArray.size(); i++){
for (int i = 0; i < cusLabelArray.size(); i++) {
JSONObject jsonObj = cusLabelArray.getJSONObject(i);
cusLabelList.add(jsonObj.getString("name"));
}
@ -201,13 +218,13 @@ public class CusMainController extends BaseController {
* 更新是否星标客户
*/
@PostMapping("/setIfStar")
public AjaxResult setIfStar(@RequestBody CusMain cusMain){
public AjaxResult setIfStar(@RequestBody CusMain cusMain) {
cusMainService.updateById(cusMain);
//时间轴信息
CusTimeAxis cusTimeAxis = new CusTimeAxis();
cusTimeAxis.setBusiMaxCatg("客户");
cusTimeAxis.setBusiCatg("修改");
cusTimeAxis.setContent(cusMain.getIfStar()?"设为星标":"取消星标");
cusTimeAxis.setContent(cusMain.getIfStar() ? "设为星标" : "取消星标");
cusTimeAxis.setCusId(cusMain.getId());
cusTimeAxisService.saveNewTimeAxis(cusTimeAxis);
return success();

View File

@ -8,9 +8,21 @@ import java.io.IOException;
public interface ICusImportService {
/**
* 导入客户及联系人信息
*
* @param file 导入文件
* @return 导入结果
*/
AjaxResult importCusAndContacts(MultipartFile file) throws IOException;
/**
* 导入公海客户
*
* @param file TODO
* @return com.ruoyi.common.core.domain.AjaxResult
* @author PQZ
* @date 14:30 2025/11/24
**/
AjaxResult importCusSeasAndContacts(MultipartFile file) throws IOException;
}

View File

@ -1,18 +1,30 @@
package com.ruoyi.cus.service;
import java.util.List;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.cus.domain.CusMain;
import com.ruoyi.cus.domain.CusMainSeas;
import com.ruoyi.cus.vo.MainVO;
/**
* 公海客户信息Service接口
*
*
* @author vinjor-m
* @date 2025-11-24
*/
public interface ICusMainSeasService extends IService<CusMainSeas> {
IPage<MainVO> queryListPage(CusMainSeas pageReqVO, Page<CusMainSeas> page);
/**
* 通过名称保存公海客户信息
*
* @param cusMainList 客户信息集合
* @return void
* @author PQZ
* @date 14:44 2025/11/20
**/
void saveOrUpdateByCusName(List<CusMainSeas> cusMainList);
}

View File

@ -36,6 +36,8 @@ public class CusImportServiceImpl implements ICusImportService {
private ICusBankService cusBankService;
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
@Autowired
private ICusMainSeasService cusMainSeasService;
/**
* 导入客户及联系人信息
@ -58,13 +60,49 @@ public class CusImportServiceImpl implements ICusImportService {
InputStream inputStream = file.getInputStream();
// 读取第二个sheet页数据索引为1
ExcelUtil<CusImportDTO> cusUtil = new ExcelUtil<>(CusImportDTO.class);
List<CusImportDTO> secondSheetList = cusUtil.importExcel("客户联系人", inputStream, 1);
List<CusImportDTO> cusImportList = cusUtil.importExcel("客户联系人", inputStream, 1);
// 重新获取输入流用于读取第三个sheet页数据
InputStream thirdSheetInputStream = file.getInputStream();
// 读取第三个sheet页数据索引为2
ExcelUtil<CusBankImportDTO> bankUtil = new ExcelUtil<>(CusBankImportDTO.class);
List<CusBankImportDTO> thirdSheetList = bankUtil.importExcel("银行资料", thirdSheetInputStream, 0);
saveCusAndBank(secondSheetList, thirdSheetList);
List<CusBankImportDTO> bankList = bankUtil.importExcel("银行资料", thirdSheetInputStream, 0);
saveCusAndBank(cusImportList, bankList);
return AjaxResult.success("导入成功");
} catch (Exception e) {
return AjaxResult.error("导入失败:" + e.getMessage());
}
}
/**
* 导入公海客户
*
* @param file 文件
* @return com.ruoyi.common.core.domain.AjaxResult
* @author PQZ
* @date 14:30 2025/11/24
**/
@Override
public AjaxResult importCusSeasAndContacts(MultipartFile file) throws IOException {
try {
// 先打印所有sheet页名称
Workbook workbook = new XSSFWorkbook(file.getInputStream());
int numberOfSheets = workbook.getNumberOfSheets();
for (int i = 0; i < numberOfSheets; i++) {
Sheet sheet = workbook.getSheetAt(i);
}
// 关闭workbook
workbook.close();
// 重新获取输入流用于数据读取
InputStream inputStream = file.getInputStream();
// 读取第二个sheet页数据索引为1
ExcelUtil<CusImportDTO> cusUtil = new ExcelUtil<>(CusImportDTO.class);
List<CusImportDTO> cusImportList = cusUtil.importExcel("客户联系人", inputStream, 1);
// 重新获取输入流用于读取第三个sheet页数据
InputStream thirdSheetInputStream = file.getInputStream();
// 读取第三个sheet页数据索引为2
ExcelUtil<CusBankImportDTO> bankUtil = new ExcelUtil<>(CusBankImportDTO.class);
List<CusBankImportDTO> bankList = bankUtil.importExcel("银行资料", thirdSheetInputStream, 0);
saveCusSeasAndBank(cusImportList, bankList);
return AjaxResult.success("导入成功");
} catch (Exception e) {
return AjaxResult.error("导入失败:" + e.getMessage());
@ -210,6 +248,145 @@ public class CusImportServiceImpl implements ICusImportService {
cusBankService.saveOrUpdateByAccount(cusBankList);
}
}
/**
* 数据处理
*
* @param cusList List<CusImportDTO>
* @param bankList List<CusBankImportDTO>
* @author PQZ
* @date 15:30 2025/11/19
**/
private void saveCusSeasAndBank(List<CusImportDTO> cusList, List<CusBankImportDTO> bankList) {
if (cusList == null || cusList.isEmpty()) {
return;
}
// 使用Map按客户代码分组保留每个客户的所有联系人信息
Map<String, List<CusImportDTO>> customerGroupMap = cusList.stream()
.collect(Collectors.groupingBy(CusImportDTO::getFullName));
// 准备批量插入的集合
List<CusMainSeas> cusMainList = new ArrayList<>();
List<CusCompany> cusCompanyList = new ArrayList<>();
List<CusManager> cusManagerList = new ArrayList<>();
List<CusContacts> cusContactsList = new ArrayList<>();
List<CusBank> cusBankList = new ArrayList<>();
// 遍历每个客户的联系人列表只保存一次客户信息但保存所有联系人
for (Map.Entry<String, List<CusImportDTO>> entry : customerGroupMap.entrySet()) {
List<CusImportDTO> customerContacts = entry.getValue();
if (customerContacts.isEmpty()) {
continue;
}
// 取第一个联系人记录作为客户基本信息因为同一客户的基本信息是重复的
CusImportDTO customerInfo = customerContacts.get(0);
// 为客户提供UUID
String customerId = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
// 提取客户主表信息 CusMain
CusMainSeas customer = new CusMainSeas();
//绑定客户id
customer.setId(customerId);
customer.setCusCode(customerInfo.getCusCode());
customer.setFullName(customerInfo.getFullName());
customer.setShortName(customerInfo.getShortName());
customer.setCusType(customerInfo.getCusType());
customer.setCountry(customerInfo.getCountry());
customer.setZoneName(customerInfo.getZoneName());
customer.setMainProds(customerInfo.getMainProds());
customer.setSiteUrl(customerInfo.getSiteUrl());
customer.setCreator(customerInfo.getCreateBy());
customer.setCreateTime(new Date());
customer.setUpdateTime(new Date());
customer.setRemark(customerInfo.getCusRemark());
cusMainList.add(customer);
// 提取客户公司信息表 CusCompany
CusCompany companyInfo = new CusCompany();
//绑定客户id
companyInfo.setCusId(customerId);
companyInfo.setCusName(customerInfo.getFullName());
companyInfo.setCusFrom(customerInfo.getCusSource());
companyInfo.setCusLevel(customerInfo.getCusLevel());
companyInfo.setBusiType(customerInfo.getBusinessType());
companyInfo.setContactAddress(customerInfo.getContactAddress());
companyInfo.setCreator(customerInfo.getCreateBy());
companyInfo.setCreateTime(new Date());
cusCompanyList.add(companyInfo);
// 提取客户管理信息表 CusManager
CusManager managementInfo = new CusManager();
//绑定客户id
managementInfo.setCusId(customerId);
managementInfo.setCusName(customerInfo.getFullName());
managementInfo.setUserName(customerInfo.getUserName());
managementInfo.setFollowStep(customerInfo.getFollowStep());
managementInfo.setSeasReason(customerInfo.getSeasReason());
managementInfo.setSeasGroup(customerInfo.getSeasGroup());
managementInfo.setOldDept(customerInfo.getOldDept());
managementInfo.setCreator(customerInfo.getCreateBy());
managementInfo.setCreateTime(new Date());
cusManagerList.add(managementInfo);
// 提取客户的所有联系人信息 CusContacts
for (CusImportDTO contact : customerContacts) {
CusContacts customerContact = new CusContacts();
customerContact.setId(snowflakeIdGenerator.generateId());
//绑定客户id
customerContact.setCusId(customerId);
customerContact.setCusName(contact.getFullName());
customerContact.setName(contact.getName());
customerContact.setNickName(contact.getNickName());
customerContact.setEmail(contact.getEmail());
customerContact.setTelephone(contact.getTelephone());
customerContact.setSex(contact.getSex());
customerContact.setBirthday(new Date());
customerContact.setWhatsApp(contact.getWhatsApp());
customerContact.setCreator(contact.getCreateBy());
customerContact.setCreateTime(new Date());
cusContactsList.add(customerContact);
}
//提取银行信息
for (CusBankImportDTO bank : bankList) {
if (bank.getCusName().equals(customerInfo.getFullName())) {
CusBank bankInfo = new CusBank();
//绑定客户id
bankInfo.setCusId(customerId);
bankInfo.setCusName(bank.getCusName());
bankInfo.setBankAccount(bank.getBankAccount());
bankInfo.setBankName(bank.getBankName());
bankInfo.setCurrency(bank.getCurrency());
bankInfo.setBankCode(bank.getBankCode());
bankInfo.setSwiftCode(bank.getSwiftCode());
bankInfo.setBankAddress(bank.getBankAddress());
bankInfo.setBranchCode(bank.getBranchCode());
bankInfo.setTaxId(bank.getTaxId());
cusBankList.add(bankInfo);
}
}
}
// 批量保存公海客户
if (!cusMainList.isEmpty()) {
cusMainSeasService.saveOrUpdateByCusName(cusMainList);
}
// 批量保存客户公司信息表
if (!cusCompanyList.isEmpty()) {
cusCompanyService.saveOrUpdateByCusName(cusCompanyList);
}
// 批量保存客户管理信息表
if (!cusManagerList.isEmpty()) {
cusManagerService.saveOrUpdateByCusName(cusManagerList);
}
// 批量保存客户联系人信息
if (!cusContactsList.isEmpty()) {
cusContactsService.saveOrUpdateByCusName(cusContactsList);
}
//批量保存银行账户信息
if (!cusBankList.isEmpty()) {
cusBankService.saveOrUpdateByAccount(cusBankList);
}
}

View File

@ -1,12 +1,21 @@
package com.ruoyi.cus.service.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.utils.DateUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.cus.domain.CusMain;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.cus.vo.MainVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -37,4 +46,60 @@ public class CusMainSeasServiceImpl extends ServiceImpl<CusMainSeasMapper,CusMai
});
return list;
}
/**
* 通过名称保存公海客户信息
*
* @param cusMainList 客户信息集合
* @return void
* @author PQZ
* @date 14:44 2025/11/20
**/
@Override
public void saveOrUpdateByCusName(List<CusMainSeas> cusMainList) {
if (cusMainList == null || cusMainList.isEmpty()) {
return;
}
// 提取所有需要处理的 fullName
List<String> fullNames = cusMainList.stream()
.map(CusMainSeas::getFullName)
.filter(StringUtils::isNotEmpty)
.distinct()
.collect(Collectors.toList());
// 一次性查询数据库中已存在的客户信息
Map<String, CusMainSeas> existingCusMap = new HashMap<>();
if (!fullNames.isEmpty()) {
List<CusMainSeas> existingCusList = this.list(
new LambdaQueryWrapper<CusMainSeas>()
.in(CusMainSeas::getFullName, fullNames)
);
existingCusMap = existingCusList.stream()
.collect(Collectors.toMap(CusMainSeas::getFullName, Function.identity()));
}
// 分离需要新增和更新的客户
List<CusMainSeas> toSaveList = new ArrayList<>();
List<CusMainSeas> toUpdateList = new ArrayList<>();
for (CusMainSeas cusMain : cusMainList) {
if (StringUtils.isEmpty(cusMain.getFullName())) {
continue;
}
CusMainSeas existingCus = existingCusMap.get(cusMain.getFullName());
if (existingCus != null) {
// 如果存在设置ID并加入更新列表
cusMain.setId(existingCus.getId());
toUpdateList.add(cusMain);
} else {
// 如果不存在则生成新的ID并加入保存列表
toSaveList.add(cusMain);
}
}
// 批量保存和更新
if (!toSaveList.isEmpty()) {
this.saveBatch(toSaveList);
}
if (!toUpdateList.isEmpty()) {
this.updateBatchById(toUpdateList);
}
}
}

View File

@ -114,6 +114,16 @@
v-hasPermi="['cus:seas:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-upload2"
size="mini"
@click="handleImport"
>导入
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -151,7 +161,7 @@
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
@ -202,12 +212,31 @@
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 客户信息导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline">下载模板</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listSeas, getSeas, delSeas, addSeas, updateSeas } from "@/api/cus/seas";
import { getToken } from '@/utils/auth'
export default {
name: "Seas",
data() {
@ -248,6 +277,21 @@ export default {
},
//
form: {},
//
upload: {
//
open: false,
//
title: '',
//
isUploading: false,
//
updateSupport: 0,
//
headers: { Authorization: 'Bearer ' + getToken() },
//
url: process.env.VUE_APP_BASE_API + '/cus/main/importCusSeas'
},
//
rules: {
}
@ -266,6 +310,28 @@ export default {
this.loading = false;
});
},
//
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true
},
//
handleFileSuccess(response, file, fileList) {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert('<div style=\'overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;\'>' + response.msg + '</div>', '导入结果', { dangerouslyUseHTMLString: true })
this.getList()
},
//
submitFileForm() {
this.$refs.upload.submit()
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = '用户导入'
this.upload.open = true
},
//
cancel() {
this.open = false;