Compare commits

...

12 Commits

113 changed files with 8056 additions and 1721 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"kiroAgent.configureMCP": "Disabled"
}

View File

@@ -9,7 +9,6 @@ import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.group.domain.dto.CustGroupMemberTemplate;
import com.ruoyi.group.domain.dto.CustGroupQueryDTO;
import com.ruoyi.group.domain.dto.GridImportDTO;
import com.ruoyi.group.domain.entity.CustGroup;
import com.ruoyi.group.domain.vo.CustGroupVO;
import com.ruoyi.group.service.ICustGroupService;
@@ -60,48 +59,31 @@ public class CustGroupController extends BaseController {
return AjaxResult.success(custGroup);
}
/**
* 异步创建客群(网格导入)
*/
@ApiOperation("异步创建客群(网格导入)")
@Log(title = "客群管理-网格导入创建客群", businessType = BusinessType.INSERT)
@PostMapping("/createByGrid")
public AjaxResult createCustGroupByGrid(@RequestBody @Valid GridImportDTO gridImportDTO) {
String id = custGroupService.createCustGroupByGrid(gridImportDTO);
return AjaxResult.success(id);
}
/**
* 异步创建客群(模板导入)
* gridType、regionGridIds、drawGridIds 包含在 dto 中
*/
@ApiOperation("异步创建客群(模板导入)")
@Log(title = "客群管理-异步创建客群", businessType = BusinessType.INSERT)
@PostMapping(value = "/createByTemplate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public AjaxResult createCustGroupByTemplate(@RequestPart("dto") @Valid String dtoJson,
public AjaxResult createCustGroupByTemplate(
@RequestPart("dto") @Valid String dtoJson,
@RequestPart("file") MultipartFile file) {
CustGroup custGroup = JSON.parseObject(dtoJson, CustGroup.class);
return AjaxResult.success(custGroupService.createCustGroupByTemplate(custGroup, file));
}
/**
* 更新客群(网格导入)
*/
@ApiOperation("更新客群(网格导入)")
@Log(title = "客群管理-更新客群(网格导入)", businessType = BusinessType.UPDATE)
@PostMapping("/updateByGrid")
public AjaxResult updateCustGroupByGrid(@RequestBody @Valid GridImportDTO gridImportDTO) {
String result = custGroupService.updateCustGroupByGrid(gridImportDTO);
return AjaxResult.success(result);
return AjaxResult.success("操作成功", custGroupService.createCustGroupByTemplate(custGroup, file));
}
/**
* 更新客群(模板导入)
* gridType、regionGridIds、drawGridIds 包含在 dto 中
* file 参数可选:不传文件则只更新客群信息,传文件则追加客户
*/
@ApiOperation("更新客群(模板导入)")
@Log(title = "客群管理-更新客群(模板导入)", businessType = BusinessType.UPDATE)
@PostMapping(value = "/updateByTemplate", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public AjaxResult updateCustGroupByTemplate(@RequestPart("dto") @Valid String dtoJson,
@RequestPart("file") MultipartFile file) {
public AjaxResult updateCustGroupByTemplate(
@RequestPart("dto") @Valid String dtoJson,
@RequestPart(value = "file", required = false) MultipartFile file) {
CustGroup custGroup = JSON.parseObject(dtoJson, CustGroup.class);
return AjaxResult.success(custGroupService.updateCustGroupByTemplate(custGroup, file));
}
@@ -114,7 +96,7 @@ public class CustGroupController extends BaseController {
@GetMapping("/createStatus/{id}")
public AjaxResult getCreateStatus(@PathVariable Long id) {
String status = custGroupService.getCreateStatus(id);
return AjaxResult.success(status);
return AjaxResult.success("操作成功", status);
}
/**
@@ -139,4 +121,15 @@ public class CustGroupController extends BaseController {
return AjaxResult.success(result);
}
/**
* 获取所有已有的客群标签列表
*/
@ApiOperation("获取所有客群标签")
@Log(title = "客群管理-获取客群标签")
@GetMapping("/tags")
public AjaxResult getAllGroupTags() {
List<String> tags = custGroupService.getAllGroupTags();
return AjaxResult.success(tags);
}
}

View File

@@ -36,7 +36,7 @@ public class CustGroupMemberController extends BaseController {
@GetMapping("/list/{groupId}")
public TableDataInfo listCustGroupMembers(@PathVariable Long groupId,
CustGroupMemberQueryDTO dto) {
startPage();
// 注意:startPage()在Service内部调用因为权限检查会先执行SQL导致分页失效
List<CustGroupMemberVO> list = custGroupMemberService.listCustGroupMembers(groupId, dto);
return getDataTable(list);
}

View File

@@ -0,0 +1,125 @@
package com.ruoyi.group.controller;
import com.github.pagehelper.Page;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.group.domain.entity.GroupCmpmCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCmpmCountLingshou825;
import com.ruoyi.group.domain.entity.GroupCustCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCustCountLingshou825;
import com.ruoyi.group.service.IGroupPerformanceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Api(tags = "客群业绩统计")
@RestController
@RequestMapping("/group/performance")
public class GroupPerformanceController extends BaseController {
@Resource
private IGroupPerformanceService groupPerformanceService;
@ApiOperation("查询零售客群业绩汇总列表")
@GetMapping("/ls/list")
public TableDataPageInfo<GroupCmpmCountLingshou825> selectLsCountList(String dt, String groupName) {
Page<Object> page = startPage();
List<GroupCmpmCountLingshou825> list = groupPerformanceService.selectLsCountList(dt, groupName);
return getDataTable(list, page);
}
@ApiOperation("查询公司客群业绩汇总列表")
@GetMapping("/gs/list")
public TableDataPageInfo<GroupCmpmCountGongsi825> selectGsCountList(String dt, String groupName) {
Page<Object> page = startPage();
List<GroupCmpmCountGongsi825> list = groupPerformanceService.selectGsCountList(dt, groupName);
return getDataTable(list, page);
}
@ApiOperation("查询零售客群客户明细")
@GetMapping("/ls/custList")
public TableDataPageInfo<GroupCustCountLingshou825> selectLsCustList(@RequestParam String groupId,
String custName,
String custIdc,
String dt) {
Page<Object> page = startPage();
List<GroupCustCountLingshou825> list = groupPerformanceService.selectLsCustList(groupId, custName, custIdc, dt);
return getDataTable(list, page);
}
@ApiOperation("查询公司客群客户明细")
@GetMapping("/gs/custList")
public TableDataPageInfo<GroupCustCountGongsi825> selectGsCustList(@RequestParam String groupId,
String custName,
String socialCreditCode,
String dt) {
Page<Object> page = startPage();
List<GroupCustCountGongsi825> list = groupPerformanceService.selectGsCustList(groupId, custName, socialCreditCode, dt);
return getDataTable(list, page);
}
@Log(title = "导出零售客群业绩汇总")
@ApiOperation(value = "导出零售客群业绩汇总", produces = "application/octet-stream")
@GetMapping("/exportLs")
public void exportLs(HttpServletResponse response, String dt, String groupName) {
try {
ExcelUtil<GroupCmpmCountLingshou825> util = new ExcelUtil<>(GroupCmpmCountLingshou825.class);
util.exportExcel(response, groupPerformanceService.selectLsCountList(dt, groupName), "零售客群业绩汇总");
} catch (Exception e) {
logger.error("导出零售客群业绩汇总失败", e);
}
}
@Log(title = "导出公司客群业绩汇总")
@ApiOperation(value = "导出公司客群业绩汇总", produces = "application/octet-stream")
@GetMapping("/exportGs")
public void exportGs(HttpServletResponse response, String dt, String groupName) {
try {
ExcelUtil<GroupCmpmCountGongsi825> util = new ExcelUtil<>(GroupCmpmCountGongsi825.class);
util.exportExcel(response, groupPerformanceService.selectGsCountList(dt, groupName), "公司客群业绩汇总");
} catch (Exception e) {
logger.error("导出公司客群业绩汇总失败", e);
}
}
@Log(title = "导出零售客群客户明细")
@ApiOperation(value = "导出零售客群客户明细", produces = "application/octet-stream")
@GetMapping("/exportLsCust")
public void exportLsCust(HttpServletResponse response,
@RequestParam String groupId,
String custName,
String custIdc,
String dt) {
try {
ExcelUtil<GroupCustCountLingshou825> util = new ExcelUtil<>(GroupCustCountLingshou825.class);
util.exportExcel(response, groupPerformanceService.selectLsCustList(groupId, custName, custIdc, dt), "零售客群客户明细");
} catch (Exception e) {
logger.error("导出零售客群客户明细失败", e);
}
}
@Log(title = "导出公司客群客户明细")
@ApiOperation(value = "导出公司客群客户明细", produces = "application/octet-stream")
@GetMapping("/exportGsCust")
public void exportGsCust(HttpServletResponse response,
@RequestParam String groupId,
String custName,
String socialCreditCode,
String dt) {
try {
ExcelUtil<GroupCustCountGongsi825> util = new ExcelUtil<>(GroupCustCountGongsi825.class);
util.exportExcel(response, groupPerformanceService.selectGsCustList(groupId, custName, socialCreditCode, dt), "公司客群客户明细");
} catch (Exception e) {
logger.error("导出公司客群客户明细失败", e);
}
}
}

View File

@@ -13,6 +13,18 @@ import lombok.Data;
@ApiModel(description = "客群客户查询条件")
public class CustGroupMemberQueryDTO {
/**
* 页码
*/
@ApiModelProperty(value = "页码", hidden = true)
private Integer pageNum;
/**
* 每页数量
*/
@ApiModelProperty(value = "每页数量", hidden = true)
private Integer pageSize;
/**
* 客户类型0=个人, 1=商户, 2=企业
*/
@@ -24,4 +36,34 @@ public class CustGroupMemberQueryDTO {
*/
@ApiModelProperty(value = "客户姓名")
private String custName;
/**
* 客户经理柜员号
*/
@ApiModelProperty(value = "客户经理柜员号")
private String userName;
/**
* 客户经理姓名
*/
@ApiModelProperty(value = "客户经理姓名")
private String nickName;
/**
* 当前用户角色
*/
@ApiModelProperty(value = "当前用户角色", hidden = true)
private String userRole;
/**
* 当前用户名
*/
@ApiModelProperty(value = "当前用户名", hidden = true)
private String currentUserName;
/**
* 当前机构ID
*/
@ApiModelProperty(value = "当前机构ID", hidden = true)
private Long currentDeptId;
}

View File

@@ -39,6 +39,24 @@ public class CustGroupQueryDTO implements Serializable {
@ApiModelProperty(value = "客群状态", name = "groupStatus")
private String groupStatus;
/**
* 客群标签(模糊匹配)
*/
@ApiModelProperty(value = "客群标签", name = "groupTags")
private String groupTags;
/**
* 视图类型mine=我创建的sharedToMe=下发给我的
*/
@ApiModelProperty(value = "视图类型", name = "viewType")
private String viewType;
/**
* 当前用户是否属于总行管理员口径
*/
@ApiModelProperty(value = "当前用户是否总行管理员", hidden = true)
private Boolean headRole;
/**
* 页码
*/

View File

@@ -38,10 +38,10 @@ public class CustGroup {
private String groupMode;
/**
* 创建方式1=模板导入, 2=绩效网格, 3=地理网格, 4=自定义网格
* 客群类型0=零售类(个人+商户), 1=公司类(企业)
*/
@ApiModelProperty(value = "创建方式1=模板导入, 2=绩效网格, 3=地理网格, 4=自定义网格", name = "createMode")
private String createMode;
@ApiModelProperty(value = "客群类型0=零售类(个人+商户), 1=公司类(企业)", name = "groupType")
private String groupType;
/**
* 柜员号
@@ -123,23 +123,18 @@ public class CustGroup {
private String remark;
/**
* 网格类型0=绩效网格, 1=地理网格, 2=绘制网格(动态客群使用
* 客群标签(多个标签用逗号分隔
*/
@ApiModelProperty(value = "网格类型", name = "gridType")
@ApiModelProperty(value = "客群标签(多个标签用逗号分隔)", name = "groupTags")
@TableField("group_tags")
private String groupTags;
/**
* 网格类型0=绩效网格, 1=地理网格, 2=绘制网格(管户关系来源)
*/
@ApiModelProperty(value = "网格类型管户关系来源0=绩效网格, 1=地理网格, 2=绘制网格", name = "gridType")
private String gridType;
/**
* 绩效业务类型retail=零售, corporate=公司(动态客群使用)
*/
@ApiModelProperty(value = "绩效业务类型", name = "cmpmBizType")
private String cmpmBizType;
/**
* 客户经理列表(逗号分隔,动态客群使用)
*/
@ApiModelProperty(value = "客户经理列表", name = "gridUserNames")
private String gridUserNames;
/**
* 地理网格ID列表逗号分隔动态客群使用
*/

View File

@@ -60,6 +60,48 @@ public class CustGroupMember {
@ApiModelProperty(value = "统信码(商户/企业有)", name = "socialCreditCode")
private String socialCreditCode;
/**
* 客户经理柜员号
*/
@ApiModelProperty(value = "客户经理柜员号", name = "userName")
@TableField("user_name")
private String userName;
/**
* 客户经理姓名
*/
@ApiModelProperty(value = "客户经理姓名", name = "nickName")
@TableField("nick_name")
private String nickName;
/**
* 网点ID
*/
@ApiModelProperty(value = "网点ID", name = "outletId")
@TableField("outlet_id")
private Long outletId;
/**
* 网点名称
*/
@ApiModelProperty(value = "网点名称", name = "outletName")
@TableField("outlet_name")
private String outletName;
/**
* 支行ID
*/
@ApiModelProperty(value = "支行ID", name = "branchId")
@TableField("branch_id")
private Long branchId;
/**
* 支行名称
*/
@ApiModelProperty(value = "支行名称", name = "branchName")
@TableField("branch_name")
private String branchName;
/**
* 创建者
*/
@@ -71,6 +113,12 @@ public class CustGroupMember {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/**
* 删除标识0=正常, 1=删除
*/

View File

@@ -0,0 +1,199 @@
package com.ruoyi.group.domain.entity;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.io.Serializable;
/**
* 客群业绩汇总统计_公司825
*/
@Data
public class GroupCmpmCountGongsi825 implements Serializable {
private static final long serialVersionUID = 1L;
@Excel(name = "统计日期")
private String dt;
private String groupId;
@Excel(name = "客群名称")
private String groupName;
@Excel(name = "客群模式")
private String groupMode;
@Excel(name = "归属支行")
private String deptId;
@Excel(name = "归属支行名称")
private String deptName;
@Excel(name = "归属网点")
private String outletsId;
@Excel(name = "归属网点名称")
private String outletsName;
@Excel(name = "归属客户经理")
private String userName;
@Excel(name = "入格客户数")
private Integer custNum;
@Excel(name = "活期存款余额")
private String hqCurBalance;
@Excel(name = "保证金存款余额")
private String bzCurBalance;
@Excel(name = "贷款余额")
private String loanBalanceCny;
@Excel(name = "贴现余额")
private String financeProd711Balance;
@Excel(name = "承兑汇票余额")
private String financeProd716Balance;
@Excel(name = "贷款年日均")
private String loanYearDailyaverage;
@Excel(name = "签发承兑汇票率")
private String qfcdRat;
@Excel(name = "贴现业务率")
private String txRat;
@Excel(name = "保函业务率")
private String bhRat;
@Excel(name = "有效代发工资率")
private String yxdfgzRat;
@Excel(name = "代扣电费率")
private String dkdfRat;
@Excel(name = "代扣水费率")
private String dksfRat;
@Excel(name = "代扣税费率")
private String dkshfRat;
@Excel(name = "票据宝签约率")
private String pjbRat;
@Excel(name = "财资宝签约率")
private String czbRat;
@Excel(name = "收付宝签约率")
private String sfbRat;
@Excel(name = "贸融宝签约率")
private String mrbRat;
@Excel(name = "数字生态产品签约率")
private String szstRat;
@Excel(name = "开户率")
private String khRat;
@Excel(name = "国际结算业务率")
private String gjjsywRat;
@Excel(name = "远期结算汇业务率")
private String yqjshRat;
@Excel(name = "签发承兑汇票数")
private Integer qfcdNum;
@Excel(name = "贴现业务数")
private Integer txNum;
@Excel(name = "保函业务数")
private Integer bhNum;
@Excel(name = "有效代发工资数")
private Integer yxdfgzNum;
@Excel(name = "月均代发工资笔数")
private String ustrCountPerM;
@Excel(name = "月均代发工资金额(元)")
private String ustrBalM;
@Excel(name = "代扣电费数")
private Integer dkdfNum;
@Excel(name = "代扣水费数")
private Integer dksfNum;
@Excel(name = "代扣税费数")
private Integer dkshfNum;
@Excel(name = "票据宝签约数")
private Integer pjbNum;
@Excel(name = "财资宝签约数")
private Integer czbNum;
@Excel(name = "收付宝签约数")
private Integer sfbNum;
@Excel(name = "贸融宝签约数")
private Integer mrbNum;
@Excel(name = "数字生态产品签约数")
private Integer szstNum;
@Excel(name = "开户数")
private Integer khNum;
@Excel(name = "国际结算业务数")
private Integer gjjsywNum;
@Excel(name = "远期结算汇业务数")
private Integer yqjshNum;
private String regionCode;
private String opsDept;
@Excel(name = "合同签约率")
private String htqyRat;
@Excel(name = "合同签约数")
private Integer htqyNum;
private String deptType;
@Excel(name = "近365天已走访人数")
private String zf365cnt;
@Excel(name = "近180天已走访人数")
private String zf180cnt;
@Excel(name = "近90天已走访人数")
private String zf90cnt;
@Excel(name = "近30天已走访人数")
private String zf30cnt;
@Excel(name = "近365天走访率")
private String zf365rt;
@Excel(name = "近180天走访率")
private String zf180rt;
@Excel(name = "近90天走访率")
private String zf90rt;
@Excel(name = "近30天走访率")
private String zf30rt;
@Excel(name = "建档率")
private String phRat;
@Excel(name = "建档数")
private String phNum;
}

View File

@@ -0,0 +1,158 @@
package com.ruoyi.group.domain.entity;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.io.Serializable;
/**
* 客群业绩汇总统计_零售825
*/
@Data
public class GroupCmpmCountLingshou825 implements Serializable {
private static final long serialVersionUID = 1L;
@Excel(name = "统计日期")
private String dt;
private String groupId;
@Excel(name = "客群名称")
private String groupName;
@Excel(name = "客群模式")
private String groupMode;
@Excel(name = "归属支行机构号")
private String deptId;
@Excel(name = "归属支行名称")
private String deptName;
@Excel(name = "归属网点机构号")
private String outletsId;
@Excel(name = "归属网点名称")
private String outletsName;
@Excel(name = "归属客户经理")
private String userName;
@Excel(name = "入格客户数")
private Integer custNum;
@Excel(name = "近365天已走访人数")
private String zf365cnt;
@Excel(name = "近180天已走访人数")
private String zf180cnt;
@Excel(name = "近90天已走访人数")
private String zf90cnt;
@Excel(name = "近30天已走访人数")
private String zf30cnt;
@Excel(name = "近365天走访率")
private String zf365rt;
@Excel(name = "近180天走访率")
private String zf180rt;
@Excel(name = "近90天走访率")
private String zf90rt;
@Excel(name = "近30天走访率")
private String zf30rt;
@Excel(name = "活期存款余额(元)")
private String curBalD;
@Excel(name = "授信率(%")
private String sxRat;
@Excel(name = "用信覆盖率")
private String yxRat;
@Excel(name = "授信户数")
private Integer sxNum;
@Excel(name = "用信户数")
private Integer yxNum;
@Excel(name = "授信金额(合同)")
private String sxBal;
@Excel(name = "贷款余额(元)")
private String balLoan;
@Excel(name = "贷款年日均(元)")
private String loanAve;
@Excel(name = "合同签约率(%")
private String yxhtRat;
@Excel(name = "代扣电费覆盖率(%")
private String dianRat;
@Excel(name = "代扣水费率(%")
private String shuiRat;
@Excel(name = "代扣税费率(%")
private String taxRat;
@Excel(name = "开户率(%")
private String openRat;
@Excel(name = "合同签约客户数")
private Integer yxhtNum;
@Excel(name = "代扣电费客户数")
private Integer dianNum;
@Excel(name = "代扣水费客户数")
private Integer shuiNum;
@Excel(name = "代扣税费数")
private Integer taxNum;
@Excel(name = "开户数")
private Integer openNum;
@Excel(name = "存款余额(元)")
private String depBal;
@Excel(name = "财富余额(元)")
private String finBal;
@Excel(name = "个人核心客户数")
private Integer grhxNum;
@Excel(name = "财富有效客户数")
private Integer cfyxNum;
@Excel(name = "有效信用卡数")
private Integer yxxykNum;
@Excel(name = "有效社保卡户数")
private Integer yxsbkNum;
@Excel(name = "二换三社保卡户数")
private Integer twoTo3SbkNum;
@Excel(name = "养老金迁移至社保卡户数")
private Integer yljToSbkNum;
@Excel(name = "丰收互联客户数")
private Integer fshlNum;
@Excel(name = "有效收单商户")
private Integer yxsdNum;
@Excel(name = "核心收单户数")
private String hxsdNum;
private String regionCode;
private String opsDept;
}

View File

@@ -0,0 +1,138 @@
package com.ruoyi.group.domain.entity;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.io.Serializable;
/**
* 客群客户明细统计_公司825
*/
@Data
public class GroupCustCountGongsi825 implements Serializable {
private static final long serialVersionUID = 1L;
private String groupId;
@Excel(name = "客户名称")
private String custName;
@Excel(name = "客户证件号")
private String socialCreditCode;
@Excel(name = "客户内码")
private String custIsn;
@Excel(name = "活期存款余额")
private String hqCurBalance;
@Excel(name = "保证金存款余额")
private String bzCurBalance;
@Excel(name = "是否授信")
private String isCredit;
@Excel(name = "贷款余额")
private String loanBalanceCny;
@Excel(name = "贷款年日均")
private String loanYearDailyaverage;
@Excel(name = "是否有签发承兑汇票")
private String financeProd716OpenFlag;
@Excel(name = "承兑汇票余额")
private String financeProd716Balance;
@Excel(name = "是否有贴现业务")
private String financeProd711OpenFlag;
@Excel(name = "贴现金额")
private String financeProd711Balance;
@Excel(name = "是否有保函业务")
private String intlBussinessJcbhOpenFlag;
@Excel(name = "是否为有效代发工资客户")
private String isUstr;
@Excel(name = "月均代发工资笔数")
private String ustrCountPerM;
@Excel(name = "月均代发工资金额(元)")
private String ustrBalM;
@Excel(name = "是否代扣电费")
private String elecchargeSignFlag;
@Excel(name = "是否代扣水费")
private String waterchargeSignFlag;
@Excel(name = "是否代扣税费")
private String taxdeductionSignFlag;
@Excel(name = "是否票据宝签约")
private String pjb;
@Excel(name = "是否财资宝签约")
private String czb;
@Excel(name = "是否收付宝签约")
private String sfb;
@Excel(name = "是否贸融宝签约")
private String mrb;
@Excel(name = "是否数字生态产品签约")
private String szst;
@Excel(name = "是否开户")
private String isOpenSts;
@Excel(name = "是否国际结算业务")
private String intlBussinessOpenFlag;
@Excel(name = "是否有远期结算汇业务")
private String intlBussiness325OpenFlag;
private String regionCode;
private String opsDept;
private String custType;
@Excel(name = "是否合同签约")
private String isHtqy;
@Excel(name = "归属支行名称")
private String deptName;
@Excel(name = "归属网点id")
private String outletsId;
@Excel(name = "归属网点名称")
private String outletsName;
@Excel(name = "归属客户经理")
private String userName;
@Excel(name = "归属支行id")
private String deptId;
@Excel(name = "近365天有无走访")
private String is365zf;
@Excel(name = "近180天有无走访")
private String is180zf;
@Excel(name = "近90天有无走访")
private String is90zf;
@Excel(name = "近30天有无走访")
private String is30zf;
private String dt;
@Excel(name = "是否建档")
private String isPh;
}

View File

@@ -0,0 +1,111 @@
package com.ruoyi.group.domain.entity;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.io.Serializable;
/**
* 客群客户明细统计_零售825
*/
@Data
public class GroupCustCountLingshou825 implements Serializable {
private static final long serialVersionUID = 1L;
private String groupId;
@Excel(name = "客户名称")
private String custName;
@Excel(name = "客户证件号")
private String custIdc;
@Excel(name = "客户内码")
private String custIsn;
@Excel(name = "活期存款余额")
private String curBalD;
@Excel(name = "贷款余额")
private String balLoan;
@Excel(name = "贷款年日均")
private String loanAve;
@Excel(name = "是否授信")
private String isSx;
@Excel(name = "是否用信")
private String isYx;
@Excel(name = "授信金额")
private String sxBal;
@Excel(name = "是否合同签约")
private String isYxht;
@Excel(name = "是否持有信用卡")
private String isXyk;
@Excel(name = "是否开通丰收互联")
private String fshl;
@Excel(name = "是否办理收单")
private String isSd;
@Excel(name = "是否代扣电费")
private String dian;
@Excel(name = "是否代扣水费")
private String shui;
@Excel(name = "是否代扣税费")
private String tax;
@Excel(name = "开户数")
private String openNum;
@Excel(name = "存款余额")
private String depBal;
@Excel(name = "财富余额")
private String finBal;
@Excel(name = "是否个人核心客户")
private String isGrhx;
@Excel(name = "是否财富有效客户")
private String isCfyx;
@Excel(name = "是否有效社保卡客户")
private String isYxsbk;
@Excel(name = "是否二换三社保卡")
private String is2to3Sbk;
@Excel(name = "是否养老金迁移至社保卡")
private String isYljToSbk;
private String regionCode;
private String opsDept;
private String custType;
@Excel(name = "近365天有无走访")
private String is365zf;
@Excel(name = "近180天有无走访")
private String is180zf;
@Excel(name = "近90天有无走访")
private String is90zf;
@Excel(name = "近30天有无走访")
private String is30zf;
private String dt;
@Excel(name = "是否核心收单")
private String isHxsd;
}

View File

@@ -57,10 +57,52 @@ public class CustGroupMemberVO {
@ApiModelProperty(value = "统信码(商户/企业有)", name = "socialCreditCode")
private String socialCreditCode;
/**
* 客户经理柜员号
*/
@ApiModelProperty(value = "客户经理柜员号", name = "userName")
private String userName;
/**
* 客户经理姓名
*/
@ApiModelProperty(value = "客户经理姓名", name = "nickName")
private String nickName;
/**
* 网点ID
*/
@ApiModelProperty(value = "网点ID", name = "outletId")
private Long outletId;
/**
* 网点名称
*/
@ApiModelProperty(value = "网点名称", name = "outletName")
private String outletName;
/**
* 支行ID
*/
@ApiModelProperty(value = "支行ID", name = "branchId")
private Long branchId;
/**
* 支行名称
*/
@ApiModelProperty(value = "支行名称", name = "branchName")
private String branchName;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建时间", name = "createTime")
private Date createTime;
/**
* 存量状态true=存量客户系统存在false=非存量客户(系统不存在)
*/
@ApiModelProperty(value = "存量状态true=存量客户false=非存量客户", name = "isExisting")
private Boolean isExisting;
}

View File

@@ -35,10 +35,10 @@ public class CustGroupVO {
private String groupMode;
/**
* 创建方式1=模板导入, 2=绩效网格, 3=地理网格, 4=自定义网格
* 客群类型0=零售类(个人+商户), 1=公司类(企业)
*/
@ApiModelProperty(value = "创建方式1=模板导入, 2=绩效网格, 3=地理网格, 4=自定义网格", name = "createMode")
private String createMode;
@ApiModelProperty(value = "客群类型0=零售类(个人+商户), 1=公司类(企业)", name = "groupType")
private String groupType;
/**
* 柜员号
@@ -114,6 +114,12 @@ public class CustGroupVO {
@ApiModelProperty(value = "备注", name = "remark")
private String remark;
/**
* 客群标签(多个标签用逗号分隔)
*/
@ApiModelProperty(value = "客群标签(多个标签用逗号分隔)", name = "groupTags")
private String groupTags;
/**
* 有效期截止时间
*/
@@ -128,23 +134,11 @@ public class CustGroupVO {
private String createStatus;
/**
* 网格类型0=绩效网格, 1=地理网格, 2=绘制网格
* 网格类型(管户关系来源)0=绩效网格, 1=地理网格, 2=绘制网格
*/
@ApiModelProperty(value = "网格类型", name = "gridType")
@ApiModelProperty(value = "网格类型管户关系来源0=绩效网格, 1=地理网格, 2=绘制网格", name = "gridType")
private String gridType;
/**
* 绩效业务类型retail=零售, corporate=公司
*/
@ApiModelProperty(value = "绩效业务类型", name = "cmpmBizType")
private String cmpmBizType;
/**
* 客户经理列表(逗号分隔)
*/
@ApiModelProperty(value = "客户经理列表", name = "gridUserNames")
private String gridUserNames;
/**
* 地理网格ID列表逗号分隔
*/

View File

@@ -32,7 +32,10 @@ public interface CustGroupMapper extends BaseMapper<CustGroup> {
* @param dto 查询条件
* @return 客群VO列表
*/
List<CustGroupVO> selectCustGroupList(@Param("dto") CustGroupQueryDTO dto);
List<CustGroupVO> selectCustGroupList(@Param("dto") CustGroupQueryDTO dto,
@Param("userName") String userName,
@Param("deptId") String deptId,
@Param("headId") String headId);
/**
* 根据ID查询客群详情
@@ -40,5 +43,39 @@ public interface CustGroupMapper extends BaseMapper<CustGroup> {
* @param id 客群ID
* @return 客群VO
*/
CustGroupVO selectCustGroupById(@Param("id") Long id);
CustGroupVO selectCustGroupById(@Param("id") Long id,
@Param("userName") String userName,
@Param("deptId") String deptId,
@Param("headRole") Boolean headRole,
@Param("headId") String headId);
/**
* 校验当前用户是否有客群查看权限
*
* @param id 客群ID
* @param userName 当前用户名
* @param deptId 当前部门ID
* @return 可查看数量
*/
Long countVisibleCustGroup(@Param("id") Long id,
@Param("userName") String userName,
@Param("deptId") String deptId,
@Param("headRole") Boolean headRole,
@Param("headId") String headId);
/**
* 校验客群是否属于总行管理员共享操作范围
*
* @param id 客群ID
* @return 数量
*/
Long countHeadOperableCustGroup(@Param("id") Long id,
@Param("headId") String headId);
/**
* 查询所有已有的客群标签
*
* @return 标签列表
*/
List<String> selectAllGroupTags();
}

View File

@@ -33,4 +33,29 @@ public interface CustGroupMemberMapper extends BaseMapper<CustGroupMember> {
* @param memberList 客户列表
*/
void batchInsertMembers(@Param("list") List<CustGroupMember> memberList);
/**
* 批量查询个人客户是否存在(根据客户号+身份证号)
*
* @param custIds 客户号列表
* @return 存在的客户号列表
*/
List<String> selectExistingRetailCustIds(@Param("list") List<String> custIds);
/**
* 批量查询商户客户是否存在(根据客户号+统信码)
*
* @param custIds 客户号列表
* @return 存在的客户号列表
*/
List<String> selectExistingMerchantCustIds(@Param("list") List<String> custIds);
/**
* 批量查询企业客户是否存在(根据客户号+统信码)
*
* @param custIds 客户号列表
* @return 存在的客户号列表
*/
List<String> selectExistingBusinessCustIds(@Param("list") List<String> custIds);
}

View File

@@ -0,0 +1,22 @@
package com.ruoyi.group.mapper;
import com.ruoyi.group.domain.entity.GroupCmpmCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCmpmCountLingshou825;
import com.ruoyi.group.domain.entity.GroupCustCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCustCountLingshou825;
import org.apache.ibatis.annotations.Mapper;
import java.util.HashMap;
import java.util.List;
@Mapper
public interface GroupPerformanceMapper {
List<GroupCmpmCountLingshou825> selectLsCountList(HashMap<String, Object> paramMap);
List<GroupCmpmCountGongsi825> selectGsCountList(HashMap<String, Object> paramMap);
List<GroupCustCountLingshou825> selectLsCustList(HashMap<String, Object> paramMap);
List<GroupCustCountGongsi825> selectGsCustList(HashMap<String, Object> paramMap);
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.group.service;
import com.ruoyi.group.domain.dto.CustGroupQueryDTO;
import com.ruoyi.group.domain.dto.GridImportDTO;
import com.ruoyi.group.domain.entity.CustGroup;
import com.ruoyi.group.domain.vo.CustGroupVO;
import org.springframework.web.multipart.MultipartFile;
@@ -17,49 +16,34 @@ public interface ICustGroupService {
/**
* 查询客群列表
*
* @param dto 查询条件
* @return 客群VO列表
*/
List<CustGroupVO> listCustGroup(CustGroupQueryDTO dto);
/**
* 根据ID查询客群详情
*
* @param id 客群ID
* @return 客群VO
*/
CustGroupVO getCustGroup(Long id);
/**
* 校验当前用户是否有客群查看权限
*/
void checkCustGroupViewPermission(Long id);
/**
* 异步创建客群(模板导入)
* gridType、regionGridIds、drawGridIds 从 custGroup 中获取
*
* @param custGroup 客群实体
* @param custGroup 客群实体(包含 gridType、regionGridIds、drawGridIds
* @param file Excel文件
* @return 客群ID
*/
String createCustGroupByTemplate(CustGroup custGroup, MultipartFile file);
/**
* 异步创建客群(网格导入)
*
* @param gridImportDTO 网格导入条件
* @return 客群ID
*/
String createCustGroupByGrid(GridImportDTO gridImportDTO);
/**
* 更新客群(网格导入)
*
* @param gridImportDTO 网格导入条件
* @return 结果消息
*/
String updateCustGroupByGrid(GridImportDTO gridImportDTO);
/**
* 更新客群(模板导入)
* gridType、regionGridIds、drawGridIds 从 custGroup 中获取
*
* @param custGroup 客群实体
* @param custGroup 客群实体(包含 gridType、regionGridIds、drawGridIds
* @param file Excel文件
* @return 结果消息
*/
@@ -67,31 +51,21 @@ public interface ICustGroupService {
/**
* 删除客群
*
* @param idList 客群ID列表
* @return 结果消息
*/
String deleteCustGroup(List<Long> idList);
/**
* 检查客群名称是否存在
*
* @param groupName 客群名称
* @return true=存在, false=不存在
*/
boolean checkGroupNameExist(String groupName);
/**
* 查询客群创建状态
*
* @param id 客群ID
* @return 创建状态0=创建中, 1=创建成功, 2=创建失败
*/
String getCreateStatus(Long id);
/**
* 更新动态客群(定时任务调用)
* 根据原始导入条件重新查询并更新客户列表
*/
void updateDynamicCustGroups();
@@ -100,4 +74,11 @@ public interface ICustGroupService {
*/
void checkAndDisableExpiredGroups();
/**
* 获取所有已有的客群标签列表
*
* @return 标签列表
*/
List<String> getAllGroupTags();
}

View File

@@ -0,0 +1,19 @@
package com.ruoyi.group.service;
import com.ruoyi.group.domain.entity.GroupCmpmCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCmpmCountLingshou825;
import com.ruoyi.group.domain.entity.GroupCustCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCustCountLingshou825;
import java.util.List;
public interface IGroupPerformanceService {
List<GroupCmpmCountLingshou825> selectLsCountList(String dt, String groupName);
List<GroupCmpmCountGongsi825> selectGsCountList(String dt, String groupName);
List<GroupCustCountLingshou825> selectLsCustList(String groupId, String custName, String custIdc, String dt);
List<GroupCustCountGongsi825> selectGsCustList(String groupId, String custName, String socialCreditCode, String dt);
}

View File

@@ -4,14 +4,22 @@ import com.ruoyi.group.domain.dto.CustGroupMemberQueryDTO;
import com.ruoyi.group.domain.entity.CustGroup;
import com.ruoyi.group.domain.entity.CustGroupMember;
import com.ruoyi.group.domain.vo.CustGroupMemberVO;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.group.mapper.CustGroupMapper;
import com.ruoyi.group.mapper.CustGroupMemberMapper;
import com.ruoyi.group.service.ICustGroupService;
import com.ruoyi.group.service.ICustGroupMemberService;
import com.github.pagehelper.PageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 客群客户服务实现类
@@ -27,9 +35,73 @@ public class CustGroupMemberServiceImpl implements ICustGroupMemberService {
@Resource
private CustGroupMapper custGroupMapper;
@Resource
private ICustGroupService custGroupService;
@Override
public List<CustGroupMemberVO> listCustGroupMembers(Long groupId, CustGroupMemberQueryDTO dto) {
return custGroupMemberMapper.selectCustGroupMemberList(groupId, dto);
custGroupService.checkCustGroupViewPermission(groupId);
dto.setUserRole(SecurityUtils.userRole());
dto.setCurrentUserName(SecurityUtils.getUsername());
dto.setCurrentDeptId(SecurityUtils.getDeptId());
// 在权限检查之后启动分页避免权限检查SQL消耗分页设置
int pageNum = dto.getPageNum() != null ? dto.getPageNum() : 1;
int pageSize = dto.getPageSize() != null ? dto.getPageSize() : 10;
PageHelper.startPage(pageNum, pageSize);
// 1. 查询客群成员列表(分页)
List<CustGroupMemberVO> memberList = custGroupMemberMapper.selectCustGroupMemberList(groupId, dto);
if (memberList == null || memberList.isEmpty()) {
return memberList;
}
// 2. 按客户类型分组,批量查询存量状态
// 个人客户
List<String> retailCustIds = memberList.stream()
.filter(m -> "0".equals(m.getCustType()))
.map(CustGroupMemberVO::getCustId)
.collect(Collectors.toList());
// 商户客户
List<String> merchantCustIds = memberList.stream()
.filter(m -> "1".equals(m.getCustType()))
.map(CustGroupMemberVO::getCustId)
.collect(Collectors.toList());
// 企业客户
List<String> businessCustIds = memberList.stream()
.filter(m -> "2".equals(m.getCustType()))
.map(CustGroupMemberVO::getCustId)
.collect(Collectors.toList());
// 3. 批量查询各类型存量客户
Set<String> existingRetailCustIds = new HashSet<>();
Set<String> existingMerchantCustIds = new HashSet<>();
Set<String> existingBusinessCustIds = new HashSet<>();
if (!retailCustIds.isEmpty()) {
existingRetailCustIds.addAll(custGroupMemberMapper.selectExistingRetailCustIds(retailCustIds));
}
if (!merchantCustIds.isEmpty()) {
existingMerchantCustIds.addAll(custGroupMemberMapper.selectExistingMerchantCustIds(merchantCustIds));
}
if (!businessCustIds.isEmpty()) {
existingBusinessCustIds.addAll(custGroupMemberMapper.selectExistingBusinessCustIds(businessCustIds));
}
// 4. 填充存量状态
for (CustGroupMemberVO member : memberList) {
String custType = member.getCustType();
String custId = member.getCustId();
if ("0".equals(custType)) {
member.setIsExisting(existingRetailCustIds.contains(custId));
} else if ("1".equals(custType)) {
member.setIsExisting(existingMerchantCustIds.contains(custId));
} else if ("2".equals(custType)) {
member.setIsExisting(existingBusinessCustIds.contains(custId));
} else {
member.setIsExisting(false);
}
}
return memberList;
}
@Override
@@ -38,7 +110,17 @@ public class CustGroupMemberServiceImpl implements ICustGroupMemberService {
// 检查客群是否存在
CustGroup custGroup = custGroupMapper.selectById(groupId);
if (custGroup == null) {
return "客群不存在";
throw new ServiceException("客群不存在");
}
if (!SecurityUtils.hasRole("headAdmin")
&& !SecurityUtils.hasRole("headPublic")
&& !SecurityUtils.hasRole("headPrivate")
&& !SecurityUtils.hasRole("headOps")) {
throw new ServiceException("无权限操作该客群");
}
Long count = custGroupMapper.countHeadOperableCustGroup(groupId, SecurityUtils.getHeadId());
if (count == null || count <= 0) {
throw new ServiceException("无权限操作该客群");
}
// 删除客户关联
@@ -47,6 +129,7 @@ public class CustGroupMemberServiceImpl implements ICustGroupMemberService {
if (member != null && member.getGroupId().equals(groupId)) {
// 设置手动移除标识
member.setManualRemove(1);
custGroupMemberMapper.updateById(member);
// 逻辑删除
custGroupMemberMapper.deleteById(memberId);
}

View File

@@ -0,0 +1,104 @@
package com.ruoyi.group.service.impl;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.group.domain.entity.GroupCmpmCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCmpmCountLingshou825;
import com.ruoyi.group.domain.entity.GroupCustCountGongsi825;
import com.ruoyi.group.domain.entity.GroupCustCountLingshou825;
import com.ruoyi.group.mapper.GroupPerformanceMapper;
import com.ruoyi.group.service.IGroupPerformanceService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
@Service
public class GroupPerformanceServiceImpl implements IGroupPerformanceService {
@Resource
private GroupPerformanceMapper groupPerformanceMapper;
@Override
public List<GroupCmpmCountLingshou825> selectLsCountList(String dt, String groupName) {
return groupPerformanceMapper.selectLsCountList(buildLsCountParams(dt, groupName));
}
private HashMap<String, Object> buildLsCountParams(String dt, String groupName) {
HashMap<String, Object> paramMap = new HashMap<>();
if (SecurityUtils.userRole().equals("branch")) {
paramMap.put("isBranch", true);
}
if (SecurityUtils.userRole().equals("outlet")) {
paramMap.put("isOutlet", true);
}
if (SecurityUtils.userRole().equals("manager")) {
paramMap.put("isManager", true);
}
paramMap.put("deptId", SecurityUtils.getDeptId());
paramMap.put("userName", SecurityUtils.getUsername());
paramMap.put("dt", dt);
paramMap.put("groupName", groupName);
return paramMap;
}
@Override
public List<GroupCmpmCountGongsi825> selectGsCountList(String dt, String groupName) {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("userRole", "head");
if (SecurityUtils.userRole().equals("branch")) {
paramMap.put("userRole", "branch");
paramMap.put("isBranch", true);
}
if (SecurityUtils.userRole().equals("outlet")) {
paramMap.put("userRole", "outlet");
paramMap.put("isOutlet", true);
}
if (SecurityUtils.userRole().equals("manager")) {
paramMap.put("userRole", "manager");
paramMap.put("isManager", true);
}
paramMap.put("deptId", SecurityUtils.getDeptId());
paramMap.put("userName", SecurityUtils.getUsername());
paramMap.put("dt", dt);
paramMap.put("groupName", groupName);
return groupPerformanceMapper.selectGsCountList(paramMap);
}
@Override
public List<GroupCustCountLingshou825> selectLsCustList(String groupId, String custName, String custIdc, String dt) {
return groupPerformanceMapper.selectLsCustList(buildLsCustParams(groupId, custName, custIdc, dt));
}
private HashMap<String, Object> buildLsCustParams(String groupId, String custName, String custIdc, String dt) {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("deptId", SecurityUtils.getDeptId());
paramMap.put("userName", SecurityUtils.getUsername());
paramMap.put("groupId", groupId);
paramMap.put("custName", custName);
paramMap.put("custIdc", custIdc);
paramMap.put("dt", dt);
return paramMap;
}
@Override
public List<GroupCustCountGongsi825> selectGsCustList(String groupId, String custName, String socialCreditCode, String dt) {
HashMap<String, Object> paramMap = new HashMap<>();
if (SecurityUtils.userRole().equals("branch")) {
paramMap.put("isBranch", true);
}
if (SecurityUtils.userRole().equals("outlet")) {
paramMap.put("isOutlet", true);
}
if (SecurityUtils.userRole().equals("manager")) {
paramMap.put("isManager", true);
}
paramMap.put("deptId", SecurityUtils.getDeptId());
paramMap.put("userName", SecurityUtils.getUsername());
paramMap.put("groupId", groupId);
paramMap.put("custName", custName);
paramMap.put("socialCreditCode", socialCreditCode);
paramMap.put("dt", dt);
return groupPerformanceMapper.selectGsCustList(paramMap);
}
}

View File

@@ -4,18 +4,80 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.group.mapper.CustGroupMapper">
<sql id="custGroupVisibleBaseCondition">
AND (
<choose>
<when test="headRole != null and headRole">
EXISTS (
SELECT 1
FROM sys_user su
LEFT JOIN sys_user_role sur ON su.user_id = sur.user_id
LEFT JOIN sys_role sr ON sur.role_id = sr.role_id
WHERE su.user_name = cg.user_name
AND LEFT(CAST(cg.dept_id AS CHAR), 3) = #{headId}
AND sr.role_key IN ('headAdmin', 'headPublic', 'headPrivate', 'headOps')
)
</when>
<otherwise>
1 = 2
</otherwise>
</choose>
OR (
cg.share_enabled = 1
AND cg.group_status = '0'
AND cg.share_dept_ids IS NOT NULL
AND cg.share_dept_ids != ''
AND find_in_set(#{deptId}, cg.share_dept_ids)
)
)
</sql>
<sql id="custGroupVisibleCondition">
<choose>
<when test="dto != null and dto.viewType == 'mine'">
<choose>
<when test="dto.headRole">
AND EXISTS (
SELECT 1
FROM sys_user su
LEFT JOIN sys_user_role sur ON su.user_id = sur.user_id
LEFT JOIN sys_role sr ON sur.role_id = sr.role_id
WHERE su.user_name = cg.user_name
AND LEFT(CAST(cg.dept_id AS CHAR), 3) = #{headId}
AND sr.role_key IN ('headAdmin', 'headPublic', 'headPrivate', 'headOps')
)
</when>
<otherwise>
AND 1 = 2
</otherwise>
</choose>
</when>
<when test="dto != null and dto.viewType == 'sharedToMe'">
AND cg.share_enabled = 1
AND cg.group_status = '0'
AND cg.share_dept_ids IS NOT NULL
AND cg.share_dept_ids != ''
AND find_in_set(#{deptId}, cg.share_dept_ids)
</when>
<otherwise>
<include refid="custGroupVisibleBaseCondition"/>
</otherwise>
</choose>
</sql>
<select id="selectCustGroupList" resultType="CustGroupVO">
SELECT
cg.id,
cg.group_name,
cg.group_mode,
cg.create_mode,
cg.group_type,
cg.user_name,
cg.nick_name,
cg.dept_id,
cg.share_enabled,
cg.share_dept_ids,
cg.group_status,
cg.group_tags,
cg.create_by,
cg.create_time,
cg.update_by,
@@ -26,19 +88,20 @@
FROM ibs_cust_group cg
<where>
cg.del_flag = '0'
and create_status = '1'
AND cg.create_status = '1'
<include refid="custGroupVisibleCondition"/>
<if test="dto.groupName != null and dto.groupName != ''">
AND cg.group_name LIKE CONCAT('%', #{dto.groupName}, '%')
</if>
<if test="dto.groupMode != null and dto.groupMode != ''">
AND cg.group_mode = #{dto.groupMode}
</if>
<if test="dto.createMode != null and dto.createMode != ''">
AND cg.create_mode = #{dto.createMode}
</if>
<if test="dto.groupStatus != null and dto.groupStatus != ''">
AND cg.group_status = #{dto.groupStatus}
</if>
<if test="dto.groupTags != null and dto.groupTags != ''">
AND cg.group_tags LIKE CONCAT('%', #{dto.groupTags}, '%')
</if>
</where>
ORDER BY cg.create_time DESC
</select>
@@ -48,13 +111,14 @@
cg.id,
cg.group_name,
cg.group_mode,
cg.create_mode,
cg.group_type,
cg.user_name,
cg.nick_name,
cg.dept_id,
cg.share_enabled,
cg.share_dept_ids,
cg.group_status,
cg.group_tags,
cg.valid_time,
cg.create_by,
cg.create_time,
@@ -63,13 +127,49 @@
cg.remark,
cg.create_status,
cg.grid_type,
cg.cmpm_biz_type,
cg.grid_user_names,
cg.region_grid_ids,
cg.draw_grid_ids,
(SELECT COUNT(*) FROM ibs_cust_group_member cgm WHERE cgm.group_id = cg.id AND cgm.del_flag = '0') AS cust_count
FROM ibs_cust_group cg
WHERE cg.id = #{id} AND cg.del_flag = '0'
WHERE cg.id = #{id}
AND cg.del_flag = '0'
AND cg.create_status = '1'
<include refid="custGroupVisibleBaseCondition"/>
</select>
<select id="countVisibleCustGroup" resultType="java.lang.Long">
SELECT COUNT(1)
FROM ibs_cust_group cg
WHERE cg.id = #{id}
AND cg.del_flag = '0'
AND cg.create_status = '1'
<include refid="custGroupVisibleBaseCondition"/>
</select>
<select id="countHeadOperableCustGroup" resultType="java.lang.Long">
SELECT COUNT(1)
FROM ibs_cust_group cg
WHERE cg.id = #{id}
AND cg.del_flag = '0'
AND EXISTS (
SELECT 1
FROM sys_user su
LEFT JOIN sys_user_role sur ON su.user_id = sur.user_id
LEFT JOIN sys_role sr ON sur.role_id = sr.role_id
WHERE su.user_name = cg.user_name
AND LEFT(CAST(cg.dept_id AS CHAR), 3) = #{headId}
AND sr.role_key IN ('headAdmin', 'headPublic', 'headPrivate', 'headOps')
)
</select>
<select id="selectAllGroupTags" resultType="java.lang.String">
SELECT DISTINCT group_tags
FROM ibs_cust_group
WHERE del_flag = '0'
AND create_status = '1'
AND group_tags IS NOT NULL
AND group_tags != ''
ORDER BY group_tags
</select>
</mapper>

View File

@@ -13,28 +13,94 @@
cgm.cust_name,
cgm.cust_idc,
cgm.social_credit_code,
cgm.user_name,
cgm.nick_name,
cgm.outlet_id,
cgm.outlet_name,
cgm.branch_id,
cgm.branch_name,
cgm.create_time
FROM ibs_cust_group_member cgm
<where>
cgm.group_id = #{groupId}
AND cgm.del_flag = '0'
<choose>
<when test="dto != null and dto.userRole == 'branch'">
AND cgm.branch_id = #{dto.currentDeptId}
</when>
<when test="dto != null and dto.userRole == 'outlet'">
AND cgm.outlet_id = #{dto.currentDeptId}
</when>
<when test="dto != null and dto.userRole == 'manager'">
AND cgm.user_name = #{dto.currentUserName}
</when>
</choose>
<if test="dto != null and dto.custType != null and dto.custType != ''">
AND cgm.cust_type = #{dto.custType}
</if>
<if test="dto != null and dto.custName != null and dto.custName != ''">
AND cgm.cust_name LIKE CONCAT('%', #{dto.custName}, '%')
</if>
<if test="dto != null and dto.userName != null and dto.userName != ''">
AND cgm.user_name = #{dto.userName}
</if>
<if test="dto != null and dto.nickName != null and dto.nickName != ''">
AND cgm.nick_name LIKE CONCAT('%', #{dto.nickName}, '%')
</if>
</where>
ORDER BY cgm.create_time ASC
</select>
<!-- 批量查询个人客户是否存在 -->
<select id="selectExistingRetailCustIds" resultType="String">
SELECT DISTINCT t.cust_id
FROM ibs_cust_group_member t
INNER JOIN cust_info_retail c ON t.cust_id = c.cust_id AND t.cust_idc = c.cust_idc
WHERE t.del_flag = '0'
AND t.cust_type = '0'
AND t.cust_id IN
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<!-- 批量查询商户客户是否存在 -->
<select id="selectExistingMerchantCustIds" resultType="String">
SELECT DISTINCT t.cust_id
FROM ibs_cust_group_member t
INNER JOIN cust_info_merchant c ON t.cust_id = c.cust_id AND t.social_credit_code = c.social_credit_code
WHERE t.del_flag = '0'
AND t.cust_type = '1'
AND t.cust_id IN
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<!-- 批量查询企业客户是否存在 -->
<select id="selectExistingBusinessCustIds" resultType="String">
SELECT DISTINCT t.cust_id
FROM ibs_cust_group_member t
INNER JOIN cust_info_business c ON t.cust_id = c.cust_id AND t.social_credit_code = c.social_credit_code
WHERE t.del_flag = '0'
AND t.cust_type = '2'
AND t.cust_id IN
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
<!-- 批量插入客群客户INSERT IGNORE遇到重复键自动跳过 -->
<insert id="batchInsertMembers">
INSERT IGNORE INTO ibs_cust_group_member
(group_id, cust_type, cust_id, cust_name, cust_idc, social_credit_code, create_by, create_time, del_flag, manual_remove)
(group_id, cust_type, cust_id, cust_name, cust_idc, social_credit_code,
user_name, nick_name, outlet_id, outlet_name, branch_id, branch_name,
create_by, create_time, del_flag, manual_remove)
VALUES
<foreach collection="list" item="item" index="index" separator=",">
(#{item.groupId}, #{item.custType}, #{item.custId}, #{item.custName}, #{item.custIdc}, #{item.socialCreditCode}, #{item.createBy}, NOW(), '0', '0')
(#{item.groupId}, #{item.custType}, #{item.custId}, #{item.custName}, #{item.custIdc}, #{item.socialCreditCode},
#{item.userName}, #{item.nickName}, #{item.outletId}, #{item.outletName}, #{item.branchId}, #{item.branchName},
#{item.createBy}, NOW(), '0', '0')
</foreach>
</insert>

View File

@@ -0,0 +1,245 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.group.mapper.GroupPerformanceMapper">
<select id="selectLsCountList" resultType="com.ruoyi.group.domain.entity.GroupCmpmCountLingshou825">
SELECT
dt,
group_id,
group_name,
group_mode,
dept_id,
dept_name,
outlets_id,
outlets_name,
user_name,
cust_num,
zf_365cnt,
zf_180cnt,
zf_90cnt,
zf_30cnt,
zf_365rt,
zf_180rt,
zf_90rt,
zf_30rt,
cur_bal_d,
sx_rat,
yx_rat,
sx_num,
yx_num,
sx_bal,
bal_loan,
loan_ave,
yxht_rat,
dian_rat,
shui_rat,
tax_rat,
open_rat,
yxht_num,
dian_num,
shui_num,
tax_num,
open_num,
dep_bal,
fin_bal,
grhx_num,
cfyx_num,
yxxyk_num,
yxsbk_num,
`2to3_sbk_num` as twoTo3SbkNum,
ylj_to_sbk_num,
fshl_num,
yxsd_num,
hxsd_num,
region_code,
ops_dept
FROM group_cmpm_count_lingshou_825
<where>
<if test="dt != null and dt != ''">and dt = #{dt}</if>
<if test="groupName != null and groupName != ''">and group_name like concat('%', #{groupName}, '%')</if>
<if test="isBranch == true">and dept_id like concat('%',concat(#{deptId},'%'))</if>
<if test="isOutlet == true">and outlets_id like concat('%',concat(#{deptId},'%'))</if>
<if test="isManager == true">and user_name like concat('%',concat(#{userName},'%'))</if>
</where>
</select>
<select id="selectGsCountList" resultType="com.ruoyi.group.domain.entity.GroupCmpmCountGongsi825">
SELECT
dt,
group_id,
group_name,
group_mode,
dept_id,
dept_name,
outlets_id,
outlets_name,
user_name,
cust_num,
hq_cur_balance,
bz_cur_balance,
loan_balance_cny,
finance_prod_711_balance,
finance_prod_716_balance,
loan_year_dailyaverage,
qfcd_rat,
tx_rat,
bh_rat,
yxdfgz_rat,
dkdf_rat,
dksf_rat,
dkshf_rat,
pjb_rat,
czb_rat,
sfb_rat,
mrb_rat,
szst_rat,
kh_rat,
gjjsyw_rat,
yqjsh_rat,
qfcd_num,
tx_num,
bh_num,
yxdfgz_num,
ustr_count_per_m,
ustr_bal_m,
dkdf_num,
dksf_num,
dkshf_num,
pjb_num,
czb_num,
sfb_num,
mrb_num,
szst_num,
kh_num,
gjjsyw_num,
yqjsh_num,
region_code,
ops_dept,
htqy_rat,
htqy_num,
dept_type,
zf_365cnt,
zf_180cnt,
zf_90cnt,
zf_30cnt,
zf_365rt,
zf_180rt,
zf_90rt,
zf_30rt,
ph_rat,
ph_num
FROM group_cmpm_count_gongsi_825
<where>
<if test="dt != null and dt != ''">and dt = #{dt}</if>
<if test="groupName != null and groupName != ''">and group_name like concat('%', #{groupName}, '%')</if>
<if test=" isBranch == true">and dept_id like concat('%',concat(#{deptId},'%'))</if>
<if test=" isOutlet == true">and outlets_id like concat('%',concat(#{deptId},'%'))</if>
<if test=" isManager == true">and user_name like concat('%',concat(#{userName},'%'))</if>
</where>
</select>
<select id="selectLsCustList" resultType="com.ruoyi.group.domain.entity.GroupCustCountLingshou825">
SELECT
group_id,
cust_name,
cust_idc,
cust_isn,
cur_bal_d,
bal_loan,
loan_ave,
is_sx,
is_yx,
sx_bal,
is_yxht,
is_xyk,
fshl,
is_sd,
dian,
shui,
tax,
open_num,
dep_bal,
fin_bal,
is_grhx,
is_cfyx,
is_yxsbk,
is_2to3_sbk,
is_ylj_to_sbk,
region_code,
ops_dept,
cust_type,
is_365zf,
is_180zf,
is_90zf,
is_30zf,
dt,
is_hxsd
FROM group_cust_count_lingshou_825
<where>
group_id = #{groupId}
<if test="dt != null and dt != ''">and dt = #{dt}</if>
<if test="custName != null and custName != ''">and cust_name like concat('%', #{custName}, '%')</if>
<if test="custIdc != null and custIdc != ''">and cust_idc like concat('%', #{custIdc}, '%')</if>
</where>
</select>
<select id="selectGsCustList" resultType="com.ruoyi.group.domain.entity.GroupCustCountGongsi825">
SELECT
group_id,
cust_name,
social_credit_code,
cust_isn,
hq_cur_balance,
bz_cur_balance,
is_credit,
loan_balance_cny,
loan_year_dailyaverage,
finance_prod_716_open_flag,
finance_prod_716_balance,
finance_prod_711_open_flag,
finance_prod_711_balance,
intl_bussiness_jcbh_open_flag,
is_ustr,
ustr_count_per_m,
ustr_bal_m,
eleccharge_sign_flag,
watercharge_sign_flag,
taxdeduction_sign_flag,
pjb,
czb,
sfb,
mrb,
szst,
is_open_sts,
intl_bussiness_open_flag,
intl_bussiness_325_open_flag,
region_code,
ops_dept,
cust_type,
is_htqy,
dept_name,
outlets_id,
outlets_name,
user_name,
dept_id,
is_365zf,
is_180zf,
is_90zf,
is_30zf,
dt,
is_ph
FROM group_cust_count_gongsi_825
<where>
group_id = #{groupId}
<if test="dt != null and dt != ''">and dt = #{dt}</if>
<if test="isBranch == true">and dept_id like concat('%',concat(#{deptId},'%'))</if>
<if test="isOutlet == true">and outlets_id like concat('%',concat(#{deptId},'%'))</if>
<if test="isManager == true">and user_name like concat('%',concat(#{userName},'%'))</if>
<if test="custName != null and custName != ''">and cust_name like concat('%', #{custName}, '%')</if>
<if test="socialCreditCode != null and socialCreditCode != ''">and social_credit_code like concat('%', #{socialCreditCode}, '%')</if>
</where>
</select>
</mapper>

View File

@@ -5,6 +5,7 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.ibs.cmpm.domain.dto.CustLevelDTO;
import com.ruoyi.ibs.cmpm.domain.dto.CustManagerDTO;
@@ -104,6 +105,17 @@ public class GridCmpmController extends BaseController {
return success(gridCmpmService.getCustLevelListForManager());
}
@PostMapping("/custManager/export")
@Log(title = "绩效网格-管户报表异步导出", businessType = BusinessType.EXPORT)
@ApiOperation("管户报表异步导出")
public AjaxResult exportCustManager(@RequestBody(required = false) CustManagerDTO custManagerDTO) {
if (custManagerDTO == null) {
custManagerDTO = new CustManagerDTO();
}
String taskId = gridCmpmService.exportCustManagerAsync(custManagerDTO);
return AjaxResult.success("导出任务创建成功,请稍后前往下载中心下载", taskId);
}
@GetMapping("/custLevel/count")
@Log(title = "绩效网格-查询客户分层等级")
@ApiOperation("查询客户分层等级")
@@ -118,13 +130,4 @@ public class GridCmpmController extends BaseController {
return AjaxResult.success( gridCmpmCustService.selectCustInfoList (custBaseInfo)) ;
}
/**
* 根据网格类型获取客户经理列表
*/
@GetMapping("/managerList")
@Log(title = "绩效网格-获取客户经理列表")
@ApiOperation("获取客户经理列表")
public AjaxResult getManagerListByGridType(@RequestParam String gridType) {
return AjaxResult.success(gridCmpmService.getManagerListByGridType(gridType));
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.ibs.cmpm.domain.vo;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -24,74 +23,92 @@ public class DwbRetailCustLevelManagerDetailVO {
/** 网点号 */
@ApiModelProperty(value = "网点号")
@ExcelProperty("网点号")
private String outletId;
/** 网点名 */
@ApiModelProperty(value = "网点名")
@ExcelProperty("网点名")
private String outletName;
/** 支行号 */
@ApiModelProperty(value = "支行号")
@ExcelProperty("支行号")
private String branchId;
/** 支行名 */
@ApiModelProperty(value = "支行名")
@ExcelProperty("支行名")
private String branchName;
/** 客户名称 */
@ApiModelProperty(value = "客户名称")
@ExcelProperty("客户名称")
private String custName;
/** 客户证件号 */
@ApiModelProperty(value = "客户证件号")
@ExcelProperty("客户证件号")
private String custIdc;
/** 客户内码 */
@ApiModelProperty(value = "客户内码")
@ExcelProperty("客户内码")
private String custIsn;
/** 年龄 */
@ApiModelProperty(value = "年龄")
@ExcelProperty("年龄")
private String custAge;
/** 性别 */
@ApiModelProperty(value = "性别")
@ExcelProperty("性别")
private String custSex;
/** 联系电话 */
@ApiModelProperty(value = "联系电话")
@ExcelProperty("联系电话")
private String custPhone;
/** 联系地址 */
@ApiModelProperty(value = "联系地址")
@ExcelProperty("联系地址")
private String custAddress;
/** 总资产余额 */
@ApiModelProperty(value = "总资产余额")
@ExcelProperty("总资产余额")
private BigDecimal custAumBal;
/** 总资产余额较上月变动 */
@ApiModelProperty(value = "总资产余额较上月变动")
@ExcelProperty("总资产余额较上月变动")
private BigDecimal aumBalCompLm;
/** 总资产月日均 */
@ApiModelProperty(value = "总资产月日均")
@ExcelProperty("总资产余额月日均")
private BigDecimal custAumMonthAvg;
/** 客户星级 */
@ApiModelProperty(value = "客户星级")
@ExcelProperty("客户星级")
private String custLevel;
/** 星级较上月变动 */
@ApiModelProperty(value = "星级较上月变动")
@ExcelProperty("星级较上月变动")
private String custLevelCompLm;
/** 责任人 */
@ApiModelProperty(value = "责任人")
@ExcelProperty("责任人")
private String managerName;
/** 责任人柜员号 */
@ApiModelProperty(value = "责任人柜员号")
@ExcelProperty("责任人柜员号")
private String managerId;
}

View File

@@ -47,6 +47,11 @@ public interface GridCmpmMapper {
List<DwbRetailCustLevelManagerDetailVO> getCustManagerList(CustManagerDTO custManagerDTO);
List<DwbRetailCustLevelManagerDetailVO> getCustManagerListByPage(@Param("dto") CustManagerDTO custManagerDTO,
@Param("headId") String headId,
@Param("offset") Integer offset,
@Param("pageSize") Integer pageSize);
int getCustLevelCount(CustManagerDTO custManagerDTO);
List<CustBaseInfo> selectCustInfoFromGridCmpm(CustBaseInfo custBaseInfo);
@@ -65,30 +70,21 @@ public interface GridCmpmMapper {
List<String> selectManagerList();
/**
* 根据网格类型和总行ID查询客户经理列表
* @param gridType 网格类型零售retail、对公corporate、对公账户corporate_account
* 全量查询绩效网格客户列表(用于客群管户关系匹配,不按客户经理过滤)
* @param gridType 网格类型
* @param headId 总行ID
* @return 客户经理列表(user_name, nick_name
* @return 客户列表(包含管户关系信息
*/
List<Map<String, String>> getManagerListByGridType(@Param("gridType") String gridType, @Param("headId") String headId);
List<GridCmpmVO> getAllCustomerListForImport(@Param("gridType") String gridType, @Param("headId") String headId);
/**
* 根据网格类型、总行ID和客户经理查询客户列表分表查询适用于客群导入
* @param gridType 网格类型
* @param userName 客户经理柜员号
* 根据客户ID和类型列表查询管户关系用于动态客群更新管户关系
* @param gridType 网格类型retail/corporate
* @param headId 总行ID
* @return 客户列表
* @param custInfoList 客户信息列表包含custId和custType
* @return 客户管户关系列表
*/
List<GridCmpmVO> getCustomerListForImport(@Param("gridType") String gridType, @Param("userName") String userName, @Param("headId") String headId);
/**
* 根据网格类型、总行ID和客户经理流式查询客户列表使用Cursor适用于大数据量场景
* @param gridType 网格类型
* @param userName 客户经理柜员号
* @param headId 总行ID
* @return 客户列表游标
*/
Cursor<GridCmpmVO> getCustomerListForImportCursor(@Param("gridType") String gridType, @Param("userName") String userName, @Param("headId") String headId);
List<GridCmpmVO> getRelationshipsByCustList(@Param("gridType") String gridType, @Param("headId") String headId, @Param("custInfoList") List<Map<String, String>> custInfoList);
// List<CustBaseInfo> selectCustInfoRetailFromGridCmpm(CustBaseInfo custBaseInfo);

View File

@@ -1,11 +1,15 @@
package com.ruoyi.ibs.cmpm.service;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.ibs.cmpm.domain.dto.CustLevelDTO;
import com.ruoyi.ibs.cmpm.domain.dto.CustManagerDTO;
import com.ruoyi.ibs.cmpm.domain.dto.GridCmpmListDTO;
@@ -14,11 +18,19 @@ import com.ruoyi.ibs.cmpm.domain.vo.DwbRetailCustLevelManagerDetailVO;
import com.ruoyi.ibs.cmpm.domain.vo.DwbRetailResultVO;
import com.ruoyi.ibs.cmpm.domain.vo.GridCmpmVO;
import com.ruoyi.ibs.cmpm.mapper.GridCmpmMapper;
import com.ruoyi.ibs.task.domain.entity.ImportExportTask;
import com.ruoyi.ibs.task.mapper.ImportExportTaskMapper;
import com.ruoyi.system.enums.OssFileEnum;
import com.ruoyi.system.service.OssFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -27,6 +39,7 @@ import java.util.stream.Collectors;
* @Date 2025/10/15
**/
@Service
@Slf4j
public class GridCmpmService {
@@ -39,6 +52,15 @@ public class GridCmpmService {
@Resource
private RedisCache redisCache;
@Resource
private ImportExportTaskMapper importExportTaskMapper;
@Resource
private OssFileService ossFileService;
@Resource(name = "excelExportExecutor")
private ExecutorService executorService;
private final String CUST_LEVEL_COUNT_KEY = "GRID_CMPM_CUST_LEVEL_COUNT_";
public List<GridCmpmVO> selectManageList(GridCmpmListDTO gridCmpmRetailListDTO){
@@ -94,33 +116,32 @@ public class GridCmpmService {
}
public List<DwbRetailCustLevelManagerDetailVO> selectCustManagerList(CustManagerDTO custManagerDTO) {
String userRole = SecurityUtils.userRole();
if (userRole.equals("manager")){
//客户经理查自己
custManagerDTO.setManagerId(SecurityUtils.getUsername());
}else if (userRole.equals("outlet")){
//网点管理员查网点
custManagerDTO.setOutletId(String.valueOf(SecurityUtils.getDeptId()));
}else if (userRole.equals("branch")){
//支行管理员查支行
custManagerDTO.setBranchId(String.valueOf(SecurityUtils.getDeptId()));
}
//其他角色查全部
applyCustManagerScope(custManagerDTO);
return gridCmpmMapper.getCustManagerList(custManagerDTO);
}
public int custLevelCount(CustManagerDTO custManagerDTO) {
String userRole = SecurityUtils.userRole();
if (userRole.equals("manager")){
//客户经理查自己
custManagerDTO.setManagerId(SecurityUtils.getUsername());
}else if (userRole.equals("outlet")){
//网点管理员查网点
custManagerDTO.setOutletId(String.valueOf(SecurityUtils.getDeptId()));
}else if (userRole.equals("branch")){
//支行管理员查支行
custManagerDTO.setBranchId(String.valueOf(SecurityUtils.getDeptId()));
public String exportCustManagerAsync(CustManagerDTO custManagerDTO) {
applyCustManagerScope(custManagerDTO);
String headId = SecurityUtils.getHeadId();
ImportExportTask task = new ImportExportTask();
String taskId = IdUtils.randomUUID();
task.setId(taskId);
task.setStatus("0");
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
task.setFileName(sdf.format(now) + "管户报表导出");
task.setUserName(SecurityUtils.getUsername());
task.setCreateTime(now);
importExportTaskMapper.insert(task);
String userName = SecurityUtils.getUsername();
executorService.submit(() -> doExportCustManager(taskId, custManagerDTO, userName, headId));
return taskId;
}
public int custLevelCount(CustManagerDTO custManagerDTO) {
applyCustManagerScope(custManagerDTO);
return gridCmpmMapper.getCustLevelCount(custManagerDTO);
}
@@ -274,6 +295,64 @@ public class GridCmpmService {
return custLevelCountMap;
}
private void applyCustManagerScope(CustManagerDTO custManagerDTO) {
String userRole = SecurityUtils.userRole();
if (userRole.equals("manager")) {
custManagerDTO.setManagerId(SecurityUtils.getUsername());
} else if (userRole.equals("outlet")) {
custManagerDTO.setOutletId(String.valueOf(SecurityUtils.getDeptId()));
} else if (userRole.equals("branch")) {
custManagerDTO.setBranchId(String.valueOf(SecurityUtils.getDeptId()));
}
}
private void doExportCustManager(String taskId, CustManagerDTO custManagerDTO, String userName, String headId) {
ImportExportTask task = importExportTaskMapper.selectById(taskId);
File tempFile = null;
try {
tempFile = File.createTempFile("管户报表导出_" + taskId + "-", ".xlsx");
ExcelWriter excelWriter = EasyExcel.write(tempFile, DwbRetailCustLevelManagerDetailVO.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("管户报表").build();
int pageSize = 1000;
int pageNum = 0;
List<DwbRetailCustLevelManagerDetailVO> pageData;
do {
pageData = gridCmpmMapper.getCustManagerListByPage(custManagerDTO, headId, pageNum * pageSize, pageSize);
if (!pageData.isEmpty()) {
excelWriter.write(pageData, writeSheet);
}
pageNum++;
} while (pageData.size() == pageSize);
excelWriter.finish();
String ossUUId = ossFileService.uploadFileToOss(
OssFileEnum.CUST_MANAGER_REPORT,
tempFile,
"管户报表导出_" + taskId + ".xlsx",
userName
);
task.setStatus("1");
task.setFileUrl(ossUUId);
task.setFinishTime(new Date());
importExportTaskMapper.updateById(task);
} catch (Exception e) {
task.setStatus("2");
task.setFinishTime(new Date());
task.setErrorMsg(e.getMessage());
importExportTaskMapper.updateById(task);
} finally {
if (Objects.nonNull(tempFile)) {
boolean deleted = tempFile.delete();
if (!deleted) {
log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath());
}
}
}
}
// 计算客户等级变化情况
private Map<String, Integer> calculateLevelChanges(Map<String, Integer> historyMap, Map<String, Integer> currentMap) {
Map<String, Integer> changesMap = new HashMap<>();
@@ -303,25 +382,27 @@ public class GridCmpmService {
}
/**
* 根据网格类型和总行ID查询客户经理列表
* @param gridType 网格类型零售retail、对公corporate、对公账户corporate_account
* @return 客户经理列表
* 全量查询绩效网格客户列表用于客群管户关系匹配不依赖SecurityUtils
* @param gridType 网格类型
* @param headId 总行ID
* @return 客户列表(包含管户关系信息)
*/
public List<Map<String, String>> getManagerListByGridType(String gridType) {
String headId = SecurityUtils.getHeadId();
return gridCmpmMapper.getManagerListByGridType(gridType, headId);
public List<GridCmpmVO> selectAllForImport(String gridType, String headId) {
return gridCmpmMapper.getAllCustomerListForImport(gridType, headId);
}
/**
* 根据参数查询绩效网格客户列表不依赖SecurityUtils适用于异步线程
* 所有参数由调用者传入,不在方法内部获取用户上下文
* @param gridType 网格类型
* @param userName 客户经理柜员号
* 根据客户ID列表查询管户关系用于动态客群更新管户关系
* @param gridType 网格类型retail/corporate
* @param headId 总行ID
* @return 客户列表
* @param custInfoList 客户信息列表包含custId和custType
* @return 客户管户关系列表
*/
public List<GridCmpmVO> selectManageListForImport(String gridType, String userName, String headId) {
return gridCmpmMapper.getCustomerListForImport(gridType, userName, headId);
public List<GridCmpmVO> getRelationshipsByCustList(String gridType, String headId, List<Map<String, String>> custInfoList) {
if (custInfoList == null || custInfoList.isEmpty()) {
return new ArrayList<>();
}
return gridCmpmMapper.getRelationshipsByCustList(gridType, headId, custInfoList);
}
}

View File

@@ -18,8 +18,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
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));
}
@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.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.CustInfoDeleteFromAnchor;
import com.ruoyi.ibs.customerselect.domain.CustInfoUpdateFromAnchor;
@@ -242,4 +243,10 @@ public interface CustInfoBusinessMapper extends BaseMapper<CustInfoBusiness>
public int insertCustomersToBusinessByScCode(List<SysGroupCustomer> sysGroupCustomers);
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;
import com.ruoyi.ibs.customerselect.domain.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@@ -41,4 +42,8 @@ public interface IMyCustomerService {
public CustListSearchVo selectCustomListSearchVo(CustBaseInfo sysCustomerBasedata);
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;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.CustInfoBusiness;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
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.vo.GridRelateVO;
import com.ruoyi.ibs.customerselect.mapper.CustInfoBusinessMapper;
@@ -32,9 +38,16 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
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.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@@ -45,6 +58,10 @@ import java.util.stream.Collectors;
@Service
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
private CustInfoBusinessMapper custInfoBusinessMapper;
@@ -80,6 +97,12 @@ public class MyCustomerServiceImpl implements IMyCustomerService {
@Resource
private RedisCache redisCache;
@Resource
private NotificationService notificationService;
@Resource(name = "excelImportExecutor")
private ExecutorService excelImportExecutor;
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));
}
@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)
{
startPage();
notice.setCurrentHeadDeptId(SecurityUtils.getHeadId() + "000");
List<SysNotice> list = noticeService.selectNoticeList(notice);
return getDataTable(list);
}

View File

@@ -4,9 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ibs.draw.domain.dto.grid.DrawGridCustListDTO;
import com.ruoyi.ibs.draw.domain.entity.DrawGridCustUserUnbind;
import com.ruoyi.ibs.draw.domain.vo.DrawGridCustVO;
import com.ruoyi.ibs.grid.domain.entity.RegionCustUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -19,14 +17,4 @@ public interface DrawGridCustUserUnbindMapper extends BaseMapper<DrawGridCustUse
List<DrawGridCustVO> getCustList(DrawGridCustListDTO drawGridCustListDTO);
List<DrawGridCustVO> getCustListByManager(DrawGridCustListDTO drawGridCustListDTO);
/**
* 根据绘制网格ID查询所有客户用于客群导入拼接headId绕过拦截器
* @param gridId 绘制网格ID
* @param headId 总行机构号前三位(用于拼接动态表名)
* @return 客户列表
*/
List<RegionCustUser> selectCustByDrawGridId(@Param("gridId") Long gridId, @Param("headId") String headId);
}

View File

@@ -2,11 +2,11 @@ package com.ruoyi.ibs.draw.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ibs.draw.domain.entity.DrawGridShapeRelate;
import com.ruoyi.ibs.grid.domain.entity.RegionCustUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @Author 吴凯程
@@ -23,10 +23,7 @@ public interface DrawGridShapeRelateMapper extends BaseMapper<DrawGridShapeRelat
List<DrawGridShapeRelate> selectByGridId(@Param("gridId") Long gridId);
/**
* 根据网格ID查询所有客户用于客群导入直接拼接headId绕过拦截器
* @param gridId 网格ID
* @param headId 部门代码(用于拼接动态表名)
* @return 客户列表,包含 custId, custName, custType
* 根据绘制网格ID查询所有客户用于客群导入直接拼接headId绕过拦截器
*/
List<Map<String, Object>> selectCustListByGridId(@Param("gridId") Long gridId, @Param("headId") String headId);
List<RegionCustUser> selectCustByDrawGridId(@Param("gridId") Long gridId, @Param("headId") String headId);
}

View File

@@ -1,38 +1,45 @@
package com.ruoyi.ibs.grid.controller;
import com.github.pagehelper.Page;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshouNew825;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshouNew825;
import com.ruoyi.ibs.grid.service.GridCountService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Api(tags = "网格汇总")
@RestController
@RequestMapping("/ibs/GridCount/")
public class GridCountController extends BaseController {
@Autowired
GridCountService service;
private GridCountService service;
@ApiOperation(value = "查询零售汇总网格列表")
@GetMapping("LsList")
public TableDataPageInfo<GridCmpmCountLingshou> selectLsCountList(String town, String village,String dt) {
public TableDataPageInfo<?> selectLsCountList(String town, String village, String dt) {
Page<Object> page = startPage();
if (isNewRetailTenant()) {
List<GridCmpmCountLingshouNew825> list = service.selectLsCountListNew825(town, village, dt);
return getDataTable(list, page);
}
List<GridCmpmCountLingshou> list = service.selectLsCountList(town, village, dt);
return getDataTable(list, page);
}
@@ -49,6 +56,11 @@ public class GridCountController extends BaseController {
@GetMapping("exportLs")
public void exportLs(HttpServletResponse response, String town, String village, String dt) {
try {
if (isNewRetailTenant()) {
ExcelUtil<GridCmpmCountLingshouNew825> util = new ExcelUtil<>(GridCmpmCountLingshouNew825.class);
util.exportExcel(response, service.selectLsCountListNew825(town, village, dt), "零售网格汇总");
return;
}
ExcelUtil<GridCmpmCountLingshou> util = new ExcelUtil<>(GridCmpmCountLingshou.class);
util.exportExcel(response, service.selectLsCountList(town, village, dt), "零售网格汇总");
} catch (Exception e) {
@@ -71,8 +83,12 @@ public class GridCountController extends BaseController {
@Log(title = "查询零售客户明细")
@ApiOperation(value = "查询零售客户明细")
@GetMapping("LsCustList")
public TableDataPageInfo<GridCustCountLingshou> selectLsCustList(@RequestParam String regionCode, String custName, String custIdc,String dt) {
public TableDataPageInfo<?> selectLsCustList(@RequestParam String regionCode, String custName, String custIdc, String dt) {
Page<Object> page = startPage();
if (isNewRetailTenant()) {
List<GridCustCountLingshouNew825> list = service.selectLsCustListNew825(regionCode, custName, custIdc, dt);
return getDataTable(list, page);
}
List<GridCustCountLingshou> list = service.selectLsCustList(regionCode, custName, custIdc, dt);
return getDataTable(list, page);
}
@@ -86,13 +102,16 @@ public class GridCountController extends BaseController {
return getDataTable(list, page);
}
@Log(title = "导出零售客户明细")
@ApiOperation(value = "导出零售客户明细", produces = "application/octet-stream")
@GetMapping("exportLsCust")
public void exportLsCust(HttpServletResponse response, @RequestParam String regionCode, String custName, String custIdc, String dt) {
try {
if (isNewRetailTenant()) {
ExcelUtil<GridCustCountLingshouNew825> util = new ExcelUtil<>(GridCustCountLingshouNew825.class);
util.exportExcel(response, service.selectLsCustListNew825(regionCode, custName, custIdc, dt), "网格客户明细");
return;
}
ExcelUtil<GridCustCountLingshou> util = new ExcelUtil<>(GridCustCountLingshou.class);
util.exportExcel(response, service.selectLsCustList(regionCode, custName, custIdc, dt), "网格客户明细");
} catch (Exception e) {
@@ -100,7 +119,6 @@ public class GridCountController extends BaseController {
}
}
@Log(title = "导出公司客户明细")
@ApiOperation(value = "导出公司客户明细", produces = "application/octet-stream")
@GetMapping("exportGsCust")
@@ -112,4 +130,8 @@ public class GridCountController extends BaseController {
e.printStackTrace();
}
}
private boolean isNewRetailTenant() {
return SecurityUtils.getDeptId().toString().startsWith("825");
}
}

View File

@@ -0,0 +1,115 @@
package com.ruoyi.ibs.grid.domain.entity;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.io.Serializable;
/**
* 网格汇总统计_零售825专用对象 grid_cmpm_count_lingshou_new_825
*/
@Data
public class GridCmpmCountLingshouNew825 implements Serializable {
private static final long serialVersionUID = 1L;
@Excel(name = "统计日期")
private String dt;
@Excel(name = "一级网格名称")
private String gridName;
@Excel(name = "二级网格名称")
private String gridName2;
@Excel(name = "县/区")
private String county;
@Excel(name = "镇/街道")
private String town;
@Excel(name = "村/社区")
private String village;
@Excel(name = "归属支行机构号")
private String deptId;
@Excel(name = "归属支行名称")
private String deptName;
@Excel(name = "归属网点机构号")
private String outletsId;
@Excel(name = "归属网点名称")
private String outletsName;
@Excel(name = "归属客户经理")
private String userName;
@Excel(name = "入格客户数")
private Integer custNum;
@Excel(name = "近365天已走访人数")
private String zf365cnt;
@Excel(name = "近180天已走访人数")
private String zf180cnt;
@Excel(name = "近90天已走访人数")
private String zf90cnt;
@Excel(name = "近30天已走访人数")
private String zf30cnt;
@Excel(name = "近365天走访率")
private String zf365rt;
@Excel(name = "近180天走访率")
private String zf180rt;
@Excel(name = "近90天走访率")
private String zf90rt;
@Excel(name = "近30天走访率")
private String zf30rt;
@Excel(name = "活期存款余额(元)")
private String curBalD;
@Excel(name = "授信率(%")
private String sxRat;
@Excel(name = "用信覆盖率")
private String yxRat;
@Excel(name = "授信户数")
private Integer sxNum;
@Excel(name = "用信户数")
private Integer yxNum;
@Excel(name = "授信金额(合同)")
private String sxBal;
@Excel(name = "贷款余额(元)")
private String balLoan;
@Excel(name = "贷款年日均(元)")
private String loanAve;
@Excel(name = "合同签约率(%")
private String yxhtRat;
@Excel(name = "代扣电费覆盖率(%")
private String dianRat;
@Excel(name = "代扣水费率(%")
private String shuiRat;
@Excel(name = "代扣税费率(%")
private String taxRat;
@Excel(name = "开户率(%")
private String openRat;
@Excel(name = "合同签约客户数")
private Integer yxhtNum;
@Excel(name = "代扣电费客户数")
private Integer dianNum;
@Excel(name = "代扣水费客户数")
private Integer shuiNum;
@Excel(name = "代扣税费数")
private Integer taxNum;
@Excel(name = "开户数")
private Integer openNum;
@Excel(name = "存款余额(元)")
private String depBal;
@Excel(name = "财富余额(元)")
private String finBal;
@Excel(name = "个人核心客户数")
private Integer grhxNum;
@Excel(name = "财富有效客户数")
private Integer cfyxNum;
@Excel(name = "有效信用卡数")
private Integer yxxykNum;
@Excel(name = "有效社保卡户数")
private Integer yxsbkNum;
@Excel(name = "有效社保卡新增")
private Integer twoTo3SbkNum;
@Excel(name = "养老金迁移至社保卡户数")
private Integer yljToSbkNum;
@Excel(name = "丰收互联客户数")
private Integer fshlNum;
@Excel(name = "有效收单商户")
private Integer yxsdNum;
@Excel(name = "核心收单户数")
private Integer hxsdNum;
private String regionCode;
private String opsDept;
}

View File

@@ -0,0 +1,77 @@
package com.ruoyi.ibs.grid.domain.entity;
import com.ruoyi.common.annotation.Excel;
import lombok.Data;
import java.io.Serializable;
/**
* 客户明细统计_零售825专用对象 grid_cust_count_lingshou_new_825
*/
@Data
public class GridCustCountLingshouNew825 implements Serializable {
private static final long serialVersionUID = 1L;
@Excel(name = "客户名称")
private String custName;
@Excel(name = "客户证件号")
private String custIdc;
@Excel(name = "客户内码")
private String custIsn;
@Excel(name = "活期存款余额")
private String curBalD;
@Excel(name = "贷款余额")
private String balLoan;
@Excel(name = "贷款年日均")
private String loanAve;
@Excel(name = "是否授信")
private String isSx;
@Excel(name = "是否用信")
private String isYx;
@Excel(name = "授信金额")
private String sxBal;
@Excel(name = "是否合同签约")
private String isYxht;
@Excel(name = "是否持有信用卡")
private String isXyk;
@Excel(name = "是否开通丰收互联")
private String fshl;
@Excel(name = "是否办理收单")
private String isSd;
@Excel(name = "是否代扣电费")
private String dian;
@Excel(name = "是否代扣水费")
private String shui;
@Excel(name = "是否代扣税费")
private String tax;
@Excel(name = "开户数")
private String openNum;
@Excel(name = "存款余额")
private String depBal;
@Excel(name = "财富余额")
private String finBal;
@Excel(name = "是否个人核心客户")
private String isGrhx;
@Excel(name = "是否财富有效客户")
private String isCfyx;
@Excel(name = "是否有效社保卡客户")
private String isYxsbk;
@Excel(name = "是否有效社保卡新增")
private String is2to3Sbk;
@Excel(name = "是否养老金迁移至社保卡")
private String isYljToSbk;
@Excel(name = "是否核心收单")
private String isHxsd;
private String regionCode;
private String opsDept;
private String custType;
@Excel(name = "近365天有无走访")
private String is365zf;
@Excel(name = "近180天有无走访")
private String is180zf;
@Excel(name = "近90天有无走访")
private String is90zf;
@Excel(name = "近30天有无走访")
private String is30zf;
private String dt;
}

View File

@@ -2,8 +2,10 @@ package com.ruoyi.ibs.grid.mapper;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshouNew825;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshouNew825;
import org.apache.ibatis.annotations.Mapper;
import java.util.HashMap;
@@ -12,10 +14,12 @@ import java.util.List;
@Mapper
public interface GridCountMapper {
List<GridCmpmCountLingshou> selectLsCountList(HashMap<String, Object> paramMap);
List<GridCmpmCountLingshouNew825> selectLsCountListNew825(HashMap<String, Object> paramMap);
List<GridCmpmCountGongsi> selectGsCountList(HashMap<String, Object> paramMap);
List<GridCustCountLingshou> selectLsCustList(HashMap<String, Object> paramMap);
List<GridCustCountLingshouNew825> selectLsCustListNew825(HashMap<String, Object> paramMap);
List<GridCustCountGongsi> selectGsCustList(HashMap<String, Object> paramMap);
}

View File

@@ -2,18 +2,22 @@ package com.ruoyi.ibs.grid.service;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshouNew825;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshouNew825;
import java.util.List;
public interface GridCountService {
List<GridCmpmCountLingshou> selectLsCountList(String town,String village,String dt);
List<GridCmpmCountLingshouNew825> selectLsCountListNew825(String town, String village, String dt);
List<GridCmpmCountGongsi> selectGsCountList(String town, String village,String dt);
List<GridCustCountLingshou> selectLsCustList(String regionCode, String custName, String custIdc,String dt);
List<GridCustCountLingshouNew825> selectLsCustListNew825(String regionCode, String custName, String custIdc, String dt);
List<GridCustCountGongsi> selectGsCustList(String regionCode, String custName, String socialCreditCode,String dt);
}

View File

@@ -3,8 +3,10 @@ package com.ruoyi.ibs.grid.service.impl;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshouNew825;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountGongsi;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshou;
import com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshouNew825;
import com.ruoyi.ibs.grid.mapper.GridCountMapper;
import com.ruoyi.ibs.grid.service.GridCountService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -21,6 +23,15 @@ public class GridCountServiceimpl implements GridCountService {
@Override
public List<GridCmpmCountLingshou> selectLsCountList(String town,String village,String dt) {
return mapper.selectLsCountList(buildLsCountParams(town, village, dt));
}
@Override
public List<GridCmpmCountLingshouNew825> selectLsCountListNew825(String town, String village, String dt) {
return mapper.selectLsCountListNew825(buildLsCountParams(town, village, dt));
}
private HashMap<String, Object> buildLsCountParams(String town, String village, String dt) {
HashMap<String, Object> paramMap = new HashMap<>();
if(SecurityUtils.userRole().equals("branch")){
paramMap.put("isBranch",true);
@@ -36,7 +47,7 @@ public class GridCountServiceimpl implements GridCountService {
paramMap.put("town",town);
paramMap.put("village",village);
paramMap.put("dt",dt);
return mapper.selectLsCountList(paramMap);
return paramMap;
}
@Override
@@ -65,6 +76,15 @@ public class GridCountServiceimpl implements GridCountService {
@Override
public List<GridCustCountLingshou> selectLsCustList(String regionCode, String custName, String custIdc,String dt) {
return mapper.selectLsCustList(buildLsCustParams(regionCode, custName, custIdc, dt));
}
@Override
public List<GridCustCountLingshouNew825> selectLsCustListNew825(String regionCode, String custName, String custIdc, String dt) {
return mapper.selectLsCustListNew825(buildLsCustParams(regionCode, custName, custIdc, dt));
}
private HashMap<String, Object> buildLsCustParams(String regionCode, String custName, String custIdc, String dt) {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("deptId",SecurityUtils.getDeptId());
paramMap.put("userName",SecurityUtils.getUsername());
@@ -72,7 +92,7 @@ public class GridCountServiceimpl implements GridCountService {
paramMap.put("custName",custName);
paramMap.put("custIdc",custIdc);
paramMap.put("dt",dt);
return mapper.selectLsCustList(paramMap);
return paramMap;
}
@Override

View File

@@ -312,6 +312,13 @@ public class SysCampaignController extends BaseController {
.stream().collect(HashMap::new, (m, v) -> m.put(v.getUuid(),v.getModelName()), HashMap::putAll)));
}
@PostMapping("/updateVisitInfoFeedback")
@ApiOperation("更新PAD走访反馈")
@Log(title ="pad走访记录-更新走访反馈", businessType = BusinessType.UPDATE)
public AjaxResult updateVisitInfoFeedback(@RequestBody VisitInfoFeedbackUpdateDTO updateDTO) {
return toAjax(sysCampaignService.updateVisitInfoFeedback(updateDTO));
}
@PostMapping("/delete")
@ApiOperation("根据campaignId删除任务")
@Log(title = "走访-根据campaignId删除任务")

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
package com.ruoyi.ibs.list.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class VisitFeedbackItemDTO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "反馈类型")
private String feedbackType;
@ApiModelProperty(value = "反馈产品列表")
private List<String> products;
}

View File

@@ -117,4 +117,40 @@ public class VisitInfo {
@ApiModelProperty(value = "走访备注")
private String remark;
@ApiModelProperty(value = "互动地址")
private String interAddr;
@ApiModelProperty(value = "协同员工名称")
private String colStafName;
@ApiModelProperty(value = "后续备注")
private String laterNote;
@ApiModelProperty(value = "意向产品值")
private String intentionProductValue;
@ApiModelProperty(value = "反馈状态")
private String feedbackStatus;
@ApiModelProperty(value = "走访来源")
private String sourceOfInterview;
@ApiModelProperty(value = "文件名")
private String filename;
@ApiModelProperty(value = "外呼状态")
private String outCallStatus;
@ApiModelProperty(value = "外呼意向")
private String outCallIntention;
@ApiModelProperty(value = "来源")
private String source;
@ApiModelProperty(value = "分析值")
private String analysisValue;
@ApiModelProperty(value = "设备")
private String facility;
}

View File

@@ -13,6 +13,10 @@ public class VisitInfoDTO {
@ApiModelProperty(value = "柜员名称")
private String visName;
/** 柜员号 */
@ApiModelProperty(value = "柜员号")
private String visId;
/** 走访时间 */
@ApiModelProperty(value = "走访时间")
private String visTime;
@@ -29,6 +33,10 @@ public class VisitInfoDTO {
@ApiModelProperty(value = "客户类型 0个人1商户2企业")
private String custType;
/** 活动ID */
@ApiModelProperty(value = "活动ID")
private String campaignId;
/** 异常走访标签(筛选是否异常) */
@ApiModelProperty(value = "异常走访标签 0正常 1走访频率异常 2走访持续时长异常 3签退时间异常")
private String abnormalVisitTag;

View File

@@ -0,0 +1,34 @@
package com.ruoyi.ibs.list.domain;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class VisitInfoFeedbackUpdateDTO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "走访记录ID")
private Long id;
@ApiModelProperty(value = "走访渠道")
private String source;
@ApiModelProperty(value = "走访备注")
private String remark;
@ApiModelProperty(value = "客户意愿结构化数据")
private List<VisitFeedbackItemDTO> feedbackItems;
@ApiModelProperty(value = "客户意愿拼接值")
private String intentionProductValue;
private String userName;
private String userRole;
private String deptId;
}

View File

@@ -128,4 +128,40 @@ public class VisitInfoVO {
@ApiModelProperty(value = "走访结果")
private String interRes;
@ApiModelProperty(value = "实地拜访地址")
private String interAddr;
@ApiModelProperty(value = "协同走访客户经理")
private String colStafName;
@ApiModelProperty(value = "事后备注")
private String laterNote;
@ApiModelProperty(value = "走访反馈")
private String intentionProductValue;
@ApiModelProperty(value = "反馈状态")
private String feedbackStatus;
@ApiModelProperty(value = "走访来源")
private String sourceOfInterview;
@ApiModelProperty(value = "批量导入文件名")
private String filename;
@ApiModelProperty(value = "外呼状态")
private String outCallStatus;
@ApiModelProperty(value = "客户意愿")
private String outCallIntention;
@ApiModelProperty(value = "走访来源1nullpad 2企业微信 3pc")
private String source;
@ApiModelProperty(value = "nlp模型提取")
private String analysisValue;
@ApiModelProperty(value = "预授信额度")
private String facility;
}

View File

@@ -156,6 +156,10 @@ public interface SysCampaignMapper extends BaseMapper<SysCampaign> {
List<VisitInfoVO> selectVisitInfoList(VisitInfoDTO visitInfoDTO);
List<VisitInfoVO> selectVisitInfoList875(VisitInfoDTO visitInfoDTO);
int updateVisitInfoFeedback(VisitInfoFeedbackUpdateDTO updateDTO);
@Update("UPDATE sys_campaign SET del_flag = '2' where campaign_id = #{campaignId}")
int deleteSysCampaignByCampaignId(@Param("campaignId") String campaignId);

View File

@@ -115,5 +115,7 @@ public interface ISysCampaignService {
public List<VisitInfoVO> selectVisitInfoVoList(VisitInfoDTO visitInfoDTO);
int updateVisitInfoFeedback(VisitInfoFeedbackUpdateDTO updateDTO);
public int deleteSysCampaign(String campaignId);
}

View File

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

View File

@@ -2175,9 +2175,31 @@ public class SysCampaignServiceImpl implements ISysCampaignService
visitInfoDTO.setUserName(SecurityUtils.getUsername());
visitInfoDTO.setUserRole(SecurityUtils.userRole());
visitInfoDTO.setDeptId(String.valueOf(SecurityUtils.getDeptId()));
if ("875".equals(SecurityUtils.getHeadId())) {
return sysCampaignMapper.selectVisitInfoList875(visitInfoDTO);
}
return sysCampaignMapper.selectVisitInfoList(visitInfoDTO);
}
@Override
public int updateVisitInfoFeedback(VisitInfoFeedbackUpdateDTO updateDTO) {
if (updateDTO == null || updateDTO.getId() == null) {
throw new ServiceException("走访记录ID不能为空");
}
String deptId = String.valueOf(SecurityUtils.getDeptId());
if (!deptId.startsWith("875")) {
throw new ServiceException("当前机构无权维护PAD走访反馈");
}
updateDTO.setUserName(SecurityUtils.getUsername());
updateDTO.setUserRole(SecurityUtils.userRole());
updateDTO.setDeptId(deptId);
updateDTO.setSource(StringUtils.trimToNull(updateDTO.getSource()));
updateDTO.setRemark(StringUtils.trimToNull(updateDTO.getRemark()));
updateDTO.setIntentionProductValue(buildIntentionProductValue(updateDTO.getFeedbackItems()));
int rows = sysCampaignMapper.updateVisitInfoFeedback(updateDTO);
return rows;
}
@Override
public int deleteSysCampaign(String campaignId) {
SysCampaign sysCampaign = sysCampaignMapper.selectSysCampaignByCampaignId(campaignId);
@@ -2186,4 +2208,28 @@ public class SysCampaignServiceImpl implements ISysCampaignService
}
return sysCampaignMapper.deleteSysCampaignByCampaignId(campaignId);
}
private String buildIntentionProductValue(List<VisitFeedbackItemDTO> feedbackItems) {
if (feedbackItems == null || feedbackItems.isEmpty()) {
return null;
}
String joinedValue = feedbackItems.stream()
.filter(Objects::nonNull)
.map(item -> {
String feedbackType = StringUtils.trimToNull(item.getFeedbackType());
List<String> products = Optional.ofNullable(item.getProducts())
.orElse(Collections.emptyList())
.stream()
.map(StringUtils::trimToNull)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
if (feedbackType == null || products.isEmpty()) {
return null;
}
return feedbackType + ":" + String.join(",", products);
})
.filter(Objects::nonNull)
.collect(Collectors.joining(";"));
return StringUtils.trimToNull(joinedValue);
}
}

View File

@@ -1,12 +1,15 @@
package com.ruoyi.ibs.task.controller;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import com.github.pagehelper.Page;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.ibs.task.domain.dto.AlterForwardRequest;
import com.ruoyi.ibs.task.domain.dto.WorkRecordDTO;
import com.ruoyi.ibs.task.domain.entity.Alter;
import com.ruoyi.ibs.task.domain.entity.AlterConfig;
@@ -95,12 +98,37 @@ public class WorkRecordController extends BaseController {
@GetMapping("/alter/allList")
@Log(title = "工作台-查询预警信息")
@ApiOperation("查询所有预警信息")
public TableDataPageInfo<AlterVO> allAlterList(String status, String alterType) {
public TableDataPageInfo<AlterVO> allAlterList(String status, String alterType, String forwardFlag) {
Page<Object> page = startPage();
List<AlterVO> list = workRecordService.getAllAlterList(status, alterType);
List<AlterVO> list = workRecordService.getAllAlterList(status, alterType, forwardFlag);
return getDataTable(list, page);
}
@GetMapping("/alter/forward/meta")
@Log(title = "工作台-查询预警转发元数据")
@ApiOperation("查询预警转发元数据")
public AjaxResult getAlterForwardMeta(@RequestParam String ids) {
List<Long> idList = Arrays.stream(ids.split(","))
.filter(org.apache.commons.lang3.StringUtils::isNotBlank)
.map(Long::valueOf)
.collect(Collectors.toList());
return AjaxResult.success(workRecordService.getAlterForwardMeta(idList));
}
@PostMapping("/alter/forward")
@Log(title = "工作台-转发预警信息")
@ApiOperation("批量转发预警信息")
public AjaxResult forwardAlter(@Validated @RequestBody AlterForwardRequest request) {
AlterForwardResultVO result = workRecordService.forwardAlter(request);
if (result.getSuccessCount() > 0 && result.getFailCount() > 0) {
return AjaxResult.success("成功转发" + result.getSuccessCount() + "条,失败" + result.getFailCount() + "", result);
}
if (result.getSuccessCount() > 0) {
return AjaxResult.success("成功转发" + result.getSuccessCount() + "", result);
}
return AjaxResult.error("未能成功转发,失败" + result.getFailCount() + "");
}
@GetMapping("/alter/count")
@Log(title = "工作台-查询预警推送次数")
@ApiOperation("查询预警推送次数")

View File

@@ -0,0 +1,23 @@
package com.ruoyi.ibs.task.domain.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Data
public class AlterForwardRequest {
@NotEmpty(message = "请选择需要转发的预警")
private List<Long> ids;
@NotBlank(message = "请选择转发目标类型")
private String targetType;
private Long deptId;
private String userName;
private Boolean useHistory;
}

View File

@@ -0,0 +1,19 @@
package com.ruoyi.ibs.task.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ForwardTarget {
private String targetType;
private Long deptId;
private String userName;
private String nickName;
private String targetName;
}

View File

@@ -0,0 +1,53 @@
package com.ruoyi.ibs.task.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("alter_assign_history")
public class AlterAssignHistory implements Serializable {
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty("预警类型")
private String alterType;
@ApiModelProperty("客户号")
private String custId;
@ApiModelProperty("客户姓名")
private String custName;
@ApiModelProperty("所属支行/当前操作机构ID")
private Long deptId;
@ApiModelProperty("最近一次转发目标类型dept/user")
private String lastAssignTargetType;
@ApiModelProperty("最近一次转发目标部门ID")
private Long lastAssignTargetDeptId;
@ApiModelProperty("最近一次转发目标用户账号")
private String lastAssignTargetUser;
@ApiModelProperty("最近一次转发目标名称")
private String lastAssignTargetName;
@ApiModelProperty("最近一次转发操作人账号")
private String lastAssignByUser;
@ApiModelProperty("最近一次转发操作人角色")
private String lastAssignByRole;
@ApiModelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@@ -94,4 +94,8 @@ public class WorkRecord implements Serializable {
@ApiModelProperty(value = "是否逾期", notes = "")
private Integer isOverdue;
/** 当前承接部门ID仅转发到网点时使用 */
@ApiModelProperty(value = "当前承接部门ID", notes = "")
private Long deptId;
}

View File

@@ -0,0 +1,14 @@
package com.ruoyi.ibs.task.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class AlterAssignTargetVO {
@ApiModelProperty("目标编码")
private String targetCode;
@ApiModelProperty("目标名称")
private String targetName;
}

View File

@@ -0,0 +1,32 @@
package com.ruoyi.ibs.task.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class AlterForwardMetaVO {
@ApiModelProperty("可选网点列表")
private List<AlterAssignTargetVO> deptOptions = new ArrayList<>();
@ApiModelProperty("可选客户经理列表")
private List<AlterAssignTargetVO> userOptions = new ArrayList<>();
@ApiModelProperty("历史推荐目标类型dept/user")
private String recommendedTargetType;
@ApiModelProperty("历史推荐目标编码")
private String recommendedTargetCode;
@ApiModelProperty("历史推荐目标名称")
private String recommendedTargetName;
@ApiModelProperty("是否仅允许按历史推荐转发")
private Boolean historyOnly = false;
@ApiModelProperty("是否存在历史推荐")
private Boolean hasHistoryRecommend = false;
}

View File

@@ -0,0 +1,14 @@
package com.ruoyi.ibs.task.domain.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class AlterForwardResultVO {
@ApiModelProperty("成功数量")
private int successCount;
@ApiModelProperty("失败数量")
private int failCount;
}

View File

@@ -47,6 +47,14 @@ public class AlterVO {
@ApiModelProperty(value = "客户内码", notes = "")
private String custIsn;
/** 当前承接部门ID */
@ApiModelProperty(value = "当前承接部门ID", notes = "")
private Long deptId;
/** 当前承接网点名称 */
@ApiModelProperty(value = "当前承接网点名称", notes = "")
private String deptName;
/** 状态 */
@ApiModelProperty(value = "状态", notes = "")
private String status;
@@ -62,4 +70,12 @@ public class AlterVO {
/** 是否需要反馈 */
@ApiModelProperty(value = "是否需要反馈", notes = "")
private String isFeedback;
/** 转发标识1需要转发0无需转发 */
@ApiModelProperty(value = "转发标识", notes = "")
private String forwardFlag;
/** 是否可转发 */
@ApiModelProperty(value = "是否可转发", notes = "")
private Boolean canForward;
}

View File

@@ -0,0 +1,9 @@
package com.ruoyi.ibs.task.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ibs.task.domain.entity.AlterAssignHistory;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AlterAssignHistoryMapper extends BaseMapper<AlterAssignHistory> {
}

View File

@@ -6,9 +6,9 @@ import java.util.Date;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ibs.task.domain.entity.WorkRecord;
import com.ruoyi.ibs.task.domain.dto.WorkRecordDTO;
import com.ruoyi.ibs.task.domain.entity.AlterConfig;
import com.ruoyi.ibs.task.domain.entity.WorkRecord;
import com.ruoyi.ibs.task.domain.vo.*;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@@ -86,10 +86,26 @@ public interface WorkRecordMapper extends BaseMapper<WorkRecord> {
* @return 预警信息
*/
List<AlterVO> selectAllAlterList(@Param("deptId") String deptId, @Param("role") String role,
@Param("status") String status, @Param("alterType") String alterType, @Param("username") String username);
@Param("status") String status, @Param("alterType") String alterType,
@Param("username") String username, @Param("forwardFlag") String forwardFlag);
AlterCountVO selectAlterCount(@Param("reportTime") Date reportTime, @Param("role") String role, @Param("deptId") String deptId);
List<AlterAssignTargetVO> selectForwardDeptTargets(@Param("branchDeptId") Long branchDeptId);
List<AlterAssignTargetVO> selectForwardUserTargets(@Param("deptId") Long deptId, @Param("role") String role);
int updateAlterForwardToDept(@Param("id") Long id, @Param("sourceUserName") String sourceUserName,
@Param("targetDeptId") Long targetDeptId, @Param("updateBy") String updateBy);
int updateAlterForwardToUserByBranch(@Param("id") Long id, @Param("sourceUserName") String sourceUserName,
@Param("targetUserName") String targetUserName, @Param("targetNickName") String targetNickName,
@Param("updateBy") String updateBy);
int updateAlterForwardToUserByOutlet(@Param("id") Long id, @Param("sourceDeptId") Long sourceDeptId,
@Param("targetUserName") String targetUserName, @Param("targetNickName") String targetNickName,
@Param("updateBy") String updateBy);
/**
* 设置工作清单为过期
*

View File

@@ -5,6 +5,7 @@ import java.util.List;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.ibs.task.domain.dto.WorkRecordDTO;
import com.ruoyi.ibs.task.domain.dto.AlterForwardRequest;
import com.ruoyi.ibs.task.domain.entity.AlterConfig;
import com.ruoyi.ibs.task.domain.entity.WorkRecord;
import com.ruoyi.ibs.task.domain.vo.*;
@@ -61,7 +62,23 @@ public interface WorkRecordService{
* @param alterType
* @return
*/
List<AlterVO> getAllAlterList(String status, String alterType);
List<AlterVO> getAllAlterList(String status, String alterType, String forwardFlag);
/**
* 获取预警转发元数据
*
* @param id 预警ID
* @return 转发元数据
*/
AlterForwardMetaVO getAlterForwardMeta(List<Long> ids);
/**
* 批量转发预警
*
* @param request 转发请求
* @return 结果
*/
AlterForwardResultVO forwardAlter(AlterForwardRequest request);
/**
* 定时任务生成工作清单
*

View File

@@ -11,20 +11,29 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ibs.task.domain.dto.AlterForwardRequest;
import com.ruoyi.ibs.task.domain.dto.ForwardTarget;
import com.ruoyi.ibs.task.domain.dto.WorkRecordDTO;
import com.ruoyi.ibs.task.domain.entity.AlterAssignHistory;
import com.ruoyi.ibs.task.domain.entity.AlterConfig;
import com.ruoyi.ibs.task.domain.entity.WorkRecord;
import com.ruoyi.ibs.task.domain.vo.*;
import com.ruoyi.ibs.task.mapper.AlterAssignHistoryMapper;
import com.ruoyi.ibs.task.mapper.WorkRecordMapper;
import com.ruoyi.ibs.task.service.WorkRecordService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -41,16 +50,31 @@ import org.springframework.transaction.annotation.Transactional;
public class WorkRecordServiceImpl implements WorkRecordService {
private final static String alterTypesRedisKey = "work:record:alter:types";
private static final String ROLE_MANAGER = "manager";
private static final String ROLE_BRANCH = "branch";
private static final String ROLE_OUTLET = "outlet";
private static final String TARGET_TYPE_DEPT = "dept";
private static final String TARGET_TYPE_USER = "user";
private static final Set<String> FORWARD_ALTER_TYPES = new HashSet<>(Arrays.asList(
"个人资产客户定期存款",
"个人资产客户封闭式理财"
));
@Autowired
private WorkRecordMapper workRecordMapper;
@Autowired
private AlterAssignHistoryMapper alterAssignHistoryMapper;
@Autowired
private ISysPostService sysPostService;
@Autowired
private ISysDeptService sysDeptService;
@Autowired
private ISysUserService sysUserService;
@Autowired
private RedisCache redisCache;
@@ -143,7 +167,9 @@ public class WorkRecordServiceImpl implements WorkRecordService {
@Transactional(rollbackFor = Exception.class)
public List<AlterVO> getAlterList(String status, String alterType) {
String username = SecurityUtils.getUsername();
return workRecordMapper.selectAlterList(username, status, alterType);
List<AlterVO> alterVOS = workRecordMapper.selectAlterList(username, status, alterType);
fillAlterExtFields(alterVOS);
return alterVOS;
}
/**
@@ -156,27 +182,98 @@ public class WorkRecordServiceImpl implements WorkRecordService {
* @return 预警信息
*/
@Override
public List<AlterVO> getAllAlterList(String status, String alterType) {
List<AlterVO> alterVOS = workRecordMapper.selectAllAlterList(String.valueOf(SecurityUtils.getDeptId()), SecurityUtils.userRole(), status, alterType, SecurityUtils.getUsername());
// 将 userName 和 nickName 以 "userName-nickName" 的方式拼接后设置到 custInfo 字段
if (alterVOS != null && !alterVOS.isEmpty()) {
alterVOS.forEach(alterVO -> {
String userName = alterVO.getUserName();
String nickName = alterVO.getNickName();
if (userName != null && nickName != null) {
alterVO.setUserInfo(nickName + "-" + userName);
} else if (userName != null) {
alterVO.setUserInfo(userName);
} else if (nickName != null) {
alterVO.setUserInfo(nickName);
} else {
alterVO.setUserInfo("");
}
});
}
public List<AlterVO> getAllAlterList(String status, String alterType, String forwardFlag) {
List<AlterVO> alterVOS = workRecordMapper.selectAllAlterList(
String.valueOf(SecurityUtils.getDeptId()),
SecurityUtils.userRole(),
status,
alterType,
SecurityUtils.getUsername(),
forwardFlag
);
fillAlterExtFields(alterVOS);
return alterVOS;
}
/**
* 查询转发弹窗所需元数据。
* 单选时返回手动选项并附带历史推荐;多选时根据是否存在历史记录决定走手动分配还是历史推荐模式。
*/
@Override
public AlterForwardMetaVO getAlterForwardMeta(List<Long> ids) {
if (ids == null || ids.isEmpty()) {
throw new ServiceException("请选择需要转发的预警");
}
AlterForwardMetaVO metaVO = new AlterForwardMetaVO();
String role = requireForwardRole();
Long currentDeptId = SecurityUtils.getDeptId();
String currentUser = SecurityUtils.getUsername();
List<WorkRecord> workRecords = workRecordMapper.selectBatchIds(ids);
if (workRecords == null || workRecords.size() != ids.size()) {
throw new ServiceException("存在预警记录已不存在,请刷新后重试");
}
workRecords.forEach(item -> validateRecordBeforeForward(item, role, currentUser, currentDeptId));
if (ids.size() > 1) {
boolean hasAnyHistory = workRecords.stream()
.map(item -> getHistoryRecommend(item.getCustId(), currentDeptId, role))
.anyMatch(Objects::nonNull);
metaVO.setHasHistoryRecommend(hasAnyHistory);
metaVO.setHistoryOnly(hasAnyHistory);
if (!hasAnyHistory) {
fillManualOptions(metaVO, role, currentDeptId);
}
return metaVO;
}
WorkRecord workRecord = workRecords.get(0);
fillManualOptions(metaVO, role, currentDeptId);
fillHistoryRecommend(metaVO, workRecord.getCustId(), currentDeptId, role);
return metaVO;
}
/**
* 执行预警转发。
* 支持手动分配和按历史推荐分配两种模式,并分别统计成功和失败数量。
*/
@Override
@Transactional(rollbackFor = Exception.class)
public AlterForwardResultVO forwardAlter(AlterForwardRequest request) {
String role = requireForwardRole();
String currentUser = SecurityUtils.getUsername();
Long currentDeptId = SecurityUtils.getDeptId();
AlterForwardResultVO result = new AlterForwardResultVO();
boolean useHistory = Boolean.TRUE.equals(request.getUseHistory());
ForwardTarget manualTarget = useHistory ? null : resolveManualTarget(request, role, currentDeptId);
List<WorkRecord> workRecords = workRecordMapper.selectBatchIds(request.getIds());
if (workRecords == null || workRecords.size() != request.getIds().size()) {
throw new ServiceException("存在预警记录已不存在,请刷新后重试");
}
for (WorkRecord workRecord : workRecords) {
validateRecordBeforeForward(workRecord, role, currentUser, currentDeptId);
AlterAssignHistory history = useHistory ? getHistoryRecommend(workRecord.getCustId(), currentDeptId, role) : null;
ForwardTarget target = useHistory ? resolveHistoryTarget(history, role, currentDeptId) : manualTarget;
if (target == null) {
result.setFailCount(result.getFailCount() + 1);
continue;
}
int row = doForward(workRecord.getId(), currentUser, currentDeptId, role, target);
if (row <= 0) {
result.setFailCount(result.getFailCount() + 1);
continue;
}
result.setSuccessCount(result.getSuccessCount() + row);
if (useHistory) {
if (history != null) {
saveAssignHistoryByHistory(workRecord, history, role, currentDeptId);
}
} else {
saveAssignHistory(workRecord, manualTarget, role, currentDeptId);
}
}
return result;
}
/**
* 定时任务生成工作清单
*
@@ -351,4 +448,306 @@ public class WorkRecordServiceImpl implements WorkRecordService {
return java.sql.Timestamp.valueOf(endTime);
}
private void fillAlterExtFields(List<AlterVO> alterVOS) {
if (alterVOS == null || alterVOS.isEmpty()) {
return;
}
String role = SecurityUtils.userRole();
Long currentDeptId = SecurityUtils.getDeptId();
String currentUser = SecurityUtils.getUsername();
alterVOS.forEach(alterVO -> {
alterVO.setForwardFlag(parseForwardFlag(alterVO.getAlterDetail()));
alterVO.setAlterDetail(stripForwardPrefix(alterVO.getAlterDetail()));
alterVO.setUserInfo(buildUserInfo(alterVO.getUserName(), alterVO.getNickName()));
alterVO.setCanForward(canForward(alterVO, role, currentDeptId, currentUser));
});
}
private String buildUserInfo(String userName, String nickName) {
if (StringUtils.isNotEmpty(userName) && StringUtils.isNotEmpty(nickName)) {
return nickName + "-" + userName;
}
if (StringUtils.isNotEmpty(userName)) {
return userName;
}
if (StringUtils.isNotEmpty(nickName)) {
return nickName;
}
return "";
}
private String parseForwardFlag(String alterDetail) {
if (StringUtils.isEmpty(alterDetail)) {
return "";
}
if (alterDetail.startsWith("[FORWARD=1]")) {
return "1";
}
if (alterDetail.startsWith("[FORWARD=0]")) {
return "0";
}
return "";
}
private String stripForwardPrefix(String alterDetail) {
if (StringUtils.isEmpty(alterDetail)) {
return alterDetail;
}
if (alterDetail.startsWith("[FORWARD=1] ")) {
return alterDetail.substring(12);
}
if (alterDetail.startsWith("[FORWARD=0] ")) {
return alterDetail.substring(12);
}
if (alterDetail.startsWith("[FORWARD=1]") || alterDetail.startsWith("[FORWARD=0]")) {
return alterDetail.substring(11);
}
return alterDetail;
}
private Boolean canForward(AlterVO alterVO, String role, Long currentDeptId, String currentUser) {
if (!FORWARD_ALTER_TYPES.contains(alterVO.getAlterType())) {
return false;
}
if (!"1".equals(alterVO.getForwardFlag())) {
return false;
}
if ("2".equals(alterVO.getStatus())) {
return false;
}
if (ROLE_BRANCH.equals(role)) {
return StringUtils.equals(currentUser, alterVO.getUserName()) && alterVO.getDeptId() == null;
}
if (ROLE_OUTLET.equals(role)) {
return alterVO.getDeptId() != null && alterVO.getDeptId().equals(currentDeptId) && StringUtils.isEmpty(alterVO.getUserName());
}
return false;
}
/**
* 校验当前登录角色是否具备预警转发能力,并返回角色标识。
*/
private String requireForwardRole() {
String role = SecurityUtils.userRole();
if (!ROLE_BRANCH.equals(role) && !ROLE_OUTLET.equals(role)) {
throw new ServiceException("当前角色不支持转发预警");
}
return role;
}
/**
* 校验预警记录当前是否仍处于登录人可转发范围内,防止页面停留期间数据状态已变化。
*/
private void validateRecordBeforeForward(WorkRecord workRecord, String role, String currentUser, Long currentDeptId) {
if (workRecord == null || workRecord.getId() == null) {
throw new ServiceException("预警记录不存在");
}
if (!Integer.valueOf(1).equals(workRecord.getIsAlter())) {
throw new ServiceException("当前记录不是预警信息");
}
if (!FORWARD_ALTER_TYPES.contains(workRecord.getAlterType())) {
throw new ServiceException("当前预警类型不支持转发");
}
if (!"1".equals(parseForwardFlag(workRecord.getAlterDetail()))) {
throw new ServiceException("当前预警已有管户,无需转发");
}
if ("2".equals(workRecord.getStatus())) {
throw new ServiceException("当前预警已完成,不能转发");
}
if (ROLE_BRANCH.equals(role)) {
if (!StringUtils.equals(currentUser, workRecord.getUserName()) || workRecord.getDeptId() != null) {
throw new ServiceException("当前预警已不在您的待转发范围内");
}
return;
}
if (ROLE_OUTLET.equals(role)) {
if (workRecord.getDeptId() == null || !workRecord.getDeptId().equals(currentDeptId) || StringUtils.isNotEmpty(workRecord.getUserName())) {
throw new ServiceException("当前预警已不在本网点待转发范围内");
}
return;
}
throw new ServiceException("当前角色不支持转发预警");
}
/**
* 解析手动转发目标,并顺带完成目标权限范围校验。
*/
private ForwardTarget resolveManualTarget(AlterForwardRequest request, String role, Long currentDeptId) {
if (TARGET_TYPE_DEPT.equals(request.getTargetType())) {
if (request.getDeptId() == null) {
throw new ServiceException("请选择转发网点");
}
if (!ROLE_BRANCH.equals(role)) {
throw new ServiceException("网点管理员只能转发给客户经理");
}
String deptName = getAllowedDeptName(request.getDeptId(), currentDeptId);
return new ForwardTarget(TARGET_TYPE_DEPT, request.getDeptId(), null, null, deptName);
}
if (!TARGET_TYPE_USER.equals(request.getTargetType()) || StringUtils.isEmpty(request.getUserName())) {
throw new ServiceException("请选择转发客户经理");
}
SysUser user = getAllowedTargetUser(request.getUserName(), role, currentDeptId);
String targetName = StringUtils.isNotEmpty(user.getNickName()) ? user.getNickName() : user.getUserName();
return new ForwardTarget(TARGET_TYPE_USER, null, user.getUserName(), user.getNickName(), targetName);
}
/**
* 将历史分配记录转换成可执行的转发目标;若历史目标已失效,则返回空。
*/
private ForwardTarget resolveHistoryTarget(AlterAssignHistory history, String role, Long currentDeptId) {
if (history == null) {
return null;
}
if (TARGET_TYPE_DEPT.equals(history.getLastAssignTargetType())) {
if (history.getLastAssignTargetDeptId() == null) {
return null;
}
String deptName = getAllowedDeptName(history.getLastAssignTargetDeptId(), currentDeptId);
return new ForwardTarget(TARGET_TYPE_DEPT, history.getLastAssignTargetDeptId(), null, null, deptName);
}
if (!TARGET_TYPE_USER.equals(history.getLastAssignTargetType()) || StringUtils.isEmpty(history.getLastAssignTargetUser())) {
return null;
}
try {
SysUser user = getAllowedTargetUser(history.getLastAssignTargetUser(), role, currentDeptId);
String targetName = StringUtils.isNotEmpty(user.getNickName()) ? user.getNickName() : user.getUserName();
return new ForwardTarget(TARGET_TYPE_USER, null, user.getUserName(), user.getNickName(), targetName);
} catch (ServiceException ex) {
return null;
}
}
/**
* 按目标类型执行真正的转发落库更新。
*/
private int doForward(Long workRecordId, String currentUser, Long currentDeptId, String role, ForwardTarget target) {
if (TARGET_TYPE_DEPT.equals(target.getTargetType())) {
return workRecordMapper.updateAlterForwardToDept(workRecordId, currentUser, target.getDeptId(), currentUser);
}
if (ROLE_BRANCH.equals(role)) {
return workRecordMapper.updateAlterForwardToUserByBranch(
workRecordId, currentUser, target.getUserName(), target.getNickName(), currentUser
);
}
return workRecordMapper.updateAlterForwardToUserByOutlet(
workRecordId, currentDeptId, target.getUserName(), target.getNickName(), currentUser
);
}
/**
* 校验目标网点是否在当前支行管理员的可转发范围内,并返回网点名称。
*/
private String getAllowedDeptName(Long targetDeptId, Long currentDeptId) {
List<AlterAssignTargetVO> deptOptions = workRecordMapper.selectForwardDeptTargets(currentDeptId);
return deptOptions.stream()
.filter(item -> String.valueOf(targetDeptId).equals(item.getTargetCode()))
.map(AlterAssignTargetVO::getTargetName)
.findFirst()
.orElseThrow(() -> new ServiceException("所选网点不在当前支行可转发范围内"));
}
/**
* 校验目标客户经理是否在当前管理员可转发范围内,并返回用户信息。
*/
private SysUser getAllowedTargetUser(String targetUserName, String role, Long currentDeptId) {
List<AlterAssignTargetVO> userOptions = workRecordMapper.selectForwardUserTargets(currentDeptId, ROLE_MANAGER);
boolean matched = userOptions.stream().anyMatch(item -> StringUtils.equals(targetUserName, item.getTargetCode()));
if (!matched) {
if (ROLE_BRANCH.equals(role)) {
throw new ServiceException("所选客户经理不在当前支行可转发范围内");
}
throw new ServiceException("所选客户经理不在当前网点可转发范围内");
}
SysUser user = sysUserService.selectUserByUserName(targetUserName);
if (user == null || StringUtils.isEmpty(user.getUserName())) {
throw new ServiceException("转发目标客户经理不存在");
}
return user;
}
/**
* 填充手动分配弹窗可选项;支行管理员可选网点和客户经理,网点管理员仅可选客户经理。
*/
private void fillManualOptions(AlterForwardMetaVO metaVO, String role, Long currentDeptId) {
if (ROLE_BRANCH.equals(role)) {
metaVO.setDeptOptions(workRecordMapper.selectForwardDeptTargets(currentDeptId));
metaVO.setUserOptions(workRecordMapper.selectForwardUserTargets(currentDeptId, ROLE_MANAGER));
return;
}
if (ROLE_OUTLET.equals(role)) {
metaVO.setUserOptions(workRecordMapper.selectForwardUserTargets(currentDeptId, ROLE_MANAGER));
return;
}
throw new ServiceException("当前角色不支持转发预警");
}
/**
* 按客户、当前部门和当前角色查询历史推荐,并回填到前端元数据中。
*/
private void fillHistoryRecommend(AlterForwardMetaVO metaVO, String custId, Long deptId, String role) {
AlterAssignHistory history = getHistoryRecommend(custId, deptId, role);
if (history == null) {
return;
}
metaVO.setHasHistoryRecommend(true);
metaVO.setRecommendedTargetType(history.getLastAssignTargetType());
if (TARGET_TYPE_DEPT.equals(history.getLastAssignTargetType())) {
metaVO.setRecommendedTargetCode(history.getLastAssignTargetDeptId() == null ? "" : String.valueOf(history.getLastAssignTargetDeptId()));
} else {
metaVO.setRecommendedTargetCode(history.getLastAssignTargetUser());
}
metaVO.setRecommendedTargetName(history.getLastAssignTargetName());
}
/**
* 保存本次手动分配结果;同一客户在同部门、同角色下只维护一条最新历史。
*/
private void saveAssignHistory(WorkRecord workRecord, ForwardTarget target, String role, Long currentDeptId) {
AlterAssignHistory history = getHistoryRecommend(workRecord.getCustId(), currentDeptId, role);
if (history == null) {
history = new AlterAssignHistory();
history.setCustId(workRecord.getCustId());
}
history.setAlterType(workRecord.getAlterType());
history.setCustName(workRecord.getCustName());
history.setDeptId(currentDeptId);
history.setLastAssignTargetType(target.getTargetType());
history.setLastAssignTargetDeptId(target.getDeptId());
history.setLastAssignTargetUser(target.getUserName());
history.setLastAssignTargetName(target.getTargetName());
history.setLastAssignByUser(SecurityUtils.getUsername());
history.setLastAssignByRole(role);
history.setUpdateTime(new Date());
if (history.getId() == null) {
alterAssignHistoryMapper.insert(history);
} else {
alterAssignHistoryMapper.updateById(history);
}
}
/**
* 按历史推荐成功转发后,刷新该客户最新一次分配历史的更新时间和目标信息。
*/
private void saveAssignHistoryByHistory(WorkRecord workRecord, AlterAssignHistory sourceHistory, String role, Long currentDeptId) {
ForwardTarget target = new ForwardTarget(
sourceHistory.getLastAssignTargetType(),
sourceHistory.getLastAssignTargetDeptId(),
sourceHistory.getLastAssignTargetUser(),
null,
sourceHistory.getLastAssignTargetName()
);
saveAssignHistory(workRecord, target, role, currentDeptId);
}
/**
* 获取当前角色在当前部门下,对指定客户的最近一次分配历史。
*/
private AlterAssignHistory getHistoryRecommend(String custId, Long deptId, String role) {
return alterAssignHistoryMapper.selectOne(new LambdaQueryWrapper<AlterAssignHistory>()
.eq(AlterAssignHistory::getCustId, custId)
.eq(AlterAssignHistory::getDeptId, deptId)
.eq(AlterAssignHistory::getLastAssignByRole, role)
.last("limit 1"));
}
}

View File

@@ -857,6 +857,28 @@
select id,cust_name from cust_info_business where social_credit_code = #{socialCreditCode}
</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 INTO cust_info_business
(cust_id,cust_name, social_credit_code, update_by, update_time, cust_phone, industry, asset, credit)

View File

@@ -184,19 +184,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</insert>
<select id="selectAlterList" resultType="AlterVO">
select id, user_name, nick_name, alter_type, alter_detail, cust_id, cust_name, read_time, status, remark, is_feedback, cust_isn
from work_record
select wr.id, wr.user_name, wr.nick_name, wr.alter_type, wr.alter_detail, wr.cust_id, wr.cust_name,
wr.read_time, wr.status, wr.remark, wr.is_feedback, wr.cust_isn, wr.dept_id, sd.dept_name
from work_record wr
left join sys_dept sd on wr.dept_id = sd.dept_id
<where>
is_alter = 1
and user_name= #{username}
wr.is_alter = 1
and wr.user_name= #{username}
<if test="status != null and status != ''">
and status = #{status}
and wr.status = #{status}
</if>
<if test="alterType != null and alterType != ''">
and alter_type = #{alterType}
and wr.alter_type = #{alterType}
</if>
</where>
order by create_time desc, status asc
order by wr.create_time desc, wr.status asc
</select>
<select id="selectAlterCount" resultType="AlterCountVO">
@@ -209,24 +211,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
from work_record wr
left join sys_user su on su.user_name = wr.user_name
left join sys_dept d on su.dept_id = d.dept_id
left join sys_dept wd on wr.dept_id = wd.dept_id
where wr.is_alter = 1
and wr.create_time &lt;= #{reportTime}
and (
<choose>
<when test="role != null and role == 'outlet'"> su.dept_id = #{deptId} </when>
<when test="role != null and role == 'branch'"> (su.dept_id = #{deptId} or find_in_set(#{deptId},d.ancestors)) </when>
<when test="role != null and role == 'private'"> (left(su.dept_id,3) = left(#{deptId},3) and wr.cust_type in ('0', '1')) </when>
<when test="role != null and role == 'public'"> (left(su.dept_id,3) = left(#{deptId},3) and wr.cust_type = '2') </when>
<when test="role != null and role == 'ops'"> left(su.dept_id,3) = left(#{deptId},3) </when>
<when test="role != null and role == 'head'"> left(su.dept_id,3) = left(#{deptId},3) </when>
<when test="role != null and role == 'outlet'"> (su.dept_id = #{deptId} or wr.dept_id = #{deptId}) </when>
<when test="role != null and role == 'branch'"> ((su.dept_id = #{deptId} or find_in_set(#{deptId},d.ancestors)) or (wr.dept_id = #{deptId} or find_in_set(#{deptId},wd.ancestors))) </when>
<when test="role != null and role == 'private'"> ((left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) and wr.cust_type in ('0', '1')) </when>
<when test="role != null and role == 'public'"> ((left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) and wr.cust_type = '2') </when>
<when test="role != null and role == 'ops'"> (left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) </when>
<when test="role != null and role == 'head'"> (left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) </when>
</choose>)
</select>
<select id="selectAllAlterList" resultType="AlterVO">
select wr.id, wr.user_name, wr.nick_name, wr.alter_type, wr.alter_detail, wr.cust_id, wr.cust_name, wr.read_time, wr.status, wr.remark, wr.cust_type, wr.is_feedback, wr.cust_isn
select wr.id, wr.user_name, wr.nick_name, wr.alter_type, wr.alter_detail, wr.cust_id, wr.cust_name, wr.read_time,
wr.status, wr.remark, wr.cust_type, wr.is_feedback, wr.cust_isn, wr.dept_id, wd.dept_name
from work_record wr
left join sys_user su on su.user_name = wr.user_name
left join sys_dept d on su.dept_id = d.dept_id
left join sys_dept wd on wr.dept_id = wd.dept_id
where wr.is_alter = 1
<if test="status != null and status != ''">
and wr.status = #{status}
@@ -234,20 +239,120 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="alterType != null and alterType != ''">
and wr.alter_type = #{alterType}
</if>
<if test="forwardFlag != null and forwardFlag != ''">
<choose>
<when test='forwardFlag == "1"'>
and wr.alter_type in ('个人资产客户定期存款', '个人资产客户封闭式理财')
and wr.alter_detail like '[FORWARD=1]%'
</when>
<when test='forwardFlag == "0"'>
and (
(wr.alter_type in ('个人资产客户定期存款', '个人资产客户封闭式理财')
and wr.alter_detail like '[FORWARD=0]%')
or wr.alter_type not in ('个人资产客户定期存款', '个人资产客户封闭式理财')
)
</when>
</choose>
</if>
<!-- "走访异常提醒"类型直接通过用户名匹配,其他类型按角色权限处理 -->
and ((wr.alter_type = '走访异常提醒' and wr.user_name = #{username}) or
(wr.alter_type != '走访异常提醒' and (
<choose>
<when test="role != null and role == 'outlet'"> su.dept_id = #{deptId} </when>
<when test="role != null and role == 'branch'"> (su.dept_id = #{deptId} or find_in_set(#{deptId},d.ancestors)) </when>
<when test="role != null and role == 'private'"> (left(su.dept_id,3) = left(#{deptId},3) and wr.cust_type in ('0', '1')) </when>
<when test="role != null and role == 'public'"> (left(su.dept_id,3) = left(#{deptId},3) and wr.cust_type = '2') </when>
<when test="role != null and role == 'ops'"> left(su.dept_id,3) = left(#{deptId},3) </when>
<when test="role != null and role == 'head'"> left(su.dept_id,3) = left(#{deptId},3) </when>
<when test="role != null and role == 'outlet'"> (su.dept_id = #{deptId} or wr.dept_id = #{deptId}) </when>
<when test="role != null and role == 'branch'"> ((su.dept_id = #{deptId} or find_in_set(#{deptId},d.ancestors)) or (wr.dept_id = #{deptId} or find_in_set(#{deptId},wd.ancestors))) </when>
<when test="role != null and role == 'private'"> ((left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) and wr.cust_type in ('0', '1')) </when>
<when test="role != null and role == 'public'"> ((left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) and wr.cust_type = '2') </when>
<when test="role != null and role == 'ops'"> (left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) </when>
<when test="role != null and role == 'head'"> (left(su.dept_id,3) = left(#{deptId},3) or left(wr.dept_id,3) = left(#{deptId},3)) </when>
</choose> )))
order by wr.create_time desc, wr.status asc, wr.user_name desc
</select>
<select id="selectForwardDeptTargets" resultType="AlterAssignTargetVO">
select cast(sd.dept_id as char) as targetCode, sd.dept_name as targetName
from sys_dept sd
where sd.del_flag = '0'
and sd.status = '0'
and sd.dept_type = 'outlet'
and sd.parent_id = #{branchDeptId}
order by sd.order_num, sd.dept_id
</select>
<select id="selectForwardUserTargets" resultType="AlterAssignTargetVO">
select su.user_name as targetCode, concat(su.nick_name, '-', su.user_name) as targetName
from sys_user su
where su.del_flag = '0'
and su.status = '0'
and su.dept_id = #{deptId}
<choose>
<when test="role == 'manager'">
and su.role_id = 102
</when>
<when test="role == 'branch'">
and su.role_id = 101
</when>
<when test="role == 'outlet'">
and su.role_id = 116
</when>
<otherwise>
and 1 = 2
</otherwise>
</choose>
order by su.nick_name, su.user_name
</select>
<update id="updateAlterForwardToDept">
update work_record
set user_name = null,
nick_name = null,
dept_id = #{targetDeptId},
read_time = null,
update_time = sysdate(),
update_by = #{updateBy}
where id = #{id}
and user_name = #{sourceUserName}
and dept_id is null
and is_alter = 1
</update>
<update id="updateAlterForwardToUserByBranch">
update work_record
set user_name = #{targetUserName},
nick_name = #{targetNickName},
alter_detail = case
when alter_detail like '[FORWARD=1] %' then concat('[FORWARD=0] ', substring(alter_detail, 13))
when alter_detail like '[FORWARD=1]%' then concat('[FORWARD=0]', substring(alter_detail, 12))
else alter_detail
end,
dept_id = null,
read_time = null,
update_time = sysdate(),
update_by = #{updateBy}
where id = #{id}
and user_name = #{sourceUserName}
and dept_id is null
and is_alter = 1
</update>
<update id="updateAlterForwardToUserByOutlet">
update work_record
set user_name = #{targetUserName},
nick_name = #{targetNickName},
alter_detail = case
when alter_detail like '[FORWARD=1] %' then concat('[FORWARD=0] ', substring(alter_detail, 13))
when alter_detail like '[FORWARD=1]%' then concat('[FORWARD=0]', substring(alter_detail, 12))
else alter_detail
end,
dept_id = null,
read_time = null,
update_time = sysdate(),
update_by = #{updateBy}
where id = #{id}
and dept_id = #{sourceDeptId}
and user_name is null
and is_alter = 1
</update>
<select id="selectAlterConfigList" resultType="AlterConfigVO">
select id, alter_type, prod_type, warn_role, warn_threshold, update_time, update_by, type
from alter_config

View File

@@ -167,6 +167,36 @@
</where>
</select>
<select id="getCustManagerListByPage" resultType="DwbRetailCustLevelManagerDetailVO">
select id, outlet_id, outlet_name, branch_id, branch_name, cust_name, cust_idc, cust_isn, cust_age, cust_sex, cust_phone, cust_address, cust_aum_bal,
aum_bal_comp_lm, cust_aum_month_avg, cust_level, cust_level_comp_lm, manager_name, manager_id
from dwb_retail_cust_level_manager_detail_${headId}
<where>
<if test="dto.managerId != null and dto.managerId !='' ">and manager_id = #{dto.managerId}</if>
<if test="dto.outletId != null and dto.outletId !='' ">and outlet_id = #{dto.outletId}</if>
<if test="dto.branchId != null and dto.branchId !='' ">and branch_id = #{dto.branchId}</if>
<if test="dto.statusType != null and dto.statusType !=''">
<choose>
<when test="dto.statusType == 'current'">
and cust_level = #{dto.custLevel}
</when>
<when test="dto.statusType == 'last'">
and cust_level_lm = #{dto.custLevel}
</when>
<when test="dto.statusType == 'rise'">
and cust_level = #{dto.custLevel}
and cust_level_comp_lm like '上升%'
</when>
<when test="dto.statusType == 'fall'">
and cust_level_lm = #{dto.custLevel}
and cust_level_comp_lm like '下降%'
</when>
</choose>
</if>
</where>
limit #{offset}, #{pageSize}
</select>
<select id="getCustLevelCount" resultType="Integer">
select count(1)
from dwb_retail_cust_level_manager_detail
@@ -505,26 +535,20 @@
where manager_id is not null
</select>
<!-- 根据网格类型和总行ID查询客户经理列表 -->
<select id="getManagerListByGridType" resultType="java.util.HashMap">
select distinct user_name as userName, nick_name as nickName
<!-- 全量查询绩效网格客户列表(用于客群管户关系匹配,不按客户经理过滤)-->
<select id="getAllCustomerListForImport" resultType="GridCmpmVO">
select cust_id, cust_type, user_name, nick_name, outlet_id, outlet_name, branch_id, branch_name
from grid_cmpm_${gridType}_${headId}
where user_name is not null
order by user_name
</select>
<!-- 根据网格类型、总行ID和客户经理查询客户列表分表查询适用于客群导入-->
<select id="getCustomerListForImport" resultType="GridCmpmVO">
select cust_id, cust_name, cust_type, cust_idc, usci
<!-- 根据客户ID列表查询管户关系用于动态客群更新管户关系-->
<select id="getRelationshipsByCustList" resultType="GridCmpmVO">
select cust_id, cust_type, user_name, nick_name, outlet_id, outlet_name, branch_id, branch_name
from grid_cmpm_${gridType}_${headId}
where user_name = #{userName}
</select>
<!-- 根据网格类型、总行ID和客户经理流式查询客户列表使用Cursor适用于大数据量场景-->
<select id="getCustomerListForImportCursor" resultType="GridCmpmVO" fetchSize="1000">
select cust_id, cust_name, cust_type, cust_idc, usci
from grid_cmpm_${gridType}_${headId}
where user_name = #{userName}
where
<foreach item="custInfo" collection="custInfoList" separator=" or " open="(" close=")">
(cust_id = #{custInfo.custId} and cust_type = #{custInfo.custType})
</foreach>
</select>
</mapper>

View File

@@ -56,16 +56,4 @@
<if test="custType != null and custType != ''">AND b.cust_type = #{custType}</if>
</select>
<!-- 根据绘制网格ID查询所有客户用于客群导入直接拼接headId绕过拦截器 -->
<select id="selectCustByDrawGridId" resultType="com.ruoyi.ibs.grid.domain.entity.RegionCustUser">
SELECT DISTINCT
sc.cust_id,
sc.cust_name,
sc.cust_type
FROM grid_draw_shape_relate sr
INNER JOIN draw_shape_cust_${headId} sc ON sc.shape_id = sr.shape_id
WHERE sr.grid_id = #{gridId}
AND sr.delete_flag = '0'
</select>
</mapper>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.ibs.draw.mapper.DrawGridShapeRelateMapper">
<select id="selectByGridId" resultType="com.ruoyi.ibs.draw.domain.entity.DrawGridShapeRelate">
SELECT *
FROM grid_draw_shape_relate
WHERE grid_id = #{gridId}
AND delete_flag = '0'
</select>
<select id="selectCustByDrawGridId" resultType="com.ruoyi.ibs.grid.domain.entity.RegionCustUser">
SELECT DISTINCT
sc.cust_id,
sc.cust_name,
sc.cust_type
FROM grid_draw_shape_relate sr
INNER JOIN draw_shape_cust_${headId} sc ON sc.shape_id = sr.shape_id
WHERE sr.grid_id = #{gridId}
AND sr.delete_flag = '0'
</select>
</mapper>

View File

@@ -21,6 +21,24 @@
</where>
</select>
<select id="selectLsCountListNew825" resultType="com.ruoyi.ibs.grid.domain.entity.GridCmpmCountLingshouNew825">
SELECT dt, grid_name, grid_name2, county, town, village, dept_id, dept_name, outlets_id, outlets_name,
user_name, cust_num, zf_365cnt, zf_180cnt, zf_90cnt, zf_30cnt, zf_365rt, zf_180rt, zf_90rt,
zf_30rt, cur_bal_d, sx_rat, yx_rat, sx_num, yx_num, sx_bal, bal_loan, loan_ave, yxht_rat, dian_rat,
shui_rat, tax_rat, open_rat, yxht_num, dian_num, shui_num, tax_num, open_num, dep_bal, fin_bal,
grhx_num, cfyx_num, yxxyk_num, yxsbk_num, `2to3_sbk_num` as twoTo3SbkNum, ylj_to_sbk_num,
fshl_num, yxsd_num, hxsd_num, region_code, ops_dept
FROM grid_cmpm_count_lingshou_new_825
<where>
<if test=" dt != null and dt != ''">and dt = #{dt}</if>
<if test=" town != null and town != ''">and town like concat('%',concat(#{town},'%'))</if>
<if test=" village != null and village != ''">and village like concat('%',concat(#{village},'%'))</if>
<if test=" isBranch == true">and dept_id like concat('%',concat(#{deptId},'%'))</if>
<if test=" isOutlet == true">and outlets_id like concat('%',concat(#{deptId},'%'))</if>
<if test=" isManager == true">and user_name like concat('%',concat(#{userName},'%'))</if>
</where>
</select>
<select id="selectGsCountList" resultType="com.ruoyi.ibs.grid.domain.entity.GridCmpmCountGongsi">
SELECT dt, grid_name, grid_name2, town, dept_id,dept_name, outlets_id,outlets_name, user_name,
cust_num, hq_cur_balance, bz_cur_balance, loan_balance_cny, finance_prod_711_balance,ustr_count_per_m,ustr_bal_m,
@@ -59,6 +77,47 @@
<if test=" custIdc != null and custIdc != ''">and cust_idc like concat('%',concat(#{custIdc},'%'))</if>
</select>
<select id="selectLsCustListNew825" resultType="com.ruoyi.ibs.grid.domain.entity.GridCustCountLingshouNew825">
SELECT cust_name,
cust_idc,
cust_isn,
cur_bal_d,
bal_loan,
loan_ave,
is_sx,
is_yx,
sx_bal,
is_yxht,
is_xyk,
fshl,
is_sd,
dian,
shui,
tax,
open_num,
dep_bal,
fin_bal,
is_grhx,
is_cfyx,
is_yxsbk,
is_2to3_sbk,
is_ylj_to_sbk,
is_hxsd,
region_code,
ops_dept,
cust_type,
is_365zf,
is_180zf,
is_90zf,
is_30zf,
dt
FROM grid_cust_count_lingshou_new_825
where region_code = #{regionCode}
<if test=" dt != null and dt != ''">and dt = #{dt}</if>
<if test=" custName != null and custName != ''">and cust_name like concat('%',concat(#{custName},'%'))</if>
<if test=" custIdc != null and custIdc != ''">and cust_idc like concat('%',concat(#{custIdc},'%'))</if>
</select>
<select id="selectGsCustList" resultType="com.ruoyi.ibs.grid.domain.entity.GridCustCountGongsi">
SELECT cust_name, social_credit_code, cust_isn, hq_cur_balance, bz_cur_balance, is_credit,

View File

@@ -239,17 +239,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
case when left(vc.campaign_id,7)='appoint' then '-1' else sc.create_role end as create_role ,
case
when dep2.dept_type = 'head' then dep.dept_id
else dep2.dept_id
when hist_branch_dep.dept_id is not null then hist_branch_dep.dept_id
when current_branch_dep.dept_type = 'head' or current_branch_dep.dept_type is null then current_outlet_dep.dept_id
else current_branch_dep.dept_id
end as dept_id,
case
when dep2.dept_type = 'head' then ''
else dep.dept_name
when hist_branch_dep.dept_id is not null then ifnull(hist_outlet_dep.dept_name, '')
when current_branch_dep.dept_type = 'head' or current_branch_dep.dept_type is null then ''
else current_outlet_dep.dept_name
end as outlets,
case
when dep2.dept_type = 'head' then dep.dept_name
else dep2.dept_name
when hist_branch_dep.dept_id is not null then hist_branch_dep.dept_name
when current_branch_dep.dept_type = 'head' or current_branch_dep.dept_type is null then current_outlet_dep.dept_name
else current_branch_dep.dept_name
end as dept_name,
concat( su.nick_name, '-', su.user_name ) as nick_name,
@@ -261,25 +264,48 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
visit_campaign_count vc left join sys_campaign sc on
vc.campaign_id = sc.campaign_id left join sys_user su on
vc.dept_id = su.user_name
left join sys_dept dep on su.dept_id = dep.dept_id
left join sys_dept dep2 on dep.parent_id = dep2.dept_id
left join (
select campaign_id, user_id, max(dept_id) as dept_id, max(outlets_id) as outlets_id
from sys_campaign_group_customer
where user_id is not null
group by campaign_id, user_id
) scgc_his on scgc_his.campaign_id = vc.campaign_id and scgc_his.user_id = su.user_id
left join sys_dept hist_branch_dep on scgc_his.dept_id = hist_branch_dep.dept_id
left join sys_dept hist_outlet_dep on scgc_his.outlets_id = hist_outlet_dep.dept_id
left join sys_dept current_outlet_dep on su.dept_id = current_outlet_dep.dept_id
left join sys_dept current_branch_dep on current_outlet_dep.parent_id = current_branch_dep.dept_id
where
vc.dept_type = '3'
<if test="campaignId != null and campaignId != ''"> and vc.campaign_id = #{campaignId}</if>
<if test="campaignName != null and campaignName != ''"> AND sc.campaign_name like concat('%', #{campaignName}, '%')</if>
<choose>
<when test="outletsId != null">
AND (dep.dept_id = #{outletsId} OR dep2.dept_id = #{outletsId})
AND ifnull(
scgc_his.outlets_id,
case
when current_branch_dep.dept_type = 'head' or current_branch_dep.dept_type is null then null
else current_outlet_dep.dept_id
end
) = #{outletsId}
</when>
<otherwise>
<if test="deptId != null and personType == 'branch' and deptId.toString().endsWith('000')">
AND dep.dept_id = #{deptId}
</if>
<if test="deptId != null and personType == 'branch'">
AND (dep.dept_id = #{deptId} OR dep2.dept_id = #{deptId})
AND ifnull(
scgc_his.dept_id,
case
when current_branch_dep.dept_type = 'head' or current_branch_dep.dept_type is null then current_outlet_dep.dept_id
else current_branch_dep.dept_id
end
) = #{deptId}
</if>
<if test="deptId != null and personType == 'outlet'">
AND (dep.dept_id = #{deptId})
AND ifnull(
scgc_his.outlets_id,
case
when current_branch_dep.dept_type = 'head' or current_branch_dep.dept_type is null then null
else current_outlet_dep.dept_id
end
) = #{deptId}
</if>
</otherwise>
</choose>

View File

@@ -127,6 +127,18 @@
<result property="remark" column="remark" />
<result property="custType" column="cust_type" />
<result property="deptName" column="dept_name" />
<result property="interAddr" column="inter_addr" />
<result property="colStafName" column="col_staf_name" />
<result property="laterNote" column="later_note" />
<result property="intentionProductValue" column="intention_product_value" />
<result property="feedbackStatus" column="feedback_status" />
<result property="sourceOfInterview" column="source_of_interview" />
<result property="filename" column="filename" />
<result property="outCallStatus" column="out_call_status" />
<result property="outCallIntention" column="out_call_intention" />
<result property="source" column="source" />
<result property="analysisValue" column="analysis_value" />
<result property="facility" column="facility" />
</resultMap>
<sql id="selectSysCampaignVo">
@@ -1388,8 +1400,10 @@
from visit_info vi
left join sys_dept d on vi.dept_id = d.dept_id
<where>
<if test="campaignId != null and campaignId != ''"> and vi.campaign_id = #{campaignId}</if>
<if test="custType != null and custType != ''"> and vi.cust_type = #{custType}</if>
<if test="visName != null and visName != ''"> and vi.vis_name like concat('%', #{visName}, '%')</if>
<if test="visId != null and visId != ''"> and vi.vis_id = #{visId}</if>
<if test="custIdc != null and custIdc != ''"> and vi.cust_idc = #{custIdc}</if>
<if test="socialCreditCode != null and socialCreditCode != ''"> and vi.social_credit_code = #{socialCreditCode}</if>
<if test="abnormalVisitTag != null and abnormalVisitTag != ''"> and vi.abnormal_visit_tag = #{abnormalVisitTag}</if>
@@ -1410,4 +1424,57 @@
order by vi.sign_in_time desc
</select>
<select id="selectVisitInfoList875" parameterType="VisitInfoDTO" resultType="VisitInfoVO">
select vi.id,vi.campaign_id,vi.campaign_name,vi.vis_name,vi.vis_id,vi.dept_id,d.dept_name,vi.vis_time,vi.cust_name,vi.cust_type,vi.cust_idc,
vi.social_credit_code,vi.create_by,vi.create_time,vi.update_by,vi.update_time,vi.remark,vi.sign_in_time,vi.sign_out_time,vi.sign_in_address,
vi.sign_out_address,vi.abnormal_visit_tag,vi.abnormal_visit_info,vi.sign_in_coordinate,vi.sign_out_coordinate,vi.is_valid_cust,vi.marketing_way,vi.inter_res,
vi.inter_addr,vi.col_staf_name,vi.later_note,vi.intention_product_value,vi.feedback_status,vi.source_of_interview,vi.filename,
vi.out_call_status,vi.out_call_intention,vi.source,vi.analysis_value,vi.facility
from visit_info_875 vi
left join sys_dept d on vi.dept_id = d.dept_id
<where>
<if test="campaignId != null and campaignId != ''"> and vi.campaign_id = #{campaignId}</if>
<if test="custType != null and custType != ''"> and vi.cust_type = #{custType}</if>
<if test="visName != null and visName != ''"> and vi.vis_name like concat('%', #{visName}, '%')</if>
<if test="visId != null and visId != ''"> and vi.vis_id = #{visId}</if>
<if test="custIdc != null and custIdc != ''"> and vi.cust_idc = #{custIdc}</if>
<if test="socialCreditCode != null and socialCreditCode != ''"> and vi.social_credit_code = #{socialCreditCode}</if>
<if test="abnormalVisitTag != null and abnormalVisitTag != ''"> and vi.abnormal_visit_tag = #{abnormalVisitTag}</if>
<if test="marketingWay != null and marketingWay != ''"> and vi.marketing_way = #{marketingWay}</if>
<if test="interRes != null and interRes != ''"> and vi.inter_res = #{interRes}</if>
<if test="visTime != null">
and (vi.sign_in_time like concat(#{visTime}, '%') or vi.sign_out_time like concat(#{visTime}, '%'))
</if>
<if test="userRole != null">
<choose>
<when test="userRole == 'manager'"> and vi.vis_id = #{userName} </when>
<when test="userRole == 'outlet'"> and d.dept_id = #{deptId} </when>
<when test="userRole == 'branch'"> and (d.dept_id = #{deptId} or find_in_set(#{deptId},d.ancestors)) </when>
<when test="userRole in {'head', 'ops', 'public', 'private'}"> and left(d.dept_id,3) = left(#{deptId},3) </when>
</choose>
</if>
</where>
order by vi.sign_in_time desc
</select>
<update id="updateVisitInfoFeedback" parameterType="VisitInfoFeedbackUpdateDTO">
update visit_info_875 vi
left join sys_dept d on vi.dept_id = d.dept_id
set vi.source = #{source},
vi.remark = #{remark},
vi.intention_product_value = #{intentionProductValue},
vi.inter_res = '0',
vi.update_by = #{userName},
vi.update_time = sysdate()
where vi.id = #{id}
<if test="userRole != null">
<choose>
<when test="userRole == 'manager'"> and vi.vis_id = #{userName} </when>
<when test="userRole == 'outlet'"> and d.dept_id = #{deptId} </when>
<when test="userRole == 'branch'"> and (d.dept_id = #{deptId} or find_in_set(#{deptId},d.ancestors)) </when>
<when test="userRole in {'head', 'ops', 'public', 'private'}"> and left(d.dept_id,3) = left(#{deptId},3) </when>
</choose>
</if>
</update>
</mapper>

View File

@@ -215,6 +215,13 @@
<version>${ruoyi.version}</version>
</dependency>
<!-- 数字支行-客群模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ibs-group</artifactId>
<version>3.8.8</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -28,6 +28,10 @@ spring:
username: root
password: Kfcx@1234
driverClassName: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://rm-bp17634n45cj631s0ao.mysql.rds.aliyuncs.com/ibs?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&allowMultiQueries=true
# username: znsj
# password: Znsj@123456
# driverClassName: com.mysql.cj.jdbc.Driver
# 从库数据源
slave:
# 从数据源开关/默认关闭
@@ -78,12 +82,14 @@ spring:
redis:
# 地址
host: 116.62.17.81
# host: r-bp1mmtcknvsscsrjrypd.redis.rds.aliyuncs.com
# 端口默认为6379
port: 6380
port: 6379
# 数据库索引
database: 0
# 密码
password: Kfcx@1234
# password: N0f3d12c4a927eee1+
# 连接超时时间
timeout: 10s
lettuce:
@@ -121,5 +127,9 @@ oss:
accessKeyId: LTAI5tMsUgorcgnpTxZDV1wS
accessKeySecret: c7qIjXIPx8Cz2CriJpYGyCFwFjRxeB
bucketName: oss-wkc
# endpoint: oss-cn-hangzhou.aliyuncs.comBucket:znjgoss.oss-cn-hangzhou.aliyuncs.com
# accessKeyId: LTAI5tCRocKhQaCtFnYKp46w
# accessKeySecret: 0ovFbMQWas1wOZTG91mpKbV70JgR32
# bucketName: oss-wkc

View File

@@ -68,7 +68,7 @@ mybatis-plus:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
mapperLocations: classpath*:mapper/*Mapper.xml,classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
type-handlers-package: com.ruoyi.ibs.handler

View File

@@ -38,6 +38,10 @@
<groupId>com.ruoyi</groupId>
<artifactId>ibs</artifactId>
</dependency>
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ibs-group</artifactId>
</dependency>
</dependencies>

View File

@@ -1,6 +1,7 @@
package com.ruoyi.quartz.task;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.group.service.ICustGroupService;
import com.ruoyi.ibs.cmpm.service.GridCmpmService;
import com.ruoyi.ibs.dashboard.service.FileOptService;
import com.ruoyi.ibs.draw.service.DrawGridCustService;
@@ -47,6 +48,9 @@ public class RyTask
@Resource
private AddressAnalyseService addressAnalyseService;
@Resource
private ICustGroupService custGroupService;
public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
{
@@ -111,4 +115,12 @@ public class RyTask
addressAnalyseService.pointInGeometryScheduled();
}
public void updateDynamicCustGroups() {
custGroupService.updateDynamicCustGroups();
}
public void checkAndDisableExpiredGroups() {
custGroupService.checkAndDisableExpiredGroups();
}
}

View File

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

View File

@@ -20,7 +20,9 @@ public enum OssFileEnum {
VISIT_RECORD("VISIT_RECORD/"),
CUST_MAP_EXPORT("CUST_MAP_EXPORT/");
CUST_MAP_EXPORT("CUST_MAP_EXPORT/"),
CUST_MANAGER_REPORT("CUST_MANAGER_REPORT/");
private String PREFIX;

View File

@@ -133,8 +133,13 @@ public class SysDeptServiceImpl implements ISysDeptService
@Override
public List<TreeSelect> selectDeptTreeListForTopGrid(SysDept dept) {
List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
List<SysDept> branchs = depts.stream().filter(sysDept -> !sysDept.getDeptType().equals("outlet"))
.filter(sysDept -> !sysDept.getDeptType().equals("head"))
if (depts == null || depts.isEmpty()) {
return Collections.emptyList();
}
List<SysDept> branchs = depts.stream()
.filter(Objects::nonNull)
.filter(sysDept -> !"outlet".equals(sysDept.getDeptType()))
.filter(sysDept -> !"head".equals(sysDept.getDeptType()))
.collect(Collectors.toList());
return buildDeptTreeSelect(branchs);
}

View File

@@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="noticeType" column="notice_type" />
<result property="noticeContent" column="notice_content" />
<result property="status" column="status" />
<result property="deptIds" column="dept_ids" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
@@ -18,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<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
</sql>
@@ -39,6 +40,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createBy != null and createBy != ''">
AND create_by like concat('%', #{createBy}, '%')
</if>
<if test="currentHeadDeptId != null and currentHeadDeptId != ''">
AND (dept_ids is null or dept_ids = '' or find_in_set(#{currentHeadDeptId}, dept_ids))
</if>
</where>
</select>
@@ -48,6 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="noticeType != null and noticeType != '' ">notice_type, </if>
<if test="noticeContent != null and noticeContent != '' ">notice_content, </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="createBy != null and createBy != ''">create_by,</if>
create_time
@@ -56,6 +61,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="noticeType != null and noticeType != ''">#{noticeType}, </if>
<if test="noticeContent != null and noticeContent != ''">#{noticeContent}, </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="createBy != null and createBy != ''">#{createBy},</if>
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="noticeContent != null">notice_content = #{noticeContent}, </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>
update_time = sysdate()
</set>

View File

@@ -92,3 +92,19 @@ export function uploadTag(data) {
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

@@ -23,3 +23,11 @@ export function getCustLevelList() {
method: 'get'
})
}
export function exportCustManagerReport(data) {
return request({
url: '/grid/cmpm/custManager/export',
method: 'post',
data
})
}

View File

@@ -17,15 +17,6 @@ export function getCustGroup(id) {
})
}
// 异步创建客群(网格导入)
export function createCustGroupByGrid(data) {
return request({
url: '/group/cust/createByGrid',
method: 'post',
data: data
})
}
// 异步创建客群(模板导入)
export function createCustGroupByTemplate(data) {
return request({
@@ -36,24 +27,6 @@ export function createCustGroupByTemplate(data) {
})
}
// 更新客群
export function updateCustGroup(data) {
return request({
url: '/group/cust/update',
method: 'post',
data: data
})
}
// 更新客群(网格导入)
export function updateCustGroupByGrid(data) {
return request({
url: '/group/cust/updateByGrid',
method: 'post',
data: data
})
}
// 更新客群(模板导入)
export function updateCustGroupByTemplate(data) {
return request({
@@ -93,31 +66,13 @@ export function deleteCustGroup(idList) {
// 手动移除客群客户
export function removeMembers(groupId, memberIds) {
return request({
url: '/group/cust/removeMembers',
url: '/group/member/remove',
method: 'post',
params: { groupId: groupId },
data: memberIds
})
}
// 检查客群名称是否存在
export function checkGroupNameExist(groupName) {
return request({
url: '/group/cust/checkName',
method: 'get',
params: { groupName: groupName }
})
}
// 根据网格类型获取客户经理列表
export function getManagerList(gridType) {
return request({
url: '/grid/cmpm/managerList',
method: 'get',
params: { gridType: gridType }
})
}
// 分页查询客群成员列表
export function listCustGroupMembers(groupId, query) {
return request({
@@ -135,3 +90,11 @@ export function getRegionGridListForGroup(query) {
params: query
})
}
// 获取所有客群标签列表
export function getAllGroupTags() {
return request({
url: '/group/cust/tags',
method: 'get'
})
}

View File

@@ -0,0 +1,69 @@
import request from '@/utils/request';
export function getGroupPerformanceLsList(params) {
return request({
url: '/group/performance/ls/list',
method: 'get',
params
});
}
export function getGroupPerformanceGsList(params) {
return request({
url: '/group/performance/gs/list',
method: 'get',
params
});
}
export function getGroupPerformanceLsCustList(params) {
return request({
url: '/group/performance/ls/custList',
method: 'get',
params
});
}
export function getGroupPerformanceGsCustList(params) {
return request({
url: '/group/performance/gs/custList',
method: 'get',
params
});
}
export function exportGroupPerformanceLs(params) {
return request({
url: '/group/performance/exportLs',
method: 'get',
params,
responseType: 'blob'
});
}
export function exportGroupPerformanceGs(params) {
return request({
url: '/group/performance/exportGs',
method: 'get',
params,
responseType: 'blob'
});
}
export function exportGroupPerformanceLsCust(params) {
return request({
url: '/group/performance/exportLsCust',
method: 'get',
params,
responseType: 'blob'
});
}
export function exportGroupPerformanceGsCust(params) {
return request({
url: '/group/performance/exportGsCust',
method: 'get',
params,
responseType: 'blob'
});
}

View File

@@ -204,12 +204,22 @@ export function warningworkRecordList(query) {
params: query
})
}
//更新预警工作清单
export function warningworkRecordSubmit(data) {
// 查询预警转发元数据
export function getAlterForwardMeta(query) {
return request({
url: `/work/record/alter/edit`,
url: `/work/record/alter/forward/meta`,
method: 'get',
params: query
})
}
// 预警转发
export function forwardAlter(data) {
return request({
url: `/work/record/alter/forward`,
method: 'post',
data: data,
data
})
}

View File

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

View File

@@ -7,3 +7,11 @@ export function getPADVisitRecord(query) {
params: query
})
}
export function updatePADVisitFeedback(data) {
return request({
url: `/system/campaign/updateVisitInfoFeedback`,
method: 'post',
data: data
})
}

View File

@@ -15,10 +15,17 @@
<div class="right-menu">
<template v-if="device !== 'mobile'">
<el-badge v-if="downloadUnreadCount > 0" :value="downloadUnreadCount" class="item download-item">
<i
class="el-icon-download right-menu-item notice"
@click="openDownload"
/>
</el-badge>
<i
v-else
class="el-icon-download right-menu-item notice"
@click="openDownload"
/>
<el-badge v-if="notReadCount > 0" :value="notReadCount" class="item">
<i
class="el-icon-chat-dot-round right-menu-item notice"
@@ -168,11 +175,14 @@ export default {
notReadCount: 0,
noticeCenterList: [],
open2: false,
downCenterList: []
downCenterList: [],
downloadUnreadCount: 0,
downloadPollingTimer: null,
downloadStatusMap: {}
};
},
computed: {
...mapGetters(['sidebar', 'avatar', 'device', 'nickName']),
...mapGetters(['sidebar', 'avatar', 'device', 'nickName', 'userName']),
setting: {
get() {
return this.$store.state.settings.showSettings;
@@ -192,6 +202,14 @@ export default {
},
created() {
this.getCenterList();
this.refreshDownloadCenterList();
window.addEventListener('notice-center-refresh', this.getCenterList);
window.addEventListener('download-center-refresh', this.handleDownloadCenterRefresh);
},
beforeDestroy() {
window.removeEventListener('notice-center-refresh', this.getCenterList);
window.removeEventListener('download-center-refresh', this.handleDownloadCenterRefresh);
this.stopDownloadPolling();
},
methods: {
openModal() {
@@ -199,8 +217,9 @@ export default {
this.open = true;
},
openDownload() {
this.getDownCenterList();
this.refreshDownloadCenterList(false, true).finally(() => {
this.open2 = true;
});
},
// 消息已读
handleHasRead(uuid) {
@@ -233,10 +252,115 @@ export default {
});
},
handleDownloadCenterRefresh() {
this.refreshDownloadCenterList(false, false, true);
},
startDownloadPolling() {
if (this.downloadPollingTimer) {
return;
}
this.downloadPollingTimer = setInterval(() => {
this.refreshDownloadCenterList(true);
}, 10000);
},
stopDownloadPolling() {
if (this.downloadPollingTimer) {
clearInterval(this.downloadPollingTimer);
this.downloadPollingTimer = null;
}
},
getDownloadReadStorageKey() {
return `download-center-read-${this.userName || 'default'}`;
},
getReadTaskIds() {
try {
const cache = localStorage.getItem(this.getDownloadReadStorageKey());
const ids = cache ? JSON.parse(cache) : [];
return Array.isArray(ids) ? ids : [];
} catch (e) {
return [];
}
},
setReadTaskIds(ids) {
localStorage.setItem(this.getDownloadReadStorageKey(), JSON.stringify(ids));
},
getDownloadInitStorageKey() {
return `download-center-init-${this.userName || 'default'}`;
},
hasInitializedDownloadReadState() {
return localStorage.getItem(this.getDownloadInitStorageKey()) === '1';
},
markDownloadReadStateInitialized() {
localStorage.setItem(this.getDownloadInitStorageKey(), '1');
},
updateDownloadUnreadCount(taskList = []) {
const readSet = new Set(this.getReadTaskIds());
this.downloadUnreadCount = taskList.filter(item => item.status !== '0' && !readSet.has(item.id)).length;
},
markDownloadTasksAsRead(taskList = []) {
const readSet = new Set(this.getReadTaskIds());
taskList.filter(item => item.status !== '0').forEach(item => readSet.add(item.id));
this.setReadTaskIds(Array.from(readSet));
this.updateDownloadUnreadCount(taskList);
},
refreshDownloadCenterList(showStatusMessage = false, markAsRead = false, allowPolling = false) {
return getDownCenterList({}).then((res) => {
if (res.code == 200) {
const rows = res.rows || [];
const hasPendingTask = rows.some(item => item.status === '0');
if (!this.hasInitializedDownloadReadState()) {
const initialReadIds = rows.filter(item => item.status !== '0').map(item => item.id);
this.setReadTaskIds(initialReadIds);
this.markDownloadReadStateInitialized();
}
if (showStatusMessage) {
rows.forEach(item => {
const prevStatus = this.downloadStatusMap[item.id];
if (prevStatus === '0' && item.status === '1') {
Message.success(`${item.fileName}导出成功,请前往下载中心下载`);
} else if (prevStatus === '0' && item.status === '2') {
Message.warning(`${item.fileName}导出失败,请前往下载中心查看`);
}
});
}
this.downloadStatusMap = rows.reduce((acc, item) => {
acc[item.id] = item.status;
return acc;
}, {});
this.downCenterList = rows;
if (markAsRead) {
this.markDownloadTasksAsRead(rows);
} else {
this.updateDownloadUnreadCount(rows);
}
if (allowPolling && hasPendingTask) {
this.startDownloadPolling();
} else {
this.stopDownloadPolling();
}
}
});
},
// 消息列表下载文件
downLoadFile(item) {
const {fileUrl, fileName, status} = item
if (!fileUrl) return;
if (status === '0') {
Message.warning('正在导出,请稍后下载');
return
@@ -245,9 +369,11 @@ export default {
Message.warning('导出失败,无法下载');
return
}
if (!fileUrl) return;
downCenterDownload({ fileUrl }).then((res) => {
downloadFiles(res, `${fileName}.xlsx`);
Message.success('下载成功');
this.markDownloadTasksAsRead(this.downCenterList);
});
},
@@ -378,6 +504,12 @@ export default {
padding-top: 0;
}
}
.download-item {
::v-deep .el-badge__content.is-fixed {
top: 18px;
right: 18px;
}
}
}
}
.page-common-wrap {

View File

@@ -238,6 +238,28 @@ export const constantRoutes = [
component: () => import('@/views/group/custGroup/detail')
}]
},
{
path: '/center/groupPerformance/list',
component: Layout,
hidden: true,
children: [{
path: '/center/groupPerformance/list',
name: 'GroupPerformanceList',
meta: { title: '客群业绩统计', activeMenu: '/center/groupPerformance/list' },
component: () => import('@/views/group/performance/list')
}]
},
{
path: '/center/groupPerformance/custom',
component: Layout,
hidden: true,
children: [{
path: '/center/groupPerformance/custom',
name: 'GroupPerformanceCustom',
meta: { title: '客群客户明细', activeMenu: '/center/groupPerformance/list' },
component: () => import('@/views/group/performance/custom')
}]
},
{
path: '/checklist/customerlist',
component: Layout,
@@ -353,7 +375,7 @@ export const constantRoutes = [
meta: { title: '个人中心', icon: 'user' }
}
]
},
}
];
// 动态路由,基于用户权限动态去加载

View File

@@ -432,7 +432,7 @@
v-if="item.cmpmType == '贷款客户经理'"
:label="`${item.cmpmType}`"
>
<span>{{ item.cmpmUserList }}</span>
<span>{{ is932Dept ? `${baseForm.belongUserName}-${baseForm.belongUserId}` : item.cmpmUserList }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -1242,6 +1242,7 @@ export default {
businessScope: '',
gridUserName: '',
belongUserName: '',
belongUserId: '',
updateTime: ''
},
registerLocationNum: '',
@@ -1374,7 +1375,7 @@ export default {
Custom
},
computed: {
...mapGetters(['roles', 'userName']),
...mapGetters(['roles', 'userName', 'deptId']),
isHeadAdmin() {
return this.roles.includes('headAdmin')
},
@@ -1386,6 +1387,10 @@ export default {
isPrivate() {
return this.roles.includes('headPrivate')
},
// 是否932开头部门
is932Dept() {
return String(this.deptId || '').substring(0, 3) === '932'
},
// 运管部
isHeadOps() {
return this.roles.includes('headOps')

View File

@@ -437,7 +437,7 @@
v-if="item.cmpmType == '贷款客户经理'"
:label="`${item.cmpmType}`"
>
<span>{{ item.cmpmUserList }}</span>
<span>{{ is932Dept ? `${baseForm.belongUserName}-${baseForm.belongUserId}` : item.cmpmUserList }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -1024,6 +1024,77 @@
</el-table-column>
</el-table>
</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-dialog
title="该客户尚未建档,请先进行营销建档"
@@ -1215,7 +1286,120 @@ import { downloadFiles } from '@/utils'
import { mapGetters } from 'vuex'
import { cloneDeep, isEmpty } from 'lodash'
import _ from 'lodash'
import * as echarts from 'echarts'
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 {
data() {
var validatePhone = (rule, value, callback) => {
@@ -1276,6 +1460,7 @@ export default {
tel: '',
gridUserName: '',
belongUserName: '',
belongUserId: '',
updateTime: ''
},
registerLocationNum: '',
@@ -1347,6 +1532,12 @@ export default {
showTagsList:[],
addTagName:"",
newCustTag:[],
// 企业九维数据
ent9vPortrait: null,
nineVFinalInfo: null,
nineDimensionRadarChart: null, // 九维画像雷达图实例
nineDimensionRadarResizeObserver: null,
nineDimensionRadarRenderTimer: null,
regAddress: {
lazy: true,
lazyLoad(node, resolve) {
@@ -1403,13 +1594,40 @@ export default {
this.managerOptions = []
this.authUser = ''
}
},
ent9vPortrait: {
handler(newVal) {
if (!newVal) {
this.destroyNineDimensionRadar()
return
}
this.scheduleNineDimensionRadarRender()
},
deep: true
}
},
components: {
Custom
},
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() {
return this.roles.includes('headAdmin')
},
@@ -1443,6 +1661,12 @@ export default {
// 海宁
is875() {
return this.userName.slice(0, 3) === '875'
},
is825() {
return String(this.deptId || '').substring(0, 3) === '825'
},
is932Dept() {
return String(this.deptId || '').substring(0, 3) === '932'
}
},
created() {
@@ -1464,6 +1688,16 @@ export default {
// systemUserAllTreeUser().then(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: {
handleAddTag(){
@@ -1591,6 +1825,9 @@ export default {
this.showTagsList=this.tagsList[0].children[0].children||[];
}
this.tagManualList = cloneDeep(res.data.tagManual) || []
// 企业九维数据
this.ent9vPortrait = res.data.ent9vPortrait || null
this.nineVFinalInfo = res.data.nineVFinalInfo || null
}
})
},
@@ -2014,6 +2251,381 @@ export default {
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>
@@ -2405,4 +3017,210 @@ export default {
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>

View File

@@ -364,7 +364,7 @@
v-if="item.cmpmType == '贷款客户经理'"
:label="`${item.cmpmType}`"
>
<span>{{ item.cmpmUserList }}</span>
<span>{{ is932Dept ? `${profile.belongUserName}-${profile.belongUserId}` : item.cmpmUserList }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -1663,7 +1663,7 @@ export default {
CustContact
},
computed: {
...mapGetters(['roles', 'userName']),
...mapGetters(['roles', 'userName', 'deptId']),
isHeadAdmin() {
return this.roles.includes('headAdmin')
},
@@ -1675,6 +1675,10 @@ export default {
isPrivate() {
return this.roles.includes('headPrivate')
},
// 是否932开头部门
is932Dept() {
return String(this.deptId || '').substring(0, 3) === '932'
},
// 运管部
isHeadOps() {
return this.roles.includes('headOps')

View File

@@ -142,6 +142,29 @@
<el-dropdown-item @click.native="handleExportAll">导出前1000条<i class="quesiton"></i></el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template v-if="selectedTab === '2' && canSeeBusinessImport">
<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>
</div>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="searchColoumns"
@@ -180,7 +203,16 @@
</div>
</template>
<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 GroupCheckMore from './components/group-check-more'
import UploadTag from './components/uploadTag.vue'
@@ -288,6 +320,8 @@ export default {
showMoreIndc: true,
contiKeys: [],
iscollapsed: false,
businessImportLoading: false,
businessImportTimer: null,
}
},
watch: {
@@ -333,6 +367,9 @@ export default {
}
return this.tableData
},
isHeadAdmin() {
return this.roles.includes('headAdmin')
},
isPublic() {
return this.roles.includes('headPublic')
},
@@ -342,6 +379,12 @@ export default {
isOps() {
return this.roles.includes('headOps')
},
is825() {
return String(this.deptId || '').substring(0, 3) === '825'
},
canSeeBusinessImport() {
return this.is825 && (this.isHeadAdmin || this.isPublic || this.isPrivate || this.isOps)
},
// 客户经理
isCommonManager() {
return this.roles.includes('commonManager')
@@ -780,6 +823,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() {
const { query } = this.$route;
@@ -800,6 +900,9 @@ export default {
this.initGetSecondRegionList()
this.initgetDrawList()
this.initGetVirtualList()
},
beforeDestroy() {
this.clearBusinessImportTimer()
}
}
</script>
@@ -1062,6 +1165,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 {
width: 100%;
height: 500px;

View File

@@ -112,6 +112,7 @@ import { Message } from "element-ui";
import {
privateTotalColumns, publicTotalColumns,
privateTotalColumnsNew825,
privateTotalColumnsNm, publicTotalColumnsNm,
privateTotalColumnsMap, publicTotalColumnsMap,
privateTotalColumnsAll, publicTotalColumnsAll,
@@ -163,7 +164,7 @@ export default {
},
computed: {
...mapGetters(["roles"]),
...mapGetters(["roles", "deptId"]),
//对公
isPublic() {
return this.roles.includes("headPublic");
@@ -172,6 +173,9 @@ export default {
isPrivate() {
return this.roles.includes("headPrivate");
},
isRetailNew825Tenant() {
return String(this.deptId || '').slice(0, 3) === '825';
},
},
created() {
const {
@@ -196,7 +200,7 @@ export default {
this.shapeName = shapeName;
this.shapeId = shapeId;
if (type == '1') {
this.tableColumns = this.isActive1 ? privateTotalColumns : this.isActive3 ?
this.tableColumns = this.isActive1 ? (this.isRetailNew825Tenant ? privateTotalColumnsNew825 : privateTotalColumns) : this.isActive3 ?
privateTotalColumnsNm : this.isActive4 ? privateTotalColumnsMap : privateTotalColumnsAll;
}
if (type == '2') {

Some files were not shown because too many files have changed in this diff Show More