Compare commits

...

2 Commits

21 changed files with 1455 additions and 25 deletions

View File

@@ -18,8 +18,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.rmi.ServerException; import java.rmi.ServerException;
@@ -220,4 +222,18 @@ public class MyCustomerController extends BaseController {
} }
return AjaxResult.success(iSysCampaignGroupCustomerService.appointCustCamp( custId, custName, custIdc, custPhone, custIsn,socialCreditCode,lpName, campaignId, custType)); return AjaxResult.success(iSysCampaignGroupCustomerService.appointCustCamp( custId, custName, custIdc, custPhone, custIsn,socialCreditCode,lpName, campaignId, custType));
} }
@Log(title = "我的客户-异步导入企业客户价值分层", businessType = com.ruoyi.common.enums.BusinessType.IMPORT)
@PostMapping(value = "/importBusinessCustLevelAsync", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiOperation("异步导入企业客户价值分层")
public AjaxResult importBusinessCustLevelAsync(@RequestPart("file") MultipartFile file) {
return AjaxResult.success("导入任务已提交,后台正在处理", myCustomerService.importBusinessCustLevelAsync(file));
}
@Log(title = "我的客户-查询企业客户价值分层导入状态")
@GetMapping("/importBusinessCustLevelStatus/{taskId}")
@ApiOperation("查询企业客户价值分层导入状态")
public AjaxResult importBusinessCustLevelStatus(@PathVariable String taskId) {
return AjaxResult.success(myCustomerService.getBusinessCustLevelImportStatus(taskId));
}
} }

View File

@@ -0,0 +1,14 @@
package com.ruoyi.ibs.customerselect.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
@Data
public class BusinessCustLevelImportExcelDTO {
@ExcelProperty("统信码")
private String socialCreditCode;
@ExcelProperty("价值分层")
private String custLevel;
}

View File

@@ -0,0 +1,30 @@
package com.ruoyi.ibs.customerselect.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class BusinessCustLevelImportTaskVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 0-处理中 1-成功 2-失败
*/
private String status;
private String message;
private Integer totalCount;
private Integer successCount;
private Integer ignoredCount;
private String userName;
private String createTime;
private String finishTime;
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.ibs.customerselect.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.common.core.domain.entity.CustInfoBusiness; import com.ruoyi.common.core.domain.entity.CustInfoBusiness;
import com.ruoyi.ibs.customerselect.domain.BusinessCustLevelImportExcelDTO;
import com.ruoyi.ibs.customerselect.domain.CustBaseInfo; import com.ruoyi.ibs.customerselect.domain.CustBaseInfo;
import com.ruoyi.ibs.customerselect.domain.CustInfoDeleteFromAnchor; import com.ruoyi.ibs.customerselect.domain.CustInfoDeleteFromAnchor;
import com.ruoyi.ibs.customerselect.domain.CustInfoUpdateFromAnchor; import com.ruoyi.ibs.customerselect.domain.CustInfoUpdateFromAnchor;
@@ -242,4 +243,10 @@ public interface CustInfoBusinessMapper extends BaseMapper<CustInfoBusiness>
public int insertCustomersToBusinessByScCode(List<SysGroupCustomer> sysGroupCustomers); public int insertCustomersToBusinessByScCode(List<SysGroupCustomer> sysGroupCustomers);
List<CustInfoBusiness> selectRecord(String socialCreditCode); List<CustInfoBusiness> selectRecord(String socialCreditCode);
List<String> selectExistingSocialCreditCodes(@Param("socialCreditCodes") List<String> socialCreditCodes,
@Param("deptCode") String deptCode);
int batchUpdateCustLevelBySocialCreditCode(@Param("list") List<BusinessCustLevelImportExcelDTO> list,
@Param("deptCode") String deptCode);
} }

View File

@@ -1,6 +1,7 @@
package com.ruoyi.ibs.customerselect.service; package com.ruoyi.ibs.customerselect.service;
import com.ruoyi.ibs.customerselect.domain.*; import com.ruoyi.ibs.customerselect.domain.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List; import java.util.List;
@@ -41,4 +42,8 @@ public interface IMyCustomerService {
public CustListSearchVo selectCustomListSearchVo(CustBaseInfo sysCustomerBasedata); public CustListSearchVo selectCustomListSearchVo(CustBaseInfo sysCustomerBasedata);
MerchantMcspInfo selectmerchantMessage(String custId); MerchantMcspInfo selectmerchantMessage(String custId);
String importBusinessCustLevelAsync(MultipartFile file);
BusinessCustLevelImportTaskVO getBusinessCustLevelImportStatus(String taskId);
} }

View File

@@ -1,13 +1,19 @@
package com.ruoyi.ibs.customerselect.service.Impl; package com.ruoyi.ibs.customerselect.service.Impl;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.DataScope; import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.CustInfoBusiness; import com.ruoyi.common.core.domain.entity.CustInfoBusiness;
import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.ibs.dashboard.service.NotificationService;
import com.ruoyi.ibs.customerselect.domain.BusinessCustLevelImportExcelDTO;
import com.ruoyi.ibs.customerselect.domain.BusinessCustLevelImportTaskVO;
import com.ruoyi.ibs.customerselect.domain.*; import com.ruoyi.ibs.customerselect.domain.*;
import com.ruoyi.ibs.customerselect.domain.vo.GridRelateVO; import com.ruoyi.ibs.customerselect.domain.vo.GridRelateVO;
import com.ruoyi.ibs.customerselect.mapper.CustInfoBusinessMapper; import com.ruoyi.ibs.customerselect.mapper.CustInfoBusinessMapper;
@@ -32,9 +38,16 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -45,6 +58,10 @@ import java.util.stream.Collectors;
@Service @Service
public class MyCustomerServiceImpl implements IMyCustomerService { public class MyCustomerServiceImpl implements IMyCustomerService {
private static final String BUSINESS_CUST_LEVEL_IMPORT_TASK_KEY = "BUSINESS_CUST_LEVEL_IMPORT_TASK_";
private static final int BUSINESS_CUST_LEVEL_IMPORT_BATCH_SIZE = 1000;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Autowired @Autowired
private CustInfoBusinessMapper custInfoBusinessMapper; private CustInfoBusinessMapper custInfoBusinessMapper;
@@ -80,6 +97,12 @@ public class MyCustomerServiceImpl implements IMyCustomerService {
@Resource @Resource
private RedisCache redisCache; private RedisCache redisCache;
@Resource
private NotificationService notificationService;
@Resource(name = "excelImportExecutor")
private ExecutorService excelImportExecutor;
private static Logger logger = LoggerFactory.getLogger(MyCustomerServiceImpl.class); private static Logger logger = LoggerFactory.getLogger(MyCustomerServiceImpl.class);
/** /**
@@ -467,5 +490,154 @@ public class MyCustomerServiceImpl implements IMyCustomerService {
return merchantMcspInfoMapper.selectOne(new LambdaQueryWrapper<MerchantMcspInfo>().eq(MerchantMcspInfo::getCustId,custId)); return merchantMcspInfoMapper.selectOne(new LambdaQueryWrapper<MerchantMcspInfo>().eq(MerchantMcspInfo::getCustId,custId));
} }
@Override
public String importBusinessCustLevelAsync(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new ServiceException("导入文件不能为空");
}
byte[] fileBytes;
try {
fileBytes = file.getBytes();
} catch (IOException e) {
throw new ServiceException("读取导入文件失败");
}
String taskId = IdUtils.fastSimpleUUID();
String userName = SecurityUtils.getUsername();
String deptCode = SecurityUtils.getHeadId();
BusinessCustLevelImportTaskVO taskVO = new BusinessCustLevelImportTaskVO();
taskVO.setStatus("0");
taskVO.setMessage("导入任务已提交,后台正在处理");
taskVO.setTotalCount(0);
taskVO.setSuccessCount(0);
taskVO.setIgnoredCount(0);
taskVO.setUserName(userName);
taskVO.setCreateTime(formatNow());
cacheBusinessCustLevelImportTask(taskId, taskVO);
excelImportExecutor.submit(() -> doImportBusinessCustLevel(taskId, userName, deptCode, fileBytes));
return taskId;
}
@Override
public BusinessCustLevelImportTaskVO getBusinessCustLevelImportStatus(String taskId) {
BusinessCustLevelImportTaskVO taskVO = redisCache.getCacheObject(getBusinessCustLevelImportTaskKey(taskId));
if (taskVO == null) {
throw new ServiceException("导入任务不存在或已过期");
}
return taskVO;
}
private void doImportBusinessCustLevel(String taskId, String userName, String deptCode, byte[] fileBytes) {
BusinessCustLevelImportTaskVO taskVO = redisCache.getCacheObject(getBusinessCustLevelImportTaskKey(taskId));
if (taskVO == null) {
taskVO = new BusinessCustLevelImportTaskVO();
taskVO.setUserName(userName);
taskVO.setCreateTime(formatNow());
}
try {
List<BusinessCustLevelImportExcelDTO> importRows = EasyExcel.read(new ByteArrayInputStream(fileBytes))
.head(BusinessCustLevelImportExcelDTO.class)
.sheet()
.doReadSync();
Map<String, String> levelMap = new LinkedHashMap<>();
if (importRows != null) {
for (BusinessCustLevelImportExcelDTO row : importRows) {
String socialCreditCode = normalizeImportCell(row.getSocialCreditCode());
String custLevel = normalizeImportCell(row.getCustLevel());
if (StringUtils.isEmpty(socialCreditCode)) {
continue;
}
levelMap.put(socialCreditCode, custLevel);
}
}
if (levelMap.isEmpty()) {
throw new ServiceException("Excel中未识别到有效的统信码和价值分层数据");
}
List<String> existingSocialCreditCodes = getExistingBusinessSocialCreditCodes(new ArrayList<>(levelMap.keySet()), deptCode);
Set<String> existingCodeSet = new HashSet<>(existingSocialCreditCodes);
List<BusinessCustLevelImportExcelDTO> updateList = new ArrayList<>();
for (Map.Entry<String, String> entry : levelMap.entrySet()) {
if (!existingCodeSet.contains(entry.getKey())) {
continue;
}
BusinessCustLevelImportExcelDTO dto = new BusinessCustLevelImportExcelDTO();
dto.setSocialCreditCode(entry.getKey());
dto.setCustLevel(entry.getValue());
updateList.add(dto);
}
batchUpdateBusinessCustLevel(updateList, deptCode);
int totalCount = levelMap.size();
int successCount = updateList.size();
int ignoredCount = totalCount - successCount;
String message = String.format("公司客户视图分层分类数据导入完成,成功更新%d条忽略%d条", successCount, ignoredCount);
taskVO.setStatus("1");
taskVO.setMessage(message);
taskVO.setTotalCount(totalCount);
taskVO.setSuccessCount(successCount);
taskVO.setIgnoredCount(ignoredCount);
taskVO.setFinishTime(formatNow());
cacheBusinessCustLevelImportTask(taskId, taskVO);
notificationService.sendNotification(userName, message);
} catch (Exception e) {
String errorMsg = StringUtils.isNotEmpty(e.getMessage()) ? e.getMessage() : "导入失败,请检查文件内容";
taskVO.setStatus("2");
taskVO.setMessage(errorMsg);
taskVO.setFinishTime(formatNow());
cacheBusinessCustLevelImportTask(taskId, taskVO);
notificationService.sendNotification(userName, "公司客户视图分层分类数据导入失败:" + errorMsg);
logger.error("公司客户视图分层分类数据导入失败taskId={}", taskId, e);
}
}
private void batchUpdateBusinessCustLevel(List<BusinessCustLevelImportExcelDTO> updateList, String deptCode) {
if (updateList == null || updateList.isEmpty()) {
return;
}
for (int i = 0; i < updateList.size(); i += BUSINESS_CUST_LEVEL_IMPORT_BATCH_SIZE) {
int endIndex = Math.min(i + BUSINESS_CUST_LEVEL_IMPORT_BATCH_SIZE, updateList.size());
custInfoBusinessMapper.batchUpdateCustLevelBySocialCreditCode(updateList.subList(i, endIndex), deptCode);
}
}
private List<String> getExistingBusinessSocialCreditCodes(List<String> socialCreditCodes, String deptCode) {
if (socialCreditCodes == null || socialCreditCodes.isEmpty()) {
return Collections.emptyList();
}
List<String> existingSocialCreditCodes = new ArrayList<>();
for (int i = 0; i < socialCreditCodes.size(); i += BUSINESS_CUST_LEVEL_IMPORT_BATCH_SIZE) {
int endIndex = Math.min(i + BUSINESS_CUST_LEVEL_IMPORT_BATCH_SIZE, socialCreditCodes.size());
List<String> batchCodes = socialCreditCodes.subList(i, endIndex);
List<String> batchResult = custInfoBusinessMapper.selectExistingSocialCreditCodes(batchCodes, deptCode);
if (batchResult != null && !batchResult.isEmpty()) {
existingSocialCreditCodes.addAll(batchResult);
}
}
return existingSocialCreditCodes;
}
private void cacheBusinessCustLevelImportTask(String taskId, BusinessCustLevelImportTaskVO taskVO) {
redisCache.setCacheObject(getBusinessCustLevelImportTaskKey(taskId), taskVO, 24, TimeUnit.HOURS);
}
private String getBusinessCustLevelImportTaskKey(String taskId) {
return BUSINESS_CUST_LEVEL_IMPORT_TASK_KEY + taskId;
}
private String normalizeImportCell(String value) {
if (value == null) {
return null;
}
String trimmedValue = value.trim();
return trimmedValue.isEmpty() ? null : trimmedValue;
}
private String formatNow() {
return LocalDateTime.now().format(DATE_TIME_FORMATTER);
}
} }

View File

@@ -173,6 +173,7 @@ public class DashboardController extends BaseController {
public TableDataInfo list(SysNotice notice) public TableDataInfo list(SysNotice notice)
{ {
startPage(); startPage();
notice.setCurrentHeadDeptId(SecurityUtils.getHeadId() + "000");
List<SysNotice> list = noticeService.selectNoticeList(notice); List<SysNotice> list = noticeService.selectNoticeList(notice);
return getDataTable(list); return getDataTable(list);
} }

View File

@@ -23,44 +23,58 @@ public class Ent9vPortraitOrc implements Serializable {
private String uniscid; private String uniscid;
/** 客户内码 */ /** 客户内码 */
@TableField("cst_id")
private String cstId; private String cstId;
/** 机构号 */ /** 机构号 */
@TableField("org_no")
private String orgNo; private String orgNo;
/** score_1合规经营 */ /** score_1合规经营 */
@TableField("score_1")
private BigDecimal score1; private BigDecimal score1;
/** score_2风险准入 */ /** score_2风险准入 */
@TableField("score_2")
private BigDecimal score2; private BigDecimal score2;
/** score_3高管信用评价 */ /** score_3高管信用评价 */
@TableField("score_3")
private String score3; private String score3;
/** score_4股东信用评价 */ /** score_4股东信用评价 */
@TableField("score_4")
private BigDecimal score4; private BigDecimal score4;
/** score_5社会贡献度 */ /** score_5社会贡献度 */
@TableField("score_5")
private BigDecimal score5; private BigDecimal score5;
/** score_6稳定经营 */ /** score_6稳定经营 */
@TableField("score_6")
private BigDecimal score6; private BigDecimal score6;
/** score_7经营能力 */ /** score_7经营能力 */
@TableField("score_7")
private BigDecimal score7; private BigDecimal score7;
/** score_8偿债能力 */ /** score_8偿债能力 */
@TableField("score_8")
private BigDecimal score8; private BigDecimal score8;
/** score_9潜在代偿资源 */ /** score_9潜在代偿资源 */
@TableField("score_9")
private BigDecimal score9; private BigDecimal score9;
/** 九维总分 */ /** 九维总分 */
@TableField("score_all")
private BigDecimal scoreAll; private BigDecimal scoreAll;
/** 九维总分排名 */ /** 九维总分排名 */
@TableField("score_all_rank")
private BigDecimal scoreAllRank; private BigDecimal scoreAllRank;
/** 会计日期 */ /** 会计日期 */
@TableField("dat_dt")
private String datDt; private String datDt;
} }

View File

@@ -1,5 +1,6 @@
package com.ruoyi.ibs.list.domain; package com.ruoyi.ibs.list.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
@@ -21,206 +22,294 @@ public class NineVFinalInfoOrc implements Serializable {
private String uniscid; private String uniscid;
/** 机构号 */ /** 机构号 */
@TableField("org_no")
private String orgNo; private String orgNo;
/** 一、企业合规经营模块 */
/** 是否存在经营异常名录信息 */ /** 是否存在经营异常名录信息 */
@TableField("score_1_1")
private String score11; private String score11;
/** 是否存在严重违法失信企业名单信息 */ /** 是否存在严重违法失信企业名单信息 */
@TableField("score_1_2")
private String score12; private String score12;
/** 企业环境行为信仰登记是否为"E"或D */ /** 企业环境行为信仰登记是否为"E"或D */
@TableField("score_1_3")
private String score13; private String score13;
/** 是否存在税务重大税收违法黑名单信息 */ /** 是否存在税务重大税收违法黑名单信息 */
@TableField("score_1_4")
private String score14; private String score14;
/** 是否存在拖欠工资黑名单 */ /** 是否存在拖欠工资黑名单 */
@TableField("score_1_5")
private String score15; private String score15;
/** 是否存在工商吊销企业信息 */ /** 是否存在工商吊销企业信息 */
@TableField("score_1_6")
private String score16; private String score16;
/** 二、企业风险准入模块 */
/** 是否存在注销企业信息 */ /** 是否存在注销企业信息 */
@TableField("score_2_1")
private String score21; private String score21;
/** 是否存在执行案件信息 */ /** 是否存在执行案件信息 */
@TableField("score_2_2")
private String score22; private String score22;
/** 是否存在查封信息 */ /** 是否存在查封信息 */
@TableField("score_2_3")
private String score23; private String score23;
/** 是否存在单位未履行生效裁判信息 */ /** 是否存在单位未履行生效裁判信息 */
@TableField("score_2_4")
private String score24; private String score24;
/** 是否存在企业破产清算信息 */ /** 是否存在企业破产清算信息 */
@TableField("score_2_5")
private String score25; private String score25;
/** 是否失信被执行人 */ /** 是否失信被执行人 */
@TableField("score_2_6")
private String score26; private String score26;
/** 是否为诉讼案件被告 */ /** 是否为诉讼案件被告 */
@TableField("score_2_7")
private String score27; private String score27;
/** 三、高管信用评价模块 */
/** 是否存在查封信息(score_3) */ /** 是否存在查封信息(score_3) */
@TableField("score_3_1")
private String score31; private String score31;
/** 是否存在执行案件信息(score_3) */ /** 是否存在执行案件信息(score_3) */
@TableField("score_3_2")
private String score32; private String score32;
/** 是否存在个人未履行生效裁判信息 */ /** 是否存在个人未履行生效裁判信息 */
@TableField("score_3_3")
private String score33; private String score33;
/** 是否存在拖欠工资黑名单(score_3) */ /** 是否存在拖欠工资黑名单(score_3) */
@TableField("score_3_4")
private String score34; private String score34;
/** 是否失信被执行人(score_3) */ /** 是否失信被执行人(score_3) */
@TableField("score_3_5")
private String score35; private String score35;
/** 是否存在刑事案件被告人生效判决信息 */ /** 是否存在刑事案件被告人生效判决信息 */
@TableField("score_3_6")
private String score36; private String score36;
/** 是否为诉讼案件被告(score_3) */ /** 是否为诉讼案件被告(score_3) */
@TableField("score_3_7")
private String score37; private String score37;
/** 四、股东信用评价模块 */
/** 是否存在查封信息(score_4) */ /** 是否存在查封信息(score_4) */
@TableField("score_4_1")
private String score41; private String score41;
/** 是否存在执行案件信息(score_4) */ /** 是否存在执行案件信息(score_4) */
@TableField("score_4_2")
private String score42; private String score42;
/** 是否存在个人未履行生效裁判信息(score_4) */ /** 是否存在个人未履行生效裁判信息(score_4) */
@TableField("score_4_3")
private String score43; private String score43;
/** 是否存在拖欠工资黑名单(score_4) */ /** 是否存在拖欠工资黑名单(score_4) */
@TableField("score_4_4")
private String score44; private String score44;
/** 是否失信被执行人(score_4) */ /** 是否失信被执行人(score_4) */
@TableField("score_4_5")
private String score45; private String score45;
/** 是否存在刑事案件被告人生效判决信息(score_4) */ /** 是否存在刑事案件被告人生效判决信息(score_4) */
@TableField("score_4_6")
private String score46; private String score46;
/** 是否为诉讼案件被告(score_4) */ /** 是否为诉讼案件被告(score_4) */
@TableField("score_4_7")
private String score47; private String score47;
/** 是否存在企业未履行生效裁判信息 */ /** 是否存在企业未履行生效裁判信息 */
@TableField("score_4_8")
private String score48; private String score48;
/** 五、企业社会贡献度模块 */
/** 前12个月纳税金额 */ /** 前12个月纳税金额 */
@TableField("score_5_1")
private String score51; private String score51;
/** 纳税等级 */ /** 纳税等级 */
@TableField("score_5_2")
private String score52; private String score52;
/** 缴纳社保人数 */ /** 缴纳社保人数 */
@TableField("score_5_3")
private String score53; private String score53;
/** 公积金缴纳人数 */ /** 公积金缴纳人数 */
@TableField("score_5_4")
private String score54; private String score54;
/** 是否为出口退税生产清单企业 */ /** 是否为出口退税生产清单企业 */
@TableField("score_5_5")
private String score55; private String score55;
/** 六、企业稳定经营模块 */
/** 市场主体经营年限 */ /** 市场主体经营年限 */
@TableField("score_6_1")
private String score61; private String score61;
/** 股东(或发起人)或投资人信息认缴出资人数 */ /** 股东(或发起人)或投资人信息认缴出资人数 */
@TableField("score_6_2")
private String score62; private String score62;
/** 最大股东持股占比 */ /** 最大股东持股占比 */
@TableField("score_6_3")
private String score63; private String score63;
/** 近三年法定代表人变更次数 */ /** 近三年法定代表人变更次数 */
@TableField("score_6_4")
private String score64; private String score64;
/** 近三年股东变更次数 */ /** 近三年股东变更次数 */
@TableField("score_6_5")
private String score65; private String score65;
/** 近三年经营范围变更次数 */ /** 近三年经营范围变更次数 */
@TableField("score_6_6")
private String score66; private String score66;
/** 近三年经营地址变更次数 */ /** 近三年经营地址变更次数 */
@TableField("score_6_7")
private String score67; private String score67;
/** 近三年缴税年数 */ /** 近三年缴税年数 */
@TableField("score_6_8")
private String score68; private String score68;
/** 法人户籍 */ /** 法人户籍 */
@TableField("score_6_9")
private String score69; private String score69;
/** 法人婚姻状况 */ /** 法人婚姻状况 */
@TableField("score_6_10")
private String score610; private String score610;
/** 七、企业经营能力模块 */
/** 上年增值税金额 */ /** 上年增值税金额 */
@TableField("score_7_1")
private String score71; private String score71;
/** 今年增值税同比变动 */ /** 今年增值税同比变动 */
@TableField("score_7_2")
private String score72; private String score72;
/** 上年企业所得税金额 */ /** 上年企业所得税金额 */
@TableField("score_7_3")
private String score73; private String score73;
/** 今年所得税同比变动 */ /** 今年所得税同比变动 */
@TableField("score_7_4")
private String score74; private String score74;
/** 缴纳社保人数同比变动 */ /** 缴纳社保人数同比变动 */
@TableField("score_7_5")
private String score75; private String score75;
/** 公积金缴纳人数同比变动 */ /** 公积金缴纳人数同比变动 */
@TableField("score_7_6")
private String score76; private String score76;
/** 当年纳税金额同比变动 */ /** 当年纳税金额同比变动 */
@TableField("score_7_7")
private String score77; private String score77;
/** 上年出口退税金额 */ /** 上年出口退税金额 */
@TableField("score_7_8")
private String score78; private String score78;
/** 八、企业偿债能力模块 */
/** 房产套数 */ /** 房产套数 */
@TableField("score_8_1")
private String score81; private String score81;
/** 房产面积 */ /** 房产面积 */
@TableField("score_8_2")
private String score82; private String score82;
/** 未抵押房产套数 */ /** 未抵押房产套数 */
@TableField("score_8_3")
private String score83; private String score83;
/** 未抵押房产面积 */ /** 未抵押房产面积 */
@TableField("score_8_4")
private String score84; private String score84;
/** 已抵押房产被担保债权数额 */ /** 已抵押房产被担保债权数额 */
@TableField("score_8_5")
private String score85; private String score85;
/** 企业车产金额 */ /** 企业车产金额 */
@TableField("score_8_6")
private String score86; private String score86;
/** 九、潜在代偿资源模块 */
/** 法人及股东房产面积合计 */ /** 法人及股东房产面积合计 */
@TableField("score_9_1")
private String score91; private String score91;
/** 法人及股东房产套数合计 */ /** 法人及股东房产套数合计 */
@TableField("score_9_2")
private String score92; private String score92;
/** 法人及股东未抵押房产套数合计 */ /** 法人及股东未抵押房产套数合计 */
@TableField("score_9_3")
private String score93; private String score93;
/** 法人及股东未抵押房产面积 */ /** 法人及股东未抵押房产面积 */
@TableField("score_9_4")
private String score94; private String score94;
/** 法人及股东已抵押房产被担保债权数额合计 */ /** 法人及股东已抵押房产被担保债权数额合计 */
@TableField("score_9_5")
private String score95; private String score95;
/** 法人代表车产金额 */ /** 法人代表车产金额 */
@TableField("score_9_6")
private String score96; private String score96;
/** 十、企业环境信用模块 */
/** 生态信用扣分 */ /** 生态信用扣分 */
@TableField("score_b015")
private String scoreB015; private String scoreB015;
/** 列入环境失信黑名单时间 */ /** 列入环境失信黑名单时间 */
@TableField("score_b016_time")
private String scoreB016Time; private String scoreB016Time;
/** 列入环境失信黑名单原因 */ /** 列入环境失信黑名单原因 */
@TableField("score_b016_reason")
private String scoreB016Reason; private String scoreB016Reason;
/** 环境行为信用评价等级 */ /** 环境行为信用评价等级 */
@TableField("score_a020")
private String scoreA020; private String scoreA020;
} }

View File

@@ -148,15 +148,15 @@ public class CustInfoBusinessServiceImpl implements ICustInfoBusinessService
custInfoBusinessVo.setTagManual(TreeNode.convertToTreeByParentId(tagCreateVos)); custInfoBusinessVo.setTagManual(TreeNode.convertToTreeByParentId(tagCreateVos));
// 仅当登录机构为825时查询九维画像数据 // 仅当登录机构为825时查询九维画像数据
// if ("825".equals(getHeadId())) { if ("965".equals(getHeadId())) {
// LambdaQueryWrapper<Ent9vPortraitOrc> portraitWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Ent9vPortraitOrc> portraitWrapper = new LambdaQueryWrapper<>();
// portraitWrapper.eq(Ent9vPortraitOrc::getUniscid, custInfoBusiness.getSocialCreditCode()); portraitWrapper.eq(Ent9vPortraitOrc::getUniscid, custInfoBusiness.getSocialCreditCode());
// custInfoBusinessVo.setEnt9vPortrait(ent9vPortraitOrcMapper.selectOne(portraitWrapper)); custInfoBusinessVo.setEnt9vPortrait(ent9vPortraitOrcMapper.selectOne(portraitWrapper));
//
// LambdaQueryWrapper<NineVFinalInfoOrc> finalInfoWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<NineVFinalInfoOrc> finalInfoWrapper = new LambdaQueryWrapper<>();
// finalInfoWrapper.eq(NineVFinalInfoOrc::getUniscid, custInfoBusiness.getSocialCreditCode()); finalInfoWrapper.eq(NineVFinalInfoOrc::getUniscid, custInfoBusiness.getSocialCreditCode());
// custInfoBusinessVo.setNineVFinalInfo(nineVFinalInfoOrcMapper.selectOne(finalInfoWrapper)); custInfoBusinessVo.setNineVFinalInfo(nineVFinalInfoOrcMapper.selectOne(finalInfoWrapper));
// } }
} }
return custInfoBusinessVo; return custInfoBusinessVo;
} }

View File

@@ -857,6 +857,28 @@
select id,cust_name from cust_info_business where social_credit_code = #{socialCreditCode} select id,cust_name from cust_info_business where social_credit_code = #{socialCreditCode}
</select> </select>
<select id="selectExistingSocialCreditCodes" resultType="java.lang.String">
select social_credit_code
from cust_info_business_${deptCode}
where social_credit_code in
<foreach item="socialCreditCode" collection="socialCreditCodes" open="(" separator="," close=")">
#{socialCreditCode}
</foreach>
</select>
<update id="batchUpdateCustLevelBySocialCreditCode">
update cust_info_business_${deptCode}
set cust_level = case social_credit_code
<foreach item="item" collection="list">
when #{item.socialCreditCode} then #{item.custLevel}
</foreach>
end
where social_credit_code in
<foreach item="item" collection="list" open="(" separator="," close=")">
#{item.socialCreditCode}
</foreach>
</update>
<insert id="insertCustomersToBusinessByScCode" parameterType="java.util.List"> <insert id="insertCustomersToBusinessByScCode" parameterType="java.util.List">
INSERT INTO cust_info_business INSERT INTO cust_info_business
(cust_id,cust_name, social_credit_code, update_by, update_time, cust_phone, industry, asset, credit) (cust_id,cust_name, social_credit_code, update_by, update_time, cust_phone, industry, asset, credit)
@@ -866,4 +888,4 @@
</foreach> </foreach>
</insert> </insert>
</mapper> </mapper>

View File

@@ -79,7 +79,7 @@ spring:
# 地址 # 地址
host: 116.62.17.81 host: 116.62.17.81
# 端口默认为6379 # 端口默认为6379
port: 6380 port: 6379
# 数据库索引 # 数据库索引
database: 0 database: 0
# 密码 # 密码

View File

@@ -31,6 +31,12 @@ public class SysNotice extends BaseEntity
/** 公告状态0正常 1关闭 */ /** 公告状态0正常 1关闭 */
private String status; private String status;
/** 可见总行部门ID多选逗号分隔 */
private String deptIds;
/** 当前登录用户所属总行部门ID仅用于查询过滤 */
private String currentHeadDeptId;
public Long getNoticeId() public Long getNoticeId()
{ {
return noticeId; return noticeId;
@@ -84,6 +90,26 @@ public class SysNotice extends BaseEntity
return status; return status;
} }
public String getDeptIds()
{
return deptIds;
}
public void setDeptIds(String deptIds)
{
this.deptIds = deptIds;
}
public String getCurrentHeadDeptId()
{
return currentHeadDeptId;
}
public void setCurrentHeadDeptId(String currentHeadDeptId)
{
this.currentHeadDeptId = currentHeadDeptId;
}
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -92,6 +118,7 @@ public class SysNotice extends BaseEntity
.append("noticeType", getNoticeType()) .append("noticeType", getNoticeType())
.append("noticeContent", getNoticeContent()) .append("noticeContent", getNoticeContent())
.append("status", getStatus()) .append("status", getStatus())
.append("deptIds", getDeptIds())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())
.append("updateBy", getUpdateBy()) .append("updateBy", getUpdateBy())

View File

@@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="noticeType" column="notice_type" /> <result property="noticeType" column="notice_type" />
<result property="noticeContent" column="notice_content" /> <result property="noticeContent" column="notice_content" />
<result property="status" column="status" /> <result property="status" column="status" />
<result property="deptIds" column="dept_ids" />
<result property="createBy" column="create_by" /> <result property="createBy" column="create_by" />
<result property="createTime" column="create_time" /> <result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" /> <result property="updateBy" column="update_by" />
@@ -18,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectNoticeVo"> <sql id="selectNoticeVo">
select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, dept_ids, create_by, create_time, update_by, update_time, remark
from sys_notice from sys_notice
</sql> </sql>
@@ -39,6 +40,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createBy != null and createBy != ''"> <if test="createBy != null and createBy != ''">
AND create_by like concat('%', #{createBy}, '%') AND create_by like concat('%', #{createBy}, '%')
</if> </if>
<if test="currentHeadDeptId != null and currentHeadDeptId != ''">
AND (dept_ids is null or dept_ids = '' or find_in_set(#{currentHeadDeptId}, dept_ids))
</if>
</where> </where>
</select> </select>
@@ -48,6 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="noticeType != null and noticeType != '' ">notice_type, </if> <if test="noticeType != null and noticeType != '' ">notice_type, </if>
<if test="noticeContent != null and noticeContent != '' ">notice_content, </if> <if test="noticeContent != null and noticeContent != '' ">notice_content, </if>
<if test="status != null and status != '' ">status, </if> <if test="status != null and status != '' ">status, </if>
<if test="deptIds != null">dept_ids, </if>
<if test="remark != null and remark != ''">remark,</if> <if test="remark != null and remark != ''">remark,</if>
<if test="createBy != null and createBy != ''">create_by,</if> <if test="createBy != null and createBy != ''">create_by,</if>
create_time create_time
@@ -56,6 +61,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="noticeType != null and noticeType != ''">#{noticeType}, </if> <if test="noticeType != null and noticeType != ''">#{noticeType}, </if>
<if test="noticeContent != null and noticeContent != ''">#{noticeContent}, </if> <if test="noticeContent != null and noticeContent != ''">#{noticeContent}, </if>
<if test="status != null and status != ''">#{status}, </if> <if test="status != null and status != ''">#{status}, </if>
<if test="deptIds != null">#{deptIds}, </if>
<if test="remark != null and remark != ''">#{remark},</if> <if test="remark != null and remark != ''">#{remark},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if> <if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate() sysdate()
@@ -69,6 +75,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="noticeType != null and noticeType != ''">notice_type = #{noticeType}, </if> <if test="noticeType != null and noticeType != ''">notice_type = #{noticeType}, </if>
<if test="noticeContent != null">notice_content = #{noticeContent}, </if> <if test="noticeContent != null">notice_content = #{noticeContent}, </if>
<if test="status != null and status != ''">status = #{status}, </if> <if test="status != null and status != ''">status = #{status}, </if>
<if test="deptIds != null">dept_ids = #{deptIds}, </if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
update_time = sysdate() update_time = sysdate()
</set> </set>
@@ -86,4 +93,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
</delete> </delete>
</mapper> </mapper>

View File

@@ -91,4 +91,20 @@ export function uploadTag(data) {
data: data, data: data,
isUpload: true isUpload: true
}) })
} }
export function importBusinessCustLevelAsync(data) {
return request({
url: '/system/custBaseInfo/importBusinessCustLevelAsync',
method: 'post',
data,
isUpload: true
})
}
export function getBusinessCustLevelImportStatus(taskId) {
return request({
url: `/system/custBaseInfo/importBusinessCustLevelStatus/${taskId}`,
method: 'get'
})
}

View File

@@ -41,4 +41,12 @@ export function delNotice(noticeId) {
url: '/system/notice/' + noticeId, url: '/system/notice/' + noticeId,
method: 'delete' method: 'delete'
}) })
} }
// 查询总行列表
export function getHeadList() {
return request({
url: '/system/dept/headList',
method: 'get'
})
}

View File

@@ -168,7 +168,8 @@ export default {
notReadCount: 0, notReadCount: 0,
noticeCenterList: [], noticeCenterList: [],
open2: false, open2: false,
downCenterList: [] downCenterList: [],
noticeCenterTimer: null
}; };
}, },
computed: { computed: {
@@ -192,6 +193,12 @@ export default {
}, },
created() { created() {
this.getCenterList(); this.getCenterList();
this.startNoticePolling();
window.addEventListener('notice-center-refresh', this.getCenterList);
},
beforeDestroy() {
this.clearNoticePolling();
window.removeEventListener('notice-center-refresh', this.getCenterList);
}, },
methods: { methods: {
openModal() { openModal() {
@@ -223,6 +230,18 @@ export default {
} }
}); });
}, },
startNoticePolling() {
this.clearNoticePolling();
this.noticeCenterTimer = setInterval(() => {
this.getCenterList();
}, 10000);
},
clearNoticePolling() {
if (this.noticeCenterTimer) {
clearInterval(this.noticeCenterTimer);
this.noticeCenterTimer = null;
}
},
// 下载中心列表 // 下载中心列表
getDownCenterList() { getDownCenterList() {

View File

@@ -1024,6 +1024,77 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
</el-collapse-item> </el-collapse-item>
<el-collapse-item v-if="is825" name="11">
<template slot="title">
<p class="common-title">企业九维数据</p>
</template>
<div v-if="ent9vPortrait || nineVFinalInfo" class="nine-dimension-data">
<!-- 企业九维画像 -->
<div v-if="ent9vPortrait" class="nine-dimension-section">
<h4 class="section-title">1.企业九维画像</h4>
<div class="nine-dimension-chart-container">
<div class="radar-chart-wrapper">
<div ref="nineDimensionRadar" class="nine-dimension-radar"></div>
</div>
<div class="nine-dimension-summary">
<div class="summary-item">
<span class="summary-label">综合评分</span>
<div class="summary-content">
<span class="summary-value">{{ formatPortraitDisplay(ent9vPortrait.scoreAll) }}</span>
<span class="summary-unit">分</span>
</div>
</div>
<div class="summary-item">
<span class="summary-label">总分排名</span>
<div class="summary-content">
<span class="summary-value is-rank">{{ formatPortraitDisplay(ent9vPortrait.scoreAllRank) }}</span>
<span class="summary-unit">名</span>
</div>
</div>
</div>
</div>
</div>
<!-- 九维细项指标 -->
<div v-if="nineVFinalInfo" class="nine-dimension-section">
<h4 class="section-title">2.九维细项指标</h4>
<div class="nine-dimension-detail-table">
<table class="detail-table">
<tbody>
<template v-for="group in nineDimensionDetailGroups">
<tr
v-for="(row, rowIndex) in group.rows"
:key="`${group.title}-${rowIndex}`"
>
<td
v-if="rowIndex === 0"
class="category-cell"
:rowspan="group.rows.length"
>
{{ group.title }}
</td>
<template v-for="metric in row">
<td :key="`${group.title}-${metric.key}-label`" class="metric-label-cell">
{{ metric.label }}
</td>
<td :key="`${group.title}-${metric.key}-value`" class="metric-value-cell">
{{ formatNineDimensionValue(metric) }}
</td>
</template>
<template v-if="row.length === 1">
<td class="metric-label-cell is-empty"></td>
<td class="metric-value-cell is-empty"></td>
</template>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
<el-empty v-else description="暂无企业九维数据"></el-empty>
</el-collapse-item>
</el-collapse> </el-collapse>
<el-dialog <el-dialog
title="该客户尚未建档,请先进行营销建档" title="该客户尚未建档,请先进行营销建档"
@@ -1215,7 +1286,120 @@ import { downloadFiles } from '@/utils'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { cloneDeep, isEmpty } from 'lodash' import { cloneDeep, isEmpty } from 'lodash'
import _ from 'lodash' import _ from 'lodash'
import * as echarts from 'echarts'
import Custom from '../custom.vue' import Custom from '../custom.vue'
const NINE_DIMENSION_DETAIL_CONFIG = [
{
title: '企业合规经营模块',
metrics: [
{ key: 'score11', label: '是否存在经营异常名录信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score12', label: '是否存在严重违法失信企业名单信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score13', label: '企业环境行为信用等级是否为“E”或“D”', valueMap: { '1': '是', '2': '否' } },
{ key: 'score14', label: '是否存在税务重大税收违法黑名单信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score15', label: '是否存在拖欠工资黑名单', valueMap: { '1': '是', '2': '否' } },
{ key: 'score16', label: '是否存在工商吊销企业信息', valueMap: { '1': '是', '2': '否' } }
]
},
{
title: '企业风险准入模块',
metrics: [
{ key: 'score21', label: '是否存在注销企业信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score22', label: '是否存在执行案件信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score23', label: '是否存在查封信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score24', label: '是否存在单位未履行生效裁判信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score25', label: '是否存在企业破产清算信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score26', label: '是否失信被执行人', valueMap: { '1': '是', '2': '否' } },
{ key: 'score27', label: '是否为诉讼案件被告', valueMap: { '1': '是', '2': '否' } }
]
},
{
title: '高管信用评价模块',
metrics: [
{ key: 'score31', label: '是否存在查封信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score32', label: '是否存在执行案件信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score33', label: '是否存在个人未履行生效裁判信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score34', label: '是否存在拖欠工资黑名单', valueMap: { '1': '是', '2': '否' } },
{ key: 'score35', label: '是否失信被执行人', valueMap: { '1': '是', '2': '否' } },
{ key: 'score36', label: '是否存在刑事案件被告人生效判决信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score37', label: '是否为诉讼案件被告', valueMap: { '1': '是', '2': '否' } }
]
},
{
title: '股东信用评价模块',
metrics: [
{ key: 'score41', label: '是否存在查封信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score42', label: '是否存在执行案件信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score43', label: '是否存在个人未履行生效裁判信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score44', label: '是否存在拖欠工资黑名单', valueMap: { '1': '是', '2': '否' } },
{ key: 'score45', label: '是否失信被执行人', valueMap: { '1': '是', '2': '否' } },
{ key: 'score46', label: '是否存在刑事案件被告人生效判决信息', valueMap: { '1': '是', '2': '否' } },
{ key: 'score47', label: '是否为诉讼案件被告', valueMap: { '1': '是', '2': '否' } },
{ key: 'score48', label: '是否存在企业未履行生效裁判信息', valueMap: { '1': '是', '2': '否' } }
]
},
{
title: '企业社会贡献模块',
metrics: [
{ key: 'score51', label: '前12个月纳税金额', valueMap: { '1': '0', '2': '05万元', '3': '5-10万元', '4': '10-50万元', '5': '50-100万元', '6': '100-500万元', '7': '500-1000万元', '8': '1000万元以上' } },
{ key: 'score52', label: '纳税等级', valueMap: { '1': 'A', '2': 'B', '3': 'M', '4': 'C、D', '5': '未评' } },
{ key: 'score53', label: '缴纳社保人数', valueMap: { '1': '0', '2': '3人以内', '3': '3-10人', '4': '10-30人', '5': '30-50人', '6': '50-100人', '7': '100-500人', '8': '500人以上' } },
{ key: 'score54', label: '公积金缴纳人数', valueMap: { '1': '0', '2': '3人以内', '3': '3-10人', '4': '10-30人', '5': '30-50人', '6': '50-100人', '7': '100-500人', '8': '500人以上' } },
{ key: 'score55', label: '是否为出口退税生产清单企业', valueMap: { '1': '是', '2': '否' } }
]
},
{
title: '企业稳定经营模块',
metrics: [
{ key: 'score61', label: '市场主体经营年限', valueMap: { '1': '1年以内', '2': '1-3年', '3': '3-5年', '4': '5-10年', '5': '10年以上' } },
{ key: 'score62', label: '股东(或发起人)或投资人信息认缴出资人数', valueMap: { '1': '1人独资', '2': '2-5人', '3': '5人以上' } },
{ key: 'score63', label: '股东(或发起人)或投资人信息最大股东持股占比', valueMap: { '1': '10%以内(含)', '2': '10%-30%(含)', '3': '30%-50%(含)', '4': '50%-66.6%(含)', '5': '66.6%以上' } },
{ key: 'score64', label: '近三年法定代表人变更次数', valueMap: { '1': '0次', '2': '1次', '3': '2次', '4': '3次及以上' } },
{ key: 'score65', label: '近三年股东变更次数', valueMap: { '1': '0次', '2': '1次', '3': '2次', '4': '3次及以上' } },
{ key: 'score66', label: '近三年经营范围变更次数', valueMap: { '1': '0次', '2': '1次', '3': '2次', '4': '3次及以上' } },
{ key: 'score67', label: '近三年经营地址变更次数', valueMap: { '1': '0次', '2': '1次', '3': '2次', '4': '3次及以上' } },
{ key: 'score68', label: '近三年缴税年数', valueMap: { '1': '0', '2': '1年', '3': '2年', '4': '3年' } },
{ key: 'score69', label: '法人户籍', valueMap: { '1': '户籍本地、原籍本地', '2': '户籍本地、原籍浙江其他地区', '3': '户籍本地、原籍未浙江', '4': '非本地户籍、浙江籍', '5': '非本地户籍、未浙江籍' } },
{ key: 'score610', label: '法人婚姻状况', valueMap: { '1': '未婚', '2': '已婚', '3': '丧偶', '4': '离婚' } }
]
},
{
title: '企业经营能力模块',
metrics: [
{ key: 'score71', label: '上年增值税金额', valueMap: { '1': '0', '2': '05万元', '3': '5-10万元', '4': '10-30万元', '5': '30-50万元', '6': '50-100万元', '7': '100-500万元', '8': '500-1000万元', '9': '1000万元以上' } },
{ key: 'score72', label: '今年增值税同比变动', valueMap: { '1': '0及以下', '2': '05%(含)', '3': '5%10%(含)', '4': '10%-20%(含)', '5': '20%以上' } },
{ key: 'score73', label: '上年企业所得税金额', valueMap: { '1': '0', '2': '05万元', '3': '5-10万元', '4': '10-30万元', '5': '30-50万元', '6': '50-100万元', '7': '100-500万元', '8': '500-1000万元', '9': '1000万元以上' } },
{ key: 'score74', label: '今年所得税同比变动', valueMap: { '1': '0及以下', '2': '05%(含)', '3': '5%10%(含)', '4': '10%-20%(含)', '5': '20%以上' } },
{ key: 'score75', label: '缴纳社保人数同比变动', valueMap: { '1': '0及以下', '2': '05%(含)', '3': '5%10%(含)', '4': '10%-20%(含)', '5': '20%以上' } },
{ key: 'score76', label: '公积金缴纳人数同比变动', valueMap: { '1': '0及以下', '2': '05%(含)', '3': '5%10%(含)', '4': '10%-20%(含)', '5': '20%以上' } },
{ key: 'score77', label: '当年纳税金额同比变动', valueMap: { '1': '0及以下', '2': '05%(含)', '3': '5%10%(含)', '4': '10%-20%(含)', '5': '20%以上' } },
{ key: 'score78', label: '上年出口退税金额', valueMap: { '1': '0', '2': '05万元', '3': '5-10万元', '4': '10-50万元', '5': '50-100万元', '6': '100万元以上' } }
]
},
{
title: '企业偿债能力模块',
metrics: [
{ key: 'score81', label: '房产套数', valueMap: { '1': '0', '2': '1套', '3': '2套', '4': '3套', '5': '4套及以上' } },
{ key: 'score82', label: '房产面积', valueMap: { '1': '0', '2': '0500平方米', '3': '5001000平方米以下', '4': '1000-3000平方米', '5': '3000-5000平方米', '6': '5000-10000平方米', '7': '10000平方米及以上' } },
{ key: 'score83', label: '未抵押房产套数', valueMap: { '1': '0', '2': '1套', '3': '2套', '4': '3套', '5': '4套及以上' } },
{ key: 'score84', label: '未抵押房产面积', valueMap: { '1': '0', '2': '0500平方米', '3': '5001000平方米以下', '4': '1000-3000平方米', '5': '3000-5000平方米', '6': '5000-10000平方米', '7': '10000平方米及以上' } },
{ key: 'score85', label: '已抵押房产被担保债权数额', valueMap: { '1': '0', '2': '0100万元', '3': '100500万元', '4': '5001000万元', '5': '10003000万元', '6': '30005000万元', '7': '500010000万元', '8': '10000万元以上' } },
{ key: 'score86', label: '企业车产金额', valueMap: { '1': '0', '2': '020万元', '3': '2040万元', '4': '4060万元', '5': '6080万元', '6': '80100万元', '7': '100万元以上' } }
]
},
{
title: '潜在代偿资源模块',
metrics: [
{ key: 'score91', label: '法人代表及股东房产面积合计', valueMap: { '1': '0', '2': '0500平方米', '3': '5001000平方米以下', '4': '1000-3000平方米', '5': '3000-5000平方米', '6': '5000-10000平方米', '7': '10000平方米及以上' } },
{ key: 'score92', label: '法人代表及股东房产套数合计', valueMap: { '1': '0', '2': '1套', '3': '2套', '4': '3套', '5': '4套及以上' } },
{ key: 'score93', label: '法人代表及股东未抵押房产套数合计', valueMap: { '1': '0', '2': '1套', '3': '2套', '4': '3套', '5': '4套及以上' } },
{ key: 'score94', label: '法人代表及股东未抵押房产面积', valueMap: { '1': '0', '2': '0500平方米', '3': '5001000平方米以下', '4': '1000-3000平方米', '5': '3000-5000平方米', '6': '5000-10000平方米', '7': '10000平方米及以上' } },
{ key: 'score95', label: '法人代表及股东已抵押房产被担保债权数额合计', valueMap: { '1': '0', '2': '0100万元', '3': '100500万元', '4': '5001000万元', '5': '10003000万元', '6': '30005000万元', '7': '500010000万元', '8': '10000万元以上' } },
{ key: 'score96', label: '法人代表车产金额', valueMap: { '1': '0', '2': '020万元', '3': '2040万元', '4': '4060万元', '5': '6080万元', '6': '80100万元', '7': '100万元以上' } }
]
}
]
export default { export default {
data() { data() {
var validatePhone = (rule, value, callback) => { var validatePhone = (rule, value, callback) => {
@@ -1347,6 +1531,12 @@ export default {
showTagsList:[], showTagsList:[],
addTagName:"", addTagName:"",
newCustTag:[], newCustTag:[],
// 企业九维数据
ent9vPortrait: null,
nineVFinalInfo: null,
nineDimensionRadarChart: null, // 九维画像雷达图实例
nineDimensionRadarResizeObserver: null,
nineDimensionRadarRenderTimer: null,
regAddress: { regAddress: {
lazy: true, lazy: true,
lazyLoad(node, resolve) { lazyLoad(node, resolve) {
@@ -1403,13 +1593,40 @@ export default {
this.managerOptions = [] this.managerOptions = []
this.authUser = '' this.authUser = ''
} }
},
ent9vPortrait: {
handler(newVal) {
if (!newVal) {
this.destroyNineDimensionRadar()
return
}
this.scheduleNineDimensionRadarRender()
},
deep: true
} }
}, },
components: { components: {
Custom Custom
}, },
computed: { computed: {
...mapGetters(['roles', 'userName']), ...mapGetters(['roles', 'userName', 'deptId']),
nineDimensionDetailGroups() {
return NINE_DIMENSION_DETAIL_CONFIG.map(group => ({
title: group.title,
rows: this.buildNineDimensionRows(group.metrics)
}))
},
nineDimensionScores() {
if (!this.ent9vPortrait) {
return []
}
return [1, 2, 3, 4, 5, 6, 7, 8, 9].map(index =>
this.normalizePortraitScore(this.ent9vPortrait[`score${index}`])
)
},
nineDimensionRadarScale() {
return this.getAdaptiveRadarScale(this.nineDimensionScores)
},
isHeadAdmin() { isHeadAdmin() {
return this.roles.includes('headAdmin') return this.roles.includes('headAdmin')
}, },
@@ -1443,6 +1660,9 @@ export default {
// 海宁 // 海宁
is875() { is875() {
return this.userName.slice(0, 3) === '875' return this.userName.slice(0, 3) === '875'
},
is825() {
return String(this.deptId || '').substring(0, 3) === '825'
} }
}, },
created() { created() {
@@ -1464,6 +1684,16 @@ export default {
// systemUserAllTreeUser().then(res => { // systemUserAllTreeUser().then(res => {
// this.secoureOption = res // this.secoureOption = res
// }) // })
window.addEventListener('resize', this.handleRadarResize);
},
activated() {
this.scheduleNineDimensionRadarRender(120)
},
beforeDestroy() {
this.clearNineDimensionRadarRenderTimer()
this.destroyNineDimensionRadarObserver()
this.destroyNineDimensionRadar()
window.removeEventListener('resize', this.handleRadarResize);
}, },
methods: { methods: {
handleAddTag(){ handleAddTag(){
@@ -1591,6 +1821,9 @@ export default {
this.showTagsList=this.tagsList[0].children[0].children||[]; this.showTagsList=this.tagsList[0].children[0].children||[];
} }
this.tagManualList = cloneDeep(res.data.tagManual) || [] this.tagManualList = cloneDeep(res.data.tagManual) || []
// 企业九维数据
this.ent9vPortrait = res.data.ent9vPortrait || null
this.nineVFinalInfo = res.data.nineVFinalInfo || null
} }
}) })
}, },
@@ -2014,6 +2247,381 @@ export default {
this.managerOptions = response.data; this.managerOptions = response.data;
}); });
}, },
normalizePortraitScore(value) {
const numericValue = Number(value)
return Number.isFinite(numericValue) ? numericValue : 0
},
getAdaptiveRadarScale(scores) {
const maxScore = Math.max(...scores, 0)
if (maxScore <= 0) {
return {
max: 10,
splitNumber: 5,
step: 2
}
}
const splitNumber = 5
const roughStep = maxScore / splitNumber
const magnitude = Math.pow(10, Math.floor(Math.log10(roughStep)))
const normalized = roughStep / magnitude
let niceFactor = 10
if (normalized <= 1) {
niceFactor = 1
} else if (normalized <= 2) {
niceFactor = 2
} else if (normalized <= 2.5) {
niceFactor = 2.5
} else if (normalized <= 5) {
niceFactor = 5
}
const step = niceFactor * magnitude
let max = Math.ceil(maxScore / step) * step
if (max <= maxScore) {
max += step
}
return {
max,
splitNumber,
step
}
},
formatPortraitDisplay(value) {
if (value === null || value === undefined || value === '') {
return '-'
}
const numericValue = Number(value)
if (!Number.isFinite(numericValue)) {
return value
}
return Number.isInteger(numericValue) ? `${numericValue}` : numericValue.toFixed(2)
},
clearNineDimensionRadarRenderTimer() {
if (this.nineDimensionRadarRenderTimer) {
clearTimeout(this.nineDimensionRadarRenderTimer)
this.nineDimensionRadarRenderTimer = null
}
},
scheduleNineDimensionRadarRender(delay = 80) {
this.clearNineDimensionRadarRenderTimer()
this.nineDimensionRadarRenderTimer = setTimeout(() => {
this.initNineDimensionRadar()
}, delay)
},
destroyNineDimensionRadar() {
if (this.nineDimensionRadarChart) {
this.nineDimensionRadarChart.dispose();
this.nineDimensionRadarChart = null;
}
},
destroyNineDimensionRadarObserver() {
if (this.nineDimensionRadarResizeObserver) {
this.nineDimensionRadarResizeObserver.disconnect()
this.nineDimensionRadarResizeObserver = null
}
},
initNineDimensionRadarObserver(chartDom) {
if (!chartDom || typeof ResizeObserver === 'undefined' || this.nineDimensionRadarResizeObserver) {
return
}
this.nineDimensionRadarResizeObserver = new ResizeObserver((entries) => {
const targetRect = entries && entries[0] ? entries[0].contentRect : null
if (this.nineDimensionRadarChart) {
this.handleRadarResize()
return
}
if (targetRect && targetRect.width >= 360 && targetRect.height >= 260) {
this.scheduleNineDimensionRadarRender(0)
}
})
this.nineDimensionRadarResizeObserver.observe(chartDom)
if (chartDom.parentElement) {
this.nineDimensionRadarResizeObserver.observe(chartDom.parentElement)
}
},
formatRadarLabel(label, chunkSize = 7) {
if (!label || label.length <= chunkSize) {
return label
}
const segments = []
for (let index = 0; index < label.length; index += chunkSize) {
segments.push(label.slice(index, index + chunkSize))
}
return segments.join('\n')
},
// 九维画像分数字段标签映射
getPortraitLabel(key) {
const labelMap = {
uniscid: '统一社会信用代码',
cstId: '客户内码',
orgNo: '机构号',
score1: '企业合规经营模块',
score2: '企业风险准入模块',
score3: '高管信用评价模块',
score4: '股东信用评价模块',
score5: '企业社会贡献模块',
score6: '企业稳定经营模块',
score7: '企业经营能力模块',
score8: '企业偿债能力模块',
score9: '潜在代偿资源模块',
scoreAll: '九维总分',
scoreAllRank: '九维总分排名',
datDt: '会计日期'
};
return labelMap[key] || key;
},
// 获取九维画像维度名称列表
getNineDimensionLabels() {
return [
'企业合规经营模块',
'企业风险准入模块',
'高管信用评价模块',
'股东信用评价模块',
'企业社会贡献模块',
'企业稳定经营模块',
'企业经营能力模块',
'企业偿债能力模块',
'潜在代偿资源模块'
];
},
// 初始化九维画像雷达图
initNineDimensionRadar() {
if (!this.ent9vPortrait) {
this.destroyNineDimensionRadar()
return;
}
this.$nextTick(() => {
const chartDom = this.$refs.nineDimensionRadar;
if (!chartDom) return;
this.initNineDimensionRadarObserver(chartDom)
const chartWidth = chartDom.clientWidth || 0
const chartHeight = chartDom.clientHeight || 0
if (chartWidth < 360 || chartHeight < 260) {
this.scheduleNineDimensionRadarRender(140)
return
}
const scores = this.nineDimensionScores
const radarScale = this.nineDimensionRadarScale
const dimensionLabels = this.getNineDimensionLabels()
const isCompactChart = chartWidth > 0 && chartWidth < 760
const currentInstance = echarts.getInstanceByDom(chartDom)
if (currentInstance) {
this.nineDimensionRadarChart = currentInstance
} else {
this.destroyNineDimensionRadar()
this.nineDimensionRadarChart = echarts.init(chartDom);
}
const option = {
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(17, 24, 39, 0.92)',
borderColor: 'rgba(99, 102, 241, 0.35)',
borderWidth: 1,
padding: [10, 14],
textStyle: {
color: '#f8fafc',
fontSize: 13
},
formatter: (params) => {
const lines = dimensionLabels.map((name, index) => `${name}: ${this.formatPortraitDisplay(params.value[index])}`)
return lines.join('<br/>')
}
},
radar: {
indicator: dimensionLabels.map(name => ({ name, max: radarScale.max })),
shape: 'polygon',
splitNumber: radarScale.splitNumber,
radius: isCompactChart ? '76%' : '82%',
center: ['50%', '54%'],
name: {
formatter: name => (isCompactChart ? this.formatRadarLabel(name, 6) : name),
textStyle: {
color: '#364152',
fontSize: isCompactChart ? 13 : 14,
fontWeight: 500
}
},
splitLine: {
lineStyle: {
color: 'rgba(122, 108, 255, 0.34)',
width: 1
}
},
splitArea: {
show: true,
areaStyle: {
color: [
'rgba(107, 114, 128, 0.12)',
'rgba(148, 163, 184, 0.1)',
'rgba(203, 213, 225, 0.08)',
'rgba(226, 232, 240, 0.06)',
'rgba(241, 245, 249, 0.04)'
]
}
},
axisLine: {
lineStyle: {
color: 'rgba(148, 163, 184, 0.4)',
width: 1
}
},
axisNameGap: isCompactChart ? 4 : 8
},
series: [
{
name: '企业九维画像',
type: 'radar',
data: [
{
value: scores,
name: '当前企业',
itemStyle: {
color: '#ffbf2f'
},
areaStyle: {
color: 'rgba(255, 191, 47, 0.68)'
},
lineStyle: {
color: '#f5b700',
width: 2.5
},
symbol: 'circle',
symbolSize: 6
}
]
}
],
animationDuration: 650
};
this.nineDimensionRadarChart.setOption(option);
this.handleRadarResize()
setTimeout(() => {
this.handleRadarResize()
}, 120)
});
},
// 处理雷达图窗口大小变化
handleRadarResize() {
if (this.nineDimensionRadarChart) {
this.$nextTick(() => {
this.nineDimensionRadarChart.resize();
})
}
},
buildNineDimensionRows(metrics) {
const rows = []
for (let index = 0; index < metrics.length; index += 2) {
const firstMetric = metrics[index]
const secondMetric = metrics[index + 1]
rows.push([
{
...firstMetric,
value: this.nineVFinalInfo ? this.nineVFinalInfo[firstMetric.key] : null
},
...(secondMetric
? [{
...secondMetric,
value: this.nineVFinalInfo ? this.nineVFinalInfo[secondMetric.key] : null
}]
: [])
])
}
return rows
},
formatNineDimensionValue(metric) {
const value = metric ? metric.value : null
if (value === null || value === undefined || value === '') {
return '-'
}
const rawValue = `${value}`.trim()
const normalizedValue = /^-?\d+(\.0+)?$/.test(rawValue) ? `${Number(rawValue)}` : rawValue
if (metric && metric.valueMap) {
if (Object.prototype.hasOwnProperty.call(metric.valueMap, normalizedValue)) {
return metric.valueMap[normalizedValue]
}
if (Object.prototype.hasOwnProperty.call(metric.valueMap, rawValue)) {
return metric.valueMap[rawValue]
}
}
if (metric && metric.label && metric.label.includes('是否')) {
if (['1', 1, true, 'true', 'TRUE', '是'].includes(value)) {
return '是'
}
if (['2', 2, false, 'false', 'FALSE', '否'].includes(value)) {
return '否'
}
}
return value
},
// 九维详细信息字段标签映射(部分常用字段)
getFinalInfoLabel(key) {
const labelMap = {
uniscid: '统一社会信用代码',
orgNo: '机构号',
// 维度1 - 合规经营
score11: '是否存在经营异常名录信息',
score12: '是否存在严重违法失信企业名单信息',
score13: '企业环境行为信用等级是否为E或D',
score14: '是否存在税务重大税收违法黑名单信息',
score15: '是否存在拖欠工资黑名单',
score16: '是否存在工商吊销企业信息',
// 维度2 - 风险准入
score21: '是否存在注销企业信息',
score22: '是否存在执行案件信息',
score23: '是否存在查封信息',
score24: '是否存在单位未履行生效裁判信息',
score25: '是否存在企业破产清算信息',
score26: '是否失信被执行人',
score27: '是否为诉讼案件被告',
// 维度5 - 社会贡献度
score51: '前12个月纳税金额',
score52: '纳税等级',
score53: '缴纳社保人数',
score54: '公积金缴纳人数',
score55: '是否为出口退税生产清单企业',
// 维度6 - 稳定经营
score61: '市场主体经营年限',
score62: '认缴出资人数',
score63: '最大股东持股占比',
score64: '近三年法定代表人变更次数',
score65: '近三年股东变更次数',
score69: '法人户籍',
score610: '法人婚姻状况',
// 维度7 - 经营能力
score71: '上年增值税金额',
score72: '今年增值税同比变动',
score73: '上年企业所得税金额',
score74: '今年所得税同比变动',
score75: '缴纳社保人数同比变动',
score77: '当年纳税金额同比变动',
score78: '上年出口退税金额',
// 维度8 - 偿债能力
score81: '房产套数',
score82: '房产面积',
score83: '未抵押房产套数',
score84: '未抵押房产面积',
score85: '已抵押房产被担保债权数额',
score86: '企业车产金额'
};
return labelMap[key] || key;
},
} }
} }
</script> </script>
@@ -2405,4 +3013,210 @@ export default {
width: 320px !important; width: 320px !important;
} }
} }
// 企业九维数据样式
.nine-dimension-data {
padding: 20px 0;
background: linear-gradient(180deg, #ffffff 0%, #f8fbff 100%);
border-radius: 14px;
.nine-dimension-section {
margin-bottom: 30px;
&:last-child {
margin-bottom: 0;
}
.section-title {
font-size: 15px;
font-weight: 600;
color: #202938;
margin-bottom: 18px;
padding-bottom: 12px;
border-bottom: 1px solid #edf1f7;
}
.nine-dimension-chart-container {
display: flex;
align-items: stretch;
gap: 30px;
padding: 26px 30px;
justify-content: space-between;
background: linear-gradient(135deg, #ffffff 0%, #fbfcff 100%);
border: 1px solid #e7edf7;
border-radius: 14px;
box-shadow: 0 8px 26px rgba(31, 55, 88, 0.06);
.radar-chart-wrapper {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: stretch;
padding: 4px 18px 4px 0;
border-right: 1px solid #edf1f7;
.nine-dimension-radar {
width: 100%;
max-width: none;
height: 430px;
margin: 0 auto;
}
}
.nine-dimension-summary {
width: 236px;
flex-shrink: 0;
padding: 18px 20px;
background: #fff;
border: 1px solid #edf1f7;
border-radius: 12px;
box-shadow: 0 12px 28px rgba(34, 65, 120, 0.08);
align-self: center;
.summary-item {
display: flex;
flex-direction: column;
gap: 10px;
padding: 16px 0;
border-bottom: 1px solid #edf1f7;
&:last-child {
padding-bottom: 6px;
border-bottom: 0;
}
.summary-label {
display: block;
font-size: 15px;
color: #202938;
font-weight: 600;
}
.summary-content {
display: flex;
align-items: baseline;
justify-content: flex-end;
gap: 8px;
}
.summary-value {
display: block;
font-size: 40px;
line-height: 1;
font-weight: 700;
color: #1f6feb;
letter-spacing: -1px;
&.is-rank {
color: #22c55e;
}
}
.summary-unit {
font-size: 18px;
font-weight: 600;
color: #202938;
}
}
}
}
.nine-dimension-detail-table {
overflow-x: auto;
.detail-table {
width: 100%;
min-width: 980px;
border-collapse: collapse;
table-layout: fixed;
border: 1px solid #ebeef5;
td {
padding: 18px 16px;
border: 1px solid #ebeef5;
font-size: 13px;
line-height: 1.6;
color: #303133;
vertical-align: middle;
word-break: break-word;
}
.category-cell {
width: 184px;
background: #eef3f9;
color: #1f6feb;
font-size: 15px;
font-weight: 700;
text-align: center;
}
.metric-label-cell {
background: #f6f8fb;
font-weight: 600;
}
.metric-value-cell {
width: 120px;
background: #fff;
font-weight: 500;
text-align: center;
}
.is-empty {
background: #fff;
}
}
}
.data-item {
margin-bottom: 12px;
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
.data-label {
display: inline-block;
width: 120px;
font-size: 14px;
color: #606266;
font-weight: 500;
}
.data-value {
font-size: 14px;
color: #303133;
}
}
}
}
@media (max-width: 1400px) {
.nine-dimension-data {
.nine-dimension-section {
.nine-dimension-chart-container {
flex-direction: column;
align-items: stretch;
.radar-chart-wrapper {
padding-right: 0;
border-right: 0;
border-bottom: 1px solid #edf1f7;
padding-bottom: 18px;
margin-bottom: 4px;
.nine-dimension-radar {
max-width: 100%;
height: 390px;
}
}
.nine-dimension-summary {
width: 100%;
}
}
}
}
}
</style> </style>

View File

@@ -142,6 +142,29 @@
<el-dropdown-item @click.native="handleExportAll">导出前1000条<i class="quesiton"></i></el-dropdown-item> <el-dropdown-item @click.native="handleExportAll">导出前1000条<i class="quesiton"></i></el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
<template v-if="selectedTab === '2' && is825">
<div class="import-action">
<el-upload
ref="businessImportUploadRef"
class="business-import-upload"
action="#"
:show-file-list="false"
:http-request="requestBusinessCustLevelImport"
:before-upload="beforeBusinessCustLevelUpload"
:disabled="businessImportLoading"
>
<el-button
icon="el-icon-upload2"
type="primary"
style="margin-left: 10px"
:loading="businessImportLoading"
>导入</el-button>
</el-upload>
<el-tooltip placement="top" trigger="hover" content="导入更新公司客户视图分层分类数据" width="200">
<span class="import-question"><i class="el-icon-question"></i></span>
</el-tooltip>
</div>
</template>
<upload-tag style="margin-left: 10px" v-if="selectedTab === '0' && userName.indexOf('931') === 0"></upload-tag> <upload-tag style="margin-left: 10px" v-if="selectedTab === '0' && userName.indexOf('931') === 0"></upload-tag>
</div> </div>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="searchColoumns" <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="searchColoumns"
@@ -180,7 +203,16 @@
</div> </div>
</template> </template>
<script> <script>
import { getCustomerList, getCustAddressList, getPerIndcList, getGegionList, getDrawList, getVirtualList } from '@/api/grid/mycustomer.js' import {
getCustomerList,
getCustAddressList,
getPerIndcList,
getGegionList,
getDrawList,
getVirtualList,
importBusinessCustLevelAsync,
getBusinessCustLevelImportStatus
} from '@/api/grid/mycustomer.js'
import GroupCheck from './components/group-check' import GroupCheck from './components/group-check'
import GroupCheckMore from './components/group-check-more' import GroupCheckMore from './components/group-check-more'
import UploadTag from './components/uploadTag.vue' import UploadTag from './components/uploadTag.vue'
@@ -288,6 +320,8 @@ export default {
showMoreIndc: true, showMoreIndc: true,
contiKeys: [], contiKeys: [],
iscollapsed: false, iscollapsed: false,
businessImportLoading: false,
businessImportTimer: null,
} }
}, },
watch: { watch: {
@@ -342,6 +376,9 @@ export default {
isOps() { isOps() {
return this.roles.includes('headOps') return this.roles.includes('headOps')
}, },
is825() {
return String(this.deptId || '').substring(0, 3) === '825'
},
// 客户经理 // 客户经理
isCommonManager() { isCommonManager() {
return this.roles.includes('commonManager') return this.roles.includes('commonManager')
@@ -780,6 +817,63 @@ export default {
) )
} }
}, },
beforeBusinessCustLevelUpload(file) {
const fileName = file.name ? file.name.toLowerCase() : ''
const isExcel = fileName.endsWith('.xls') || fileName.endsWith('.xlsx')
if (!isExcel) {
this.$message.warning('请上传Excel文件')
return false
}
return true
},
async requestBusinessCustLevelImport(fileOut) {
const { file } = fileOut
const formData = new FormData()
formData.append('file', file)
this.businessImportLoading = true
this.clearBusinessImportTimer()
try {
const res = await importBusinessCustLevelAsync(formData)
this.$message.success(res.msg || '导入任务已提交,后台正在处理')
if (res.data) {
this.pollBusinessCustLevelImportStatus(res.data)
}
} finally {
this.businessImportLoading = false
if (this.$refs.businessImportUploadRef) {
this.$refs.businessImportUploadRef.clearFiles()
}
}
},
pollBusinessCustLevelImportStatus(taskId) {
this.clearBusinessImportTimer()
this.businessImportTimer = setInterval(async () => {
try {
const res = await getBusinessCustLevelImportStatus(taskId)
const task = res.data
if (!task || task.status === '0') {
return
}
this.clearBusinessImportTimer()
if (task.status === '1') {
window.dispatchEvent(new Event('notice-center-refresh'))
this.$message.success(task.message || '导入成功')
this.getList()
} else if (task.status === '2') {
window.dispatchEvent(new Event('notice-center-refresh'))
this.$message.error(task.message || '导入失败')
}
} catch (error) {
this.clearBusinessImportTimer()
}
}, 3000)
},
clearBusinessImportTimer() {
if (this.businessImportTimer) {
clearInterval(this.businessImportTimer)
this.businessImportTimer = null
}
}
}, },
created() { created() {
const { query } = this.$route; const { query } = this.$route;
@@ -800,6 +894,9 @@ export default {
this.initGetSecondRegionList() this.initGetSecondRegionList()
this.initgetDrawList() this.initgetDrawList()
this.initGetVirtualList() this.initGetVirtualList()
},
beforeDestroy() {
this.clearBusinessImportTimer()
} }
} }
</script> </script>
@@ -1062,6 +1159,26 @@ export default {
} }
} }
.import-action {
display: inline-block;
position: relative;
}
.business-import-upload {
display: inline-block;
}
.import-question {
position: absolute;
top: -2px;
right: -14px;
color: #b9b9b9;
font-size: 13px;
cursor: pointer;
line-height: 1;
z-index: 1;
}
.iframe-wrap { .iframe-wrap {
width: 100%; width: 100%;
height: 500px; height: 500px;

View File

@@ -870,10 +870,6 @@ export default {
}, },
// headId为875时便捷操作只显示快速入门 // headId为875时便捷操作只显示快速入门
filteredOptArr() { filteredOptArr() {
// 当deptId以875开头时只保留快速入门
if (this.deptId && String(this.deptId).startsWith('875')) {
return this.optArr.filter(item => item.name === '快速入门')
}
return this.optArr return this.optArr
} }
}, },
@@ -1424,10 +1420,9 @@ export default {
handleSaveSetting() { handleSaveSetting() {
let arr = this.optArr.map(item => { let arr = this.optArr.map(item => {
return item.name return item.name
}) }).filter(name => name && name.trim() !== '') // 过滤掉空值
console.log(arr, 'arrarrarr') console.log(arr, 'arrarrarr')
updateQuickSelect(arr).then(res => { updateQuickSelect(arr).then(res => {
if (res.code == 200) { if (res.code == 200) {
Message.success(res.data) Message.success(res.data)
this.handleSetting() this.handleSetting()

View File

@@ -83,6 +83,11 @@
<dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType"/> <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="可见总行" align="center" min-width="180" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ formatHeadNames(scope.row.deptIds) }}</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="100"> <el-table-column label="状态" align="center" prop="status" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status"/> <dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status"/>
@@ -154,6 +159,25 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24">
<el-form-item label="可见总行" prop="deptIds">
<el-select
v-model="headList"
placeholder="请选择可见总行,不选则全员可见"
multiple
filterable
clearable
style="width: 100%;"
>
<el-option
v-for="item in headOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="内容"> <el-form-item label="内容">
<editor v-model="form.noticeContent" :min-height="192"/> <editor v-model="form.noticeContent" :min-height="192"/>
@@ -170,7 +194,7 @@
</template> </template>
<script> <script>
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"; import { listNotice, getNotice, delNotice, addNotice, updateNotice, getHeadList } from "@/api/system/notice";
export default { export default {
name: "Notice", name: "Notice",
@@ -191,6 +215,10 @@ export default {
total: 0, total: 0,
// 公告表格数据 // 公告表格数据
noticeList: [], noticeList: [],
// 总行选项
headOptions: [],
// 已选总行
headList: [],
// 弹出层标题 // 弹出层标题
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
@@ -218,6 +246,7 @@ export default {
}, },
created() { created() {
this.getList(); this.getList();
this.getHeadOptions();
}, },
methods: { methods: {
/** 查询公告列表 */ /** 查询公告列表 */
@@ -229,6 +258,16 @@ export default {
this.loading = false; this.loading = false;
}); });
}, },
getHeadOptions() {
getHeadList().then(response => {
if (response.code === 200 && Array.isArray(response.data)) {
this.headOptions = response.data.map(item => ({
label: item.deptName,
value: String(item.deptId)
}));
}
});
},
// 取消按钮 // 取消按钮
cancel() { cancel() {
this.open = false; this.open = false;
@@ -241,8 +280,10 @@ export default {
noticeTitle: undefined, noticeTitle: undefined,
noticeType: undefined, noticeType: undefined,
noticeContent: undefined, noticeContent: undefined,
deptIds: undefined,
status: "0" status: "0"
}; };
this.headList = [];
this.resetForm("form"); this.resetForm("form");
}, },
/** 搜索按钮操作 */ /** 搜索按钮操作 */
@@ -273,6 +314,7 @@ export default {
const noticeId = row.noticeId || this.ids const noticeId = row.noticeId || this.ids
getNotice(noticeId).then(response => { getNotice(noticeId).then(response => {
this.form = response.data; this.form = response.data;
this.headList = response.data.deptIds ? response.data.deptIds.split(',').filter(Boolean) : [];
this.open = true; this.open = true;
this.title = "修改公告"; this.title = "修改公告";
}); });
@@ -281,6 +323,7 @@ export default {
submitForm: function() { submitForm: function() {
this.$refs["form"].validate(valid => { this.$refs["form"].validate(valid => {
if (valid) { if (valid) {
this.form.deptIds = Array.isArray(this.headList) && this.headList.length > 0 ? this.headList.join(',') : '';
if (this.form.noticeId != undefined) { if (this.form.noticeId != undefined) {
updateNotice(this.form).then(response => { updateNotice(this.form).then(response => {
this.$modal.msgSuccess("修改成功"); this.$modal.msgSuccess("修改成功");
@@ -306,6 +349,20 @@ export default {
this.getList(); this.getList();
this.$modal.msgSuccess("删除成功"); this.$modal.msgSuccess("删除成功");
}).catch(() => {}); }).catch(() => {});
},
formatHeadNames(deptIds) {
if (!deptIds) {
return '全员可见';
}
const selectedIds = String(deptIds).split(',').filter(Boolean);
if (!selectedIds.length) {
return '全员可见';
}
const nameMap = this.headOptions.reduce((map, item) => {
map[item.value] = item.label;
return map;
}, {});
return selectedIds.map(id => nameMap[id] || id).join('、');
} }
} }
}; };