1
This commit is contained in:
parent
9fd56c5745
commit
fb0d8cde1e
@ -4,8 +4,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.ruoyi.cus.vo.CusMainVO;
|
||||||
|
import com.ruoyi.utils.CodeGenerator;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -38,7 +43,36 @@ public class CusMainController extends BaseController
|
|||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
private ICusMainService cusMainService;
|
private ICusMainService cusMainService;
|
||||||
|
@Autowired
|
||||||
|
private CodeGenerator codeGenerator;
|
||||||
|
/**
|
||||||
|
* 生成客户编码
|
||||||
|
*/
|
||||||
|
@GetMapping("/generateCode")
|
||||||
|
public AjaxResult generateCustomerCode() {
|
||||||
|
try {
|
||||||
|
String code = codeGenerator.generate();
|
||||||
|
return AjaxResult.success("编码生成成功", code);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return AjaxResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验编码是否重复
|
||||||
|
*/
|
||||||
|
@GetMapping("/checkCode")
|
||||||
|
public AjaxResult checkCode(String code) {
|
||||||
|
try {
|
||||||
|
LambdaQueryWrapper<CusMain> queryWrapper = new LambdaQueryWrapper<CusMain>().eq(CusMain::getCusCode, code);
|
||||||
|
if (cusMainService.count(queryWrapper) > 0) {
|
||||||
|
return AjaxResult.error("编码重复");
|
||||||
|
}
|
||||||
|
return success();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return AjaxResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 查询客户信息列表
|
* 查询客户信息列表
|
||||||
*/
|
*/
|
||||||
@ -82,9 +116,9 @@ public class CusMainController extends BaseController
|
|||||||
@PreAuthorize("@ss.hasPermi('cus:main:add')")
|
@PreAuthorize("@ss.hasPermi('cus:main:add')")
|
||||||
@Log(title = "客户信息", businessType = BusinessType.INSERT)
|
@Log(title = "客户信息", businessType = BusinessType.INSERT)
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public AjaxResult add(@RequestBody CusMain cusMain)
|
public AjaxResult add(@RequestBody CusMainVO cusMainVO){
|
||||||
{
|
cusMainService.saveNewCus(cusMainVO);
|
||||||
return toAjax(cusMainService.save(cusMain));
|
return success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -66,14 +66,5 @@ public class CusBank extends DlBaseEntity
|
|||||||
@Excel(name = "税号")
|
@Excel(name = "税号")
|
||||||
private String taxId;
|
private String taxId;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,14 +50,5 @@ public class CusCompany extends DlBaseEntity
|
|||||||
@Excel(name = "联系地址")
|
@Excel(name = "联系地址")
|
||||||
private String contactAddress;
|
private String contactAddress;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,6 @@ public class CusContacts extends DlBaseEntity
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** 主键(使用雪花算法生成唯一主键) */
|
/** 主键(使用雪花算法生成唯一主键) */
|
||||||
@TableId(type = IdType.ASSIGN_UUID)
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/** 客户ID */
|
/** 客户ID */
|
||||||
@ -79,14 +78,5 @@ public class CusContacts extends DlBaseEntity
|
|||||||
@Excel(name = "是否默认联系人")
|
@Excel(name = "是否默认联系人")
|
||||||
private Boolean ifDefault;
|
private Boolean ifDefault;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,14 +70,6 @@ public class CusEmail extends DlBaseEntity
|
|||||||
@Excel(name = "是否已读")
|
@Excel(name = "是否已读")
|
||||||
private Integer ifRead;
|
private Integer ifRead;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,14 +122,5 @@ public class CusFollow extends DlBaseEntity
|
|||||||
@Excel(name = "是否完成")
|
@Excel(name = "是否完成")
|
||||||
private Integer ifCompleted;
|
private Integer ifCompleted;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,12 +74,4 @@ public class CusMain extends DlBaseEntity
|
|||||||
/** 附件 */
|
/** 附件 */
|
||||||
private String files;
|
private String files;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,14 +54,5 @@ public class CusManager extends DlBaseEntity
|
|||||||
@Excel(name = "原部门")
|
@Excel(name = "原部门")
|
||||||
private String oldDept;
|
private String oldDept;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,14 +46,5 @@ public class CusMark extends DlBaseEntity
|
|||||||
@Excel(name = "图形文件路径")
|
@Excel(name = "图形文件路径")
|
||||||
private String imageUrl;
|
private String imageUrl;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,14 +54,5 @@ public class CusTimeAxis extends DlBaseEntity
|
|||||||
@Excel(name = "备注")
|
@Excel(name = "备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
/** 创建时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date createdTime;
|
|
||||||
|
|
||||||
/** 更新时间 */
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
|
||||||
@Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd")
|
|
||||||
private Date updatedTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.ruoyi.cus.domain.CusMain;
|
import com.ruoyi.cus.domain.CusMain;
|
||||||
|
import com.ruoyi.cus.vo.CusMainVO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户信息Service接口
|
* 客户信息Service接口
|
||||||
@ -15,4 +16,12 @@ import com.ruoyi.cus.domain.CusMain;
|
|||||||
public interface ICusMainService extends IService<CusMain>
|
public interface ICusMainService extends IService<CusMain>
|
||||||
{
|
{
|
||||||
IPage<CusMain> queryListPage(CusMain pageReqVO, Page<CusMain> page);
|
IPage<CusMain> queryListPage(CusMain pageReqVO, Page<CusMain> page);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增客户信息
|
||||||
|
* @author vinjor-M
|
||||||
|
* @date 15:56 2025/11/6
|
||||||
|
* @param cusMainVO TODO
|
||||||
|
**/
|
||||||
|
void saveNewCus(CusMainVO cusMainVO);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,12 +3,15 @@ package com.ruoyi.cus.service.impl;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.ruoyi.cus.domain.*;
|
||||||
|
import com.ruoyi.cus.mapper.*;
|
||||||
|
import com.ruoyi.cus.service.*;
|
||||||
|
import com.ruoyi.cus.vo.CusMainVO;
|
||||||
|
import com.ruoyi.utils.SnowflakeIdGenerator;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.ruoyi.cus.mapper.CusMainMapper;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import com.ruoyi.cus.domain.CusMain;
|
|
||||||
import com.ruoyi.cus.service.ICusMainService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户信息Service业务层处理
|
* 客户信息Service业务层处理
|
||||||
@ -21,9 +24,62 @@ public class CusMainServiceImpl extends ServiceImpl<CusMainMapper,CusMain> impl
|
|||||||
{
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
private CusMainMapper cusMainMapper;
|
private CusMainMapper cusMainMapper;
|
||||||
|
@Autowired
|
||||||
|
private SnowflakeIdGenerator snowflakeIdGenerator;
|
||||||
|
@Autowired
|
||||||
|
private ICusContactsService cusContactsService;
|
||||||
|
@Autowired
|
||||||
|
private ICusManagerService cusManagerService;
|
||||||
|
@Autowired
|
||||||
|
private ICusCompanyService cusCompanyService;
|
||||||
|
@Autowired
|
||||||
|
private ICusBankService cusBankService;
|
||||||
|
@Autowired
|
||||||
|
private ICusMarkService cusMarkService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IPage<CusMain> queryListPage(CusMain pageReqVO, Page<CusMain> page) {
|
public IPage<CusMain> queryListPage(CusMain pageReqVO, Page<CusMain> page) {
|
||||||
return cusMainMapper.queryListPage(pageReqVO, page);
|
return cusMainMapper.queryListPage(pageReqVO, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增客户信息
|
||||||
|
*
|
||||||
|
* @param cusMainVO TODO
|
||||||
|
* @author vinjor-M
|
||||||
|
* @date 15:56 2025/11/6
|
||||||
|
**/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void saveNewCus(CusMainVO cusMainVO) {
|
||||||
|
CusMain cusMain = cusMainVO.getMainInfo();
|
||||||
|
cusMainMapper.insert(cusMain);
|
||||||
|
//联系人信息
|
||||||
|
List<CusContacts> contacts = cusMainVO.getContact();
|
||||||
|
for (CusContacts contact : contacts) {
|
||||||
|
contact.setId(snowflakeIdGenerator.generateId());
|
||||||
|
contact.setCusId(cusMain.getId());
|
||||||
|
}
|
||||||
|
cusContactsService.saveBatch(contacts);
|
||||||
|
//公司信息
|
||||||
|
CusCompany cusCompany = cusMainVO.getCompanyInfo();
|
||||||
|
cusCompany.setCusId(cusMain.getId());
|
||||||
|
cusCompanyService.save(cusCompany);
|
||||||
|
//管理信息
|
||||||
|
CusManager cusManager = cusMainVO.getManagementInfo();
|
||||||
|
cusManager.setCusId(cusMain.getId());
|
||||||
|
cusManagerService.save(cusManager);
|
||||||
|
//银行信息
|
||||||
|
List<CusBank> bankList = cusMainVO.getBankInfo();
|
||||||
|
if(!bankList.isEmpty()){
|
||||||
|
bankList.forEach(bank -> bank.setCusId(cusMain.getId()));
|
||||||
|
cusBankService.saveBatch(bankList);
|
||||||
|
}
|
||||||
|
//唛头信息
|
||||||
|
List<CusMark> markList = cusMainVO.getMark();
|
||||||
|
if(!markList.isEmpty()){
|
||||||
|
markList.forEach(mark -> mark.setCusId(cusMain.getId()));
|
||||||
|
cusMarkService.saveBatch(markList);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package com.ruoyi.cus.vo;
|
||||||
|
|
||||||
|
import com.ruoyi.cus.domain.*;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CusMainVO {
|
||||||
|
/** 客户信息 */
|
||||||
|
private CusMain mainInfo;
|
||||||
|
/** 联系人信息 */
|
||||||
|
private List<CusContacts> contact;
|
||||||
|
/** 公司信息 */
|
||||||
|
private CusCompany companyInfo;
|
||||||
|
/** 管理信息 */
|
||||||
|
private CusManager managementInfo;
|
||||||
|
/** 银行信息 */
|
||||||
|
private List<CusBank> bankInfo;
|
||||||
|
/** 唛头信息 */
|
||||||
|
private List<CusMark> mark;
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package com.ruoyi.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DatePattern;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码生成工具
|
||||||
|
* @author vinjor-M
|
||||||
|
* @date 15:31 2025/11/6
|
||||||
|
**/
|
||||||
|
@Component
|
||||||
|
public class CodeGenerator {
|
||||||
|
/**
|
||||||
|
* Redis键前缀(存储每日自增序号)
|
||||||
|
*/
|
||||||
|
private static final String REDIS_KEY_PREFIX = "customer:code:seq:";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码前缀
|
||||||
|
*/
|
||||||
|
private static final String CODE_PREFIX = "CD";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自增序号位数(不足补0)
|
||||||
|
*/
|
||||||
|
private static final int SEQ_LENGTH = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每日最大序号(3位最大为999)
|
||||||
|
*/
|
||||||
|
private static final long MAX_SEQ = 999L;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成客户编码
|
||||||
|
* @return 格式:CD+年月日+3位自增数
|
||||||
|
*/
|
||||||
|
public String generate() {
|
||||||
|
// 1. 获取当天日期字符串(yyyyMMdd)
|
||||||
|
String dateStr = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
|
||||||
|
|
||||||
|
// 2. 构建Redis键(每日一个独立键,实现序号日重置)
|
||||||
|
String redisKey = REDIS_KEY_PREFIX + dateStr;
|
||||||
|
|
||||||
|
// 3. Redis原子自增(保证并发安全)
|
||||||
|
Long seq = redisTemplate.opsForValue().increment(redisKey, 1);
|
||||||
|
|
||||||
|
// 4. 校验序号是否超出最大值
|
||||||
|
if (seq == null || seq > MAX_SEQ) {
|
||||||
|
throw new RuntimeException("今日客户编码已达上限(999个),请明日再试");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 序号补零(不足3位前面补0)
|
||||||
|
String seqStr = String.format("%0" + SEQ_LENGTH + "d", seq);
|
||||||
|
|
||||||
|
// 6. 拼接最终编码
|
||||||
|
return CODE_PREFIX + dateStr + seqStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,172 @@
|
|||||||
|
package com.ruoyi.utils;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 雪花算法ID生成器(适配RuoYi框架,支持16表分表)
|
||||||
|
* 分表逻辑:ID % 16 → 0-15,对应16个分表
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SnowflakeIdGenerator implements InitializingBean {
|
||||||
|
/**
|
||||||
|
* 起始时间戳(2025-01-01 00:00:00,可自定义)
|
||||||
|
*/
|
||||||
|
private static final long START_TIMESTAMP = 1735689600000L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据中心ID位数(5位,支持0-31)
|
||||||
|
*/
|
||||||
|
private static final int DATA_CENTER_ID_BITS = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器ID位数(5位,支持0-31)
|
||||||
|
*/
|
||||||
|
private static final int MACHINE_ID_BITS = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列号位数(12位,支持0-4095)
|
||||||
|
*/
|
||||||
|
private static final int SEQUENCE_BITS = 12;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大数据中心ID(31)
|
||||||
|
*/
|
||||||
|
private static final long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大机器ID(31)
|
||||||
|
*/
|
||||||
|
private static final long MAX_MACHINE_ID = ~(-1L << MACHINE_ID_BITS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列号掩码(4095)
|
||||||
|
*/
|
||||||
|
private static final long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器ID左移位数(12位)
|
||||||
|
*/
|
||||||
|
private static final int MACHINE_ID_SHIFT = SEQUENCE_BITS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据中心ID左移位数(12+5=17位)
|
||||||
|
*/
|
||||||
|
private static final int DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳左移位数(12+5+5=22位)
|
||||||
|
*/
|
||||||
|
private static final int TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + MACHINE_ID_BITS + DATA_CENTER_ID_BITS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据中心ID(从配置文件读取)
|
||||||
|
*/
|
||||||
|
@Value("${snowflake.data-center-id:0}")
|
||||||
|
private long dataCenterId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 机器ID(从配置文件读取,分布式部署时需唯一)
|
||||||
|
*/
|
||||||
|
@Value("${snowflake.machine-id:0}")
|
||||||
|
private long machineId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上次生成ID的时间戳
|
||||||
|
*/
|
||||||
|
private volatile long lastTimestamp = -1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 序列号(原子类保证线程安全)
|
||||||
|
*/
|
||||||
|
private final AtomicLong sequence = new AtomicLong(0L);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化校验:机器ID和数据中心ID不能超出最大值
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
|
||||||
|
throw new IllegalArgumentException(String.format("数据中心ID必须在0-%d之间", MAX_DATA_CENTER_ID));
|
||||||
|
}
|
||||||
|
if (machineId > MAX_MACHINE_ID || machineId < 0) {
|
||||||
|
throw new IllegalArgumentException(String.format("机器ID必须在0-%d之间", MAX_MACHINE_ID));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成雪花算法ID(Long类型)
|
||||||
|
*/
|
||||||
|
public synchronized long generateId() {
|
||||||
|
long currentTimestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// 处理时钟回拨(避免ID重复)
|
||||||
|
if (currentTimestamp < lastTimestamp) {
|
||||||
|
throw new RuntimeException(String.format("时钟回拨异常!当前时间戳:%d,上次时间戳:%d", currentTimestamp, lastTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同一时间戳内,序列号自增
|
||||||
|
if (currentTimestamp == lastTimestamp) {
|
||||||
|
sequence.set((sequence.get() + 1) & SEQUENCE_MASK);
|
||||||
|
// 序列号用尽,等待下一毫秒
|
||||||
|
if (sequence.get() == 0) {
|
||||||
|
currentTimestamp = waitNextMillis(lastTimestamp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 新的时间戳,序列号重置为0
|
||||||
|
sequence.set(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新上次生成ID的时间戳
|
||||||
|
lastTimestamp = currentTimestamp;
|
||||||
|
|
||||||
|
// 拼接64位ID:时间戳左移22位 + 数据中心ID左移17位 + 机器ID左移12位 + 序列号
|
||||||
|
return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_LEFT_SHIFT)
|
||||||
|
| (dataCenterId << DATA_CENTER_ID_SHIFT)
|
||||||
|
| (machineId << MACHINE_ID_SHIFT)
|
||||||
|
| sequence.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待下一毫秒(避免序列号用尽)
|
||||||
|
*/
|
||||||
|
private long waitNextMillis(long lastTimestamp) {
|
||||||
|
long currentTimestamp = System.currentTimeMillis();
|
||||||
|
while (currentTimestamp <= lastTimestamp) {
|
||||||
|
currentTimestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
return currentTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成ID(String类型,避免前端Long精度丢失)
|
||||||
|
*/
|
||||||
|
public String generateIdStr() {
|
||||||
|
return String.valueOf(generateId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID获取分表索引(0-15),用于16表分表
|
||||||
|
* @param id 雪花算法生成的ID
|
||||||
|
* @return 分表索引(0-15)
|
||||||
|
*/
|
||||||
|
public int getTableIndex(Long id) {
|
||||||
|
if (id == null) {
|
||||||
|
throw new IllegalArgumentException("ID不能为空");
|
||||||
|
}
|
||||||
|
// 取序列号部分(低12位),再取模16(保证均匀分布到16个表)
|
||||||
|
return (int) (id & 0xF); // 0xF = 15,等价于 id % 16
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重载:支持String类型ID
|
||||||
|
*/
|
||||||
|
public int getTableIndex(String idStr) {
|
||||||
|
if (idStr == null || idStr.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("ID字符串不能为空");
|
||||||
|
}
|
||||||
|
return getTableIndex(Long.parseLong(idStr));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -153,32 +153,16 @@ aliyun:
|
|||||||
access-key-id: LTAI5tLThQFWgMLRTf3siNjb
|
access-key-id: LTAI5tLThQFWgMLRTf3siNjb
|
||||||
access-key-secret: M5HjOyB8ir5tYEPFOQwImfJNgsumaG
|
access-key-secret: M5HjOyB8ir5tYEPFOQwImfJNgsumaG
|
||||||
bucket-name: dianliang123
|
bucket-name: dianliang123
|
||||||
# Dify API 配置
|
|
||||||
dify:
|
|
||||||
api:
|
|
||||||
key: app-tRfIOnRtIb5fTeXRcJ46aWVh
|
|
||||||
url: https://api.dify.ai/v1
|
|
||||||
#dify:
|
|
||||||
# api:
|
|
||||||
# key: app-ahgDwrLi8KQ6V0aEKKwT6Io7
|
|
||||||
# url: http://10.19.128.77/v1
|
|
||||||
|
|
||||||
# 登录相关配置
|
# 登录相关配置
|
||||||
login:
|
login:
|
||||||
# 是否限制单用户登录
|
# 是否限制单用户登录
|
||||||
single: true
|
single: true
|
||||||
|
|
||||||
|
# 雪花算法配置
|
||||||
# Python环境配置
|
snowflake:
|
||||||
python:
|
data-center-id: 0 # 数据中心ID(0-31),多数据中心部署时区分
|
||||||
# Python可执行文件路径
|
machine-id: 0 # 机器ID(0-31),同一数据中心内机器唯一(分布式部署必填不同值)
|
||||||
path: python3
|
|
||||||
# 脚本超时时间(分钟)
|
|
||||||
timeoutMinutes: 30
|
|
||||||
# 脚本
|
|
||||||
scripts:
|
|
||||||
# 信通院爬虫脚本
|
|
||||||
caict: /Users/menfutong/workspace/myproject/design-spider/dl_industry_ai/dl_admin/python_scripts/busi_caict_spider.py
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -17,13 +17,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="taxId" column="tax_id" />
|
<result property="taxId" column="tax_id" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusBankVo">
|
<sql id="selectCusBankVo">
|
||||||
select id, cus_id, bank_account, bank_name, currency, bank_code, swift_code, bank_address, branch_code, tax_id, del_flag, creator, created_time, updater, updated_time from cus_bank
|
select id, cus_id, bank_account, bank_name, currency, bank_code, swift_code, bank_address, branch_code, tax_id, del_flag, creator, create_time, updater, update_time from cus_bank
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusBank" resultMap="CusBankResult">
|
<select id="queryListPage" parameterType="CusBank" resultMap="CusBankResult">
|
||||||
@ -38,8 +38,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.bankAddress != null and entity.bankAddress != ''"> and bank_address = #{entity.bankAddress}</if>
|
<if test="entity.bankAddress != null and entity.bankAddress != ''"> and bank_address = #{entity.bankAddress}</if>
|
||||||
<if test="entity.branchCode != null and entity.branchCode != ''"> and branch_code = #{entity.branchCode}</if>
|
<if test="entity.branchCode != null and entity.branchCode != ''"> and branch_code = #{entity.branchCode}</if>
|
||||||
<if test="entity.taxId != null and entity.taxId != ''"> and tax_id = #{entity.taxId}</if>
|
<if test="entity.taxId != null and entity.taxId != ''"> and tax_id = #{entity.taxId}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -13,13 +13,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="contactAddress" column="contact_address" />
|
<result property="contactAddress" column="contact_address" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusCompanyVo">
|
<sql id="selectCusCompanyVo">
|
||||||
select id, cus_id, cus_from, cus_level, busi_type, contact_address, del_flag, creator, created_time, updater, updated_time from cus_company
|
select id, cus_id, cus_from, cus_level, busi_type, contact_address, del_flag, creator, create_time, updater, update_time from cus_company
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusCompany" resultMap="CusCompanyResult">
|
<select id="queryListPage" parameterType="CusCompany" resultMap="CusCompanyResult">
|
||||||
@ -30,8 +30,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.cusLevel != null and entity.cusLevel != ''"> and cus_level = #{entity.cusLevel}</if>
|
<if test="entity.cusLevel != null and entity.cusLevel != ''"> and cus_level = #{entity.cusLevel}</if>
|
||||||
<if test="entity.busiType != null and entity.busiType != ''"> and busi_type = #{entity.busiType}</if>
|
<if test="entity.busiType != null and entity.busiType != ''"> and busi_type = #{entity.busiType}</if>
|
||||||
<if test="entity.contactAddress != null and entity.contactAddress != ''"> and contact_address = #{entity.contactAddress}</if>
|
<if test="entity.contactAddress != null and entity.contactAddress != ''"> and contact_address = #{entity.contactAddress}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -19,13 +19,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="qq" column="qq" />
|
<result property="qq" column="qq" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusContactsVo">
|
<sql id="selectCusContactsVo">
|
||||||
select id, cus_id, name, nick_name, sex, birthday, email, contact_address, telephone, whats_app, wechat, qq, del_flag, creator, created_time, updater, updated_time from cus_contacts
|
select id, cus_id, name, nick_name, sex, birthday, email, contact_address, telephone, whats_app, wechat, qq, del_flag, creator, create_time, updater, update_time from cus_contacts
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusContacts" resultMap="CusContactsResult">
|
<select id="queryListPage" parameterType="CusContacts" resultMap="CusContactsResult">
|
||||||
@ -42,8 +42,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.whatsApp != null and entity.whatsApp != ''"> and whats_app = #{entity.whatsApp}</if>
|
<if test="entity.whatsApp != null and entity.whatsApp != ''"> and whats_app = #{entity.whatsApp}</if>
|
||||||
<if test="entity.wechat != null and entity.wechat != ''"> and wechat = #{entity.wechat}</if>
|
<if test="entity.wechat != null and entity.wechat != ''"> and wechat = #{entity.wechat}</if>
|
||||||
<if test="entity.qq != null and entity.qq != ''"> and qq = #{entity.qq}</if>
|
<if test="entity.qq != null and entity.qq != ''"> and qq = #{entity.qq}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -18,13 +18,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="ifRead" column="if_read" />
|
<result property="ifRead" column="if_read" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusEmailVo">
|
<sql id="selectCusEmailVo">
|
||||||
select id, cus_id, contact_id, sender, receiver, send_type, subject, content, files, if_star, if_read, del_flag, creator, created_time, updater, updated_time from cus_email
|
select id, cus_id, contact_id, sender, receiver, send_type, subject, content, files, if_star, if_read, del_flag, creator, create_time, updater, update_time from cus_email
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusEmail" resultMap="CusEmailResult">
|
<select id="queryListPage" parameterType="CusEmail" resultMap="CusEmailResult">
|
||||||
@ -40,8 +40,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.files != null and entity.files != ''"> and files = #{entity.files}</if>
|
<if test="entity.files != null and entity.files != ''"> and files = #{entity.files}</if>
|
||||||
<if test="entity.ifStar != null "> and if_star = #{entity.ifStar}</if>
|
<if test="entity.ifStar != null "> and if_star = #{entity.ifStar}</if>
|
||||||
<if test="entity.ifRead != null "> and if_read = #{entity.ifRead}</if>
|
<if test="entity.ifRead != null "> and if_read = #{entity.ifRead}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -30,13 +30,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="ifCompleted" column="if_completed" />
|
<result property="ifCompleted" column="if_completed" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusFollowVo">
|
<sql id="selectCusFollowVo">
|
||||||
select id, cus_id, contact_id, follow_type, follow_content, follow_time, schedule_color, files, follow_way, follow_step, if_sync_cus, again_time, if_always_remind, cycle_type, cycle_other_type, cycle_other_value, cycle_start, cycle_end, busi_name, busi_id, user_id, other_user_ids, if_completed, del_flag, creator, created_time, updater, updated_time from cus_follow
|
select id, cus_id, contact_id, follow_type, follow_content, follow_time, schedule_color, files, follow_way, follow_step, if_sync_cus, again_time, if_always_remind, cycle_type, cycle_other_type, cycle_other_value, cycle_start, cycle_end, busi_name, busi_id, user_id, other_user_ids, if_completed, del_flag, creator, create_time, updater, update_time from cus_follow
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusFollow" resultMap="CusFollowResult">
|
<select id="queryListPage" parameterType="CusFollow" resultMap="CusFollowResult">
|
||||||
@ -64,8 +64,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.userId != null "> and user_id = #{entity.userId}</if>
|
<if test="entity.userId != null "> and user_id = #{entity.userId}</if>
|
||||||
<if test="entity.otherUserIds != null and entity.otherUserIds != ''"> and other_user_ids = #{entity.otherUserIds}</if>
|
<if test="entity.otherUserIds != null and entity.otherUserIds != ''"> and other_user_ids = #{entity.otherUserIds}</if>
|
||||||
<if test="entity.ifCompleted != null "> and if_completed = #{entity.ifCompleted}</if>
|
<if test="entity.ifCompleted != null "> and if_completed = #{entity.ifCompleted}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -19,13 +19,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="files" column="files" />
|
<result property="files" column="files" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusMainVo">
|
<sql id="selectCusMainVo">
|
||||||
select id, cus_labels, cus_code, full_name, short_name, cus_type, country, zone_name, main_prods, site_url, remark, files, del_flag, creator, created_time, updater, updated_time from cus_main
|
select id, cus_labels, cus_code, full_name, short_name, cus_type, country, zone_name, main_prods, site_url, remark, files, del_flag, creator, create_time, updater, update_time from cus_main
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusMain" resultMap="CusMainResult">
|
<select id="queryListPage" parameterType="CusMain" resultMap="CusMainResult">
|
||||||
|
|||||||
@ -14,13 +14,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="oldDept" column="old_dept" />
|
<result property="oldDept" column="old_dept" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusManagerVo">
|
<sql id="selectCusManagerVo">
|
||||||
select id, cus_id, user_id, follow_step, seas_reason, seas_group, old_dept, del_flag, creator, created_time, updater, updated_time from cus_manager
|
select id, cus_id, user_id, follow_step, seas_reason, seas_group, old_dept, del_flag, creator, create_time, updater, update_time from cus_manager
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusManager" resultMap="CusManagerResult">
|
<select id="queryListPage" parameterType="CusManager" resultMap="CusManagerResult">
|
||||||
@ -32,8 +32,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.seasReason != null and entity.seasReason != ''"> and seas_reason = #{entity.seasReason}</if>
|
<if test="entity.seasReason != null and entity.seasReason != ''"> and seas_reason = #{entity.seasReason}</if>
|
||||||
<if test="entity.seasGroup != null and entity.seasGroup != ''"> and seas_group = #{entity.seasGroup}</if>
|
<if test="entity.seasGroup != null and entity.seasGroup != ''"> and seas_group = #{entity.seasGroup}</if>
|
||||||
<if test="entity.oldDept != null and entity.oldDept != ''"> and old_dept = #{entity.oldDept}</if>
|
<if test="entity.oldDept != null and entity.oldDept != ''"> and old_dept = #{entity.oldDept}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -12,13 +12,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="imageUrl" column="image_url" />
|
<result property="imageUrl" column="image_url" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusMarkVo">
|
<sql id="selectCusMarkVo">
|
||||||
select id, cus_id, mark_position, text_content, image_url, del_flag, creator, created_time, updater, updated_time from cus_mark
|
select id, cus_id, mark_position, text_content, image_url, del_flag, creator, create_time, updater, update_time from cus_mark
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusMark" resultMap="CusMarkResult">
|
<select id="queryListPage" parameterType="CusMark" resultMap="CusMarkResult">
|
||||||
@ -28,8 +28,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.markPosition != null and entity.markPosition != ''"> and mark_position = #{entity.markPosition}</if>
|
<if test="entity.markPosition != null and entity.markPosition != ''"> and mark_position = #{entity.markPosition}</if>
|
||||||
<if test="entity.textContent != null and entity.textContent != ''"> and text_content = #{entity.textContent}</if>
|
<if test="entity.textContent != null and entity.textContent != ''"> and text_content = #{entity.textContent}</if>
|
||||||
<if test="entity.imageUrl != null and entity.imageUrl != ''"> and image_url = #{entity.imageUrl}</if>
|
<if test="entity.imageUrl != null and entity.imageUrl != ''"> and image_url = #{entity.imageUrl}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -14,13 +14,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="remark" column="remark" />
|
<result property="remark" column="remark" />
|
||||||
<result property="delFlag" column="del_flag" />
|
<result property="delFlag" column="del_flag" />
|
||||||
<result property="creator" column="creator" />
|
<result property="creator" column="creator" />
|
||||||
<result property="createdTime" column="created_time" />
|
<result property="createTime" column="create_time" />
|
||||||
<result property="updater" column="updater" />
|
<result property="updater" column="updater" />
|
||||||
<result property="updatedTime" column="updated_time" />
|
<result property="updateTime" column="update_time" />
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectCusTimeAxisVo">
|
<sql id="selectCusTimeAxisVo">
|
||||||
select id, cus_code, busi_max_catg, busi_catg, contact_id, content, remark, del_flag, creator, created_time, updater, updated_time from cus_time_axis
|
select id, cus_code, busi_max_catg, busi_catg, contact_id, content, remark, del_flag, creator, create_time, updater, update_time from cus_time_axis
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="queryListPage" parameterType="CusTimeAxis" resultMap="CusTimeAxisResult">
|
<select id="queryListPage" parameterType="CusTimeAxis" resultMap="CusTimeAxisResult">
|
||||||
@ -32,8 +32,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="entity.contactId != null and entity.contactId != ''"> and contact_id = #{entity.contactId}</if>
|
<if test="entity.contactId != null and entity.contactId != ''"> and contact_id = #{entity.contactId}</if>
|
||||||
<if test="entity.content != null and entity.content != ''"> and content = #{entity.content}</if>
|
<if test="entity.content != null and entity.content != ''"> and content = #{entity.content}</if>
|
||||||
<if test="entity.remark != null and entity.remark != ''"> and remark = #{entity.remark}</if>
|
<if test="entity.remark != null and entity.remark != ''"> and remark = #{entity.remark}</if>
|
||||||
<if test="entity.createdTime != null "> and created_time = #{entity.createdTime}</if>
|
<if test="entity.createTime != null "> and create_time = #{entity.createTime}</if>
|
||||||
<if test="entity.updatedTime != null "> and updated_time = #{entity.updatedTime}</if>
|
<if test="entity.updateTime != null "> and update_time = #{entity.updateTime}</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
@ -41,4 +41,12 @@ export default {
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
display: inline-block; /* 确保宽度生效 */
|
display: inline-block; /* 确保宽度生效 */
|
||||||
}
|
}
|
||||||
|
::v-deep .el-drawer__header{
|
||||||
|
margin-bottom: 10px !important;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 轻微阴影,增强层次感 */
|
||||||
|
}
|
||||||
|
::v-deep .el-date-editor{
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取客户编码
|
||||||
|
export function getCode() {
|
||||||
|
return request({
|
||||||
|
url: '/cus/main/generateCode',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 校验编码是否重复
|
||||||
|
export function checkCode(query) {
|
||||||
|
return request({
|
||||||
|
url: '/cus/main/checkCode',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 查询客户信息列表
|
// 查询客户信息列表
|
||||||
export function listMain(query) {
|
export function listMain(query) {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
566
dl_vue/src/views/cus/main/drawForm.vue
Normal file
566
dl_vue/src/views/cus/main/drawForm.vue
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
:title="title"
|
||||||
|
:visible.sync="open"
|
||||||
|
:size="650"
|
||||||
|
direction="rtl"
|
||||||
|
:before-close="cancel">
|
||||||
|
<div class="dl-drawer-box">
|
||||||
|
<el-form ref="form" :model="formData" :rules="rules" label-width="80px">
|
||||||
|
<!-- 1. 主要信息区块 -->
|
||||||
|
<div id="main-info" class="content-section">
|
||||||
|
<div class="section-box">
|
||||||
|
<div class="section-title">主要信息</div>
|
||||||
|
<el-switch
|
||||||
|
v-model="onlyRequired.mainInfo"
|
||||||
|
active-text="只显示必填项"
|
||||||
|
class="required-switch"
|
||||||
|
></el-switch>
|
||||||
|
</div>
|
||||||
|
<!-- 必填项 -->
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="客户名称" prop="fullName" label-width="100px">
|
||||||
|
<el-input v-model="formData.mainInfo.fullName" placeholder="客户名称">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="客户编码" prop="cusCode" label-width="100px">
|
||||||
|
<el-input v-model="formData.mainInfo.cusCode" placeholder="请输入客户编码">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12" v-if="!onlyRequired.mainInfo">
|
||||||
|
<el-form-item label="客户简称" prop="shortName" label-width="100px">
|
||||||
|
<el-input v-model="formData.mainInfo.shortName" placeholder="客户简称">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="客户类型" prop="cusType" label-width="100px">
|
||||||
|
<el-select style="width: 100%" v-model="formData.mainInfo.cusType" filterable placeholder="客户类型" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in dict.type.cus_type"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<!-- 其他非必填项-->
|
||||||
|
<div v-if="!onlyRequired.mainInfo">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="国家/地区" label-width="100px">
|
||||||
|
<el-select style="width: 100%" v-model="formData.mainInfo.country" filterable placeholder="国家/地区" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in countryList"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="时区" label-width="100px">
|
||||||
|
<el-select style="width: 100%" v-model="formData.mainInfo.zoneName" filterable placeholder="时区" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in timeZoneList"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="主营产品" label-width="100px">
|
||||||
|
<!-- collapse-tags-->
|
||||||
|
<el-select style="width: 100%" v-model="formData.mainInfo.mainProds" multiple collapse-tags filterable placeholder="主营产品" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="dict in dict.type.cus_main_product"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.label"
|
||||||
|
:value="dict.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="企业网站" label-width="100px">
|
||||||
|
<el-input v-model="formData.mainInfo.siteUrl" placeholder="企业网站">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="备注" label-width="100px">
|
||||||
|
<el-input type="textarea" v-model="formData.mainInfo.remark" placeholder="备注">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="contact" class="content-section">
|
||||||
|
<div class="section-box">
|
||||||
|
<div class="section-title">联系人<span style="font-weight: normal">({{formData.contact.length}})</span></div>
|
||||||
|
<el-switch
|
||||||
|
v-model="onlyRequired.contact"
|
||||||
|
active-text="只显示必填项"
|
||||||
|
class="required-switch"
|
||||||
|
></el-switch>
|
||||||
|
<div class="section-right">
|
||||||
|
<el-button size="mini" type="primary" icon="el-icon-circle-plus-outline" circle @click="addNewContact"></el-button>
|
||||||
|
<el-button size="mini" type="danger" icon="el-icon-delete" circle @click="delContactBatch"></el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-card class="box-card" v-for="(contact,index) in formData.contact" :class="{'choose-contact':-1!=chooseContactIndexs.indexOf(index)}" style="margin-bottom: 10px">
|
||||||
|
<!-- 左上角多选 -->
|
||||||
|
<div class="dl-checkbox-box">
|
||||||
|
<el-checkbox v-model="-1!=chooseContactIndexs.indexOf(index)" @change="chooseContact($event,index)"></el-checkbox>
|
||||||
|
</div>
|
||||||
|
<!-- 右下角删除 -->
|
||||||
|
<div class="dl-del-box">
|
||||||
|
<i class="el-icon-delete" @click="delContact(index)"></i>
|
||||||
|
</div>
|
||||||
|
<!-- 右上角默认选中 -->
|
||||||
|
<div class="corner-tag" :class="{'corner-tag-default':formData.contact[index].ifDefault,
|
||||||
|
'corner-tag-normal':!formData.contact[index].ifDefault}" @click="chooseDefault(index)">默认</div>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="姓名"
|
||||||
|
:prop="'contact.' + index + '.name'"
|
||||||
|
:rules="[{ required: true, message: '请输入联系人姓名', trigger: 'blur' }]">
|
||||||
|
<el-input v-model="formData.contact[index].name" placeholder="请输入联系人姓名"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12" v-if="!onlyRequired.contact">
|
||||||
|
<el-form-item label="称呼">
|
||||||
|
<el-input v-model="formData.contact[index].nickName" placeholder="请输入联系人称呼"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div v-if="!onlyRequired.contact">
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="性别">
|
||||||
|
<el-radio-group v-model="formData.contact[index].sex">
|
||||||
|
<el-radio
|
||||||
|
v-for="dict in dict.type.sys_user_sex"
|
||||||
|
:key="dict.value"
|
||||||
|
:label="dict.value"
|
||||||
|
>{{dict.label}}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="生日">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="formData.contact[index].birthday"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择生日">
|
||||||
|
</el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系地址">
|
||||||
|
<el-input v-model="formData.contact[index].contactAddress" placeholder="请输入联系地址"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="邮箱">
|
||||||
|
<el-input v-model="formData.contact[index].email" placeholder="请输入邮箱"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row >
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="手机">
|
||||||
|
<el-input v-model="formData.contact[index].telephone" placeholder="请输入手机">
|
||||||
|
<el-select v-model="formData.contact[index].telephonePre" slot="prepend" placeholder="区号">
|
||||||
|
<el-option key="+86" label="+86" value="+86">中国,+86</el-option>
|
||||||
|
<el-option key="+12" label="+12" value="+12">阿拉伯联合酋长国 | THE UNITED ARAB EMIRATES + 971</el-option>
|
||||||
|
<el-option key="+34" label="+34" value="+34">中国,+34</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="WhatsApp">
|
||||||
|
<template #label>
|
||||||
|
<el-tooltip content="WhatsApp" placement="top" effect="dark">
|
||||||
|
<span class="ellipsis-label">WhatsApp</span>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
<el-input v-model="formData.contact[index].whatsApp" placeholder="请输入WhatsApp">
|
||||||
|
<el-select v-model="formData.contact[index].whatsAppPre" slot="prepend" placeholder="区号">
|
||||||
|
<el-option key="+86" label="+86" value="+86">中国,+86</el-option>
|
||||||
|
<el-option key="+12" label="+12" value="+12">阿拉伯联合酋长国 | THE UNITED ARAB EMIRATES + 971</el-option>
|
||||||
|
<el-option key="+34" label="+34" value="+34">中国,+34</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="微信">
|
||||||
|
<el-input v-model="formData.contact[index].wechat" placeholder="请输入微信"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="QQ">
|
||||||
|
<el-input v-model="formData.contact[index].qq" placeholder="请输入QQ"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
<el-empty v-if="formData.contact.length==0" description="暂无数据"></el-empty>
|
||||||
|
</div>
|
||||||
|
<!-- 7. 附件区块 -->
|
||||||
|
<div id="attachment" class="content-section">
|
||||||
|
<div class="section-box">
|
||||||
|
<div class="section-title">附件</div>
|
||||||
|
</div>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="附件">
|
||||||
|
<file-upload v-model="formData.files"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
<div class="dl-drawer-footer">
|
||||||
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getCode, addMain } from "@/api/cus/main";
|
||||||
|
export default {
|
||||||
|
name: 'drawForm',
|
||||||
|
dicts: ['cus_main_product', 'cus_label', 'cus_type','sys_user_sex','cus_from','cus_level','cus_busi_type','cus_follow_step'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 弹出层标题
|
||||||
|
title: "快速新建客户",
|
||||||
|
// 是否显示弹出层
|
||||||
|
open: false,
|
||||||
|
//当前选中的联系人索引
|
||||||
|
chooseContactIndexs: [],
|
||||||
|
// 只显示必填项开关状态
|
||||||
|
onlyRequired: {
|
||||||
|
mainInfo: false,
|
||||||
|
contact: false,
|
||||||
|
},
|
||||||
|
// 表单参数
|
||||||
|
formData: {
|
||||||
|
mainInfo: {
|
||||||
|
cusCode: '',
|
||||||
|
fullName: '',
|
||||||
|
cusType: '',
|
||||||
|
country: '',
|
||||||
|
shortName: '',
|
||||||
|
zoneName: '',
|
||||||
|
mainProds: "",
|
||||||
|
siteUrl: '',
|
||||||
|
remark: "",
|
||||||
|
files: ""
|
||||||
|
},
|
||||||
|
contact: [
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
ifDefault: true,
|
||||||
|
nickName: '',
|
||||||
|
sex: '1',
|
||||||
|
birthday: '',
|
||||||
|
contactAddress: '',
|
||||||
|
email: '',
|
||||||
|
telephone: '',
|
||||||
|
telephonePre: '',
|
||||||
|
whatsApp: '',
|
||||||
|
whatsAppPre: '',
|
||||||
|
wechat: '',
|
||||||
|
qq: '',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 表单校验
|
||||||
|
//可选国家列表
|
||||||
|
countryList: [],
|
||||||
|
//可选时区列表
|
||||||
|
timeZoneList: [],
|
||||||
|
// 表单校验
|
||||||
|
rules: {
|
||||||
|
cusCode: [
|
||||||
|
{ required: true, message: '请输入客户编码', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
fullName: [
|
||||||
|
{ required: true, message: '请输入客户名称', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
cusType: [
|
||||||
|
{ required: true, message: '请选择客户类型', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'contact': [
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
required: true,
|
||||||
|
message: '请至少添加一个联系人',
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* 新增联系人
|
||||||
|
*/
|
||||||
|
addNewContact(){
|
||||||
|
this.formData.contact.push({
|
||||||
|
name: '',
|
||||||
|
ifDefault: false,
|
||||||
|
nickName: '',
|
||||||
|
sex: '0',
|
||||||
|
birthday: '',
|
||||||
|
contactAddress: '',
|
||||||
|
email: '',
|
||||||
|
telephone: '',
|
||||||
|
telephonePre: '',
|
||||||
|
whatsApp: '',
|
||||||
|
whatsAppPre: '',
|
||||||
|
wechat: '',
|
||||||
|
qq: '',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 选中默认的联系人
|
||||||
|
*/
|
||||||
|
chooseDefault(index){
|
||||||
|
this.$nextTick(()=>{
|
||||||
|
this.formData.contact.forEach((item,thisIndex) => {
|
||||||
|
item.ifDefault = thisIndex==index
|
||||||
|
})
|
||||||
|
})
|
||||||
|
console.log(this.formData.contact)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 批量删除联系人
|
||||||
|
*/
|
||||||
|
delContactBatch(){
|
||||||
|
if(this.chooseContactIndexs.length==0){
|
||||||
|
this.$message({
|
||||||
|
message: '请至少选择一个联系人',
|
||||||
|
type: 'warning'
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
this.formData.contact = this.formData.contact.filter((item,index) => {
|
||||||
|
return !this.chooseContactIndexs.includes(index)
|
||||||
|
})
|
||||||
|
this.chooseContactIndexs = []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 删除联系人
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
delContact(index){
|
||||||
|
this.formData.contact = this.formData.contact.filter((item,thisIndex) => {
|
||||||
|
return thisIndex!=index
|
||||||
|
})
|
||||||
|
this.chooseContactIndexs = this.chooseContactIndexs.filter((item,thisIndex) => {
|
||||||
|
return thisIndex!=index
|
||||||
|
})
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 选择联系人
|
||||||
|
* @param val
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
chooseContact(val,index){
|
||||||
|
if(val){
|
||||||
|
//选中
|
||||||
|
this.chooseContactIndexs.push(index)
|
||||||
|
}else{
|
||||||
|
this.chooseContactIndexs.splice(this.chooseContactIndexs.indexOf(index),1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 取消按钮
|
||||||
|
cancel() {
|
||||||
|
this.open = false;
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
// 表单重置
|
||||||
|
reset() {
|
||||||
|
this.formData = {
|
||||||
|
mainInfo: {
|
||||||
|
cusCode: '',
|
||||||
|
fullName: '',
|
||||||
|
cusType: '',
|
||||||
|
country: '',
|
||||||
|
shortName: '',
|
||||||
|
zoneName: '',
|
||||||
|
mainProds: "",
|
||||||
|
siteUrl: '',
|
||||||
|
remark: "",
|
||||||
|
files: ""
|
||||||
|
},
|
||||||
|
contact: [
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
ifDefault: true,
|
||||||
|
nickName: '',
|
||||||
|
sex: '1',
|
||||||
|
birthday: '',
|
||||||
|
contactAddress: '',
|
||||||
|
email: '',
|
||||||
|
telephone: '',
|
||||||
|
telephonePre: '',
|
||||||
|
whatsApp: '',
|
||||||
|
whatsAppPre: '',
|
||||||
|
wechat: '',
|
||||||
|
qq: '',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
this.resetForm("formData");
|
||||||
|
},
|
||||||
|
/** 提交按钮 */
|
||||||
|
submitForm() {
|
||||||
|
this.$refs["formData"].validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 内容区块样式 */
|
||||||
|
.content-section {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-radius: 8px; /* 圆角优化,更美观 */
|
||||||
|
padding: 5px 20px;
|
||||||
|
margin-bottom: 15px; /* 区块之间间距 */
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); /* 轻微阴影,增强层次感 */
|
||||||
|
}
|
||||||
|
/* 区块标题样式 */
|
||||||
|
.section-box {
|
||||||
|
margin: 8px 0 16px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333333;
|
||||||
|
padding: 0 20px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title::before {
|
||||||
|
content: "";
|
||||||
|
width: 3px;
|
||||||
|
height: 12px;
|
||||||
|
background: #1890ff;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.section-right{
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dl-drawer-box{
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
.dl-drawer-footer{
|
||||||
|
z-index: 999;
|
||||||
|
background-color: white;
|
||||||
|
border-top: 1px solid #DCDFE6;;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
height: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: end;
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
::v-deep .el-select .el-input {
|
||||||
|
min-width: 60px;
|
||||||
|
}
|
||||||
|
::v-deep .el-select .el-input__inner{
|
||||||
|
padding: 5px !important;
|
||||||
|
}
|
||||||
|
::v-deep .input-with-select .el-input-group__prepend {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.choose-contact{
|
||||||
|
border: 1px solid #1366ff !important;
|
||||||
|
}
|
||||||
|
.box-card{
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
::v-deep .el-card__body{
|
||||||
|
padding: 15px 20px 0 20px;
|
||||||
|
}
|
||||||
|
.dl-checkbox-box{
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
.dl-del-box{
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
bottom: 5px;
|
||||||
|
}
|
||||||
|
/* 角标样式:定位、旋转、外观 */
|
||||||
|
.corner-tag {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
transform: translate(50%, -50%) rotate(45deg); /* 关键:定位到右上角并倾斜 */
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 10px 18px 5px 18px;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); /* 可选:添加阴影增强立体感 */
|
||||||
|
}
|
||||||
|
.corner-tag-default{
|
||||||
|
background-color: #1890ff; /* 蓝色背景,可自定义 */
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.corner-tag-normal{
|
||||||
|
background-color: rgba(187, 178, 178, 0.05); /* 蓝色背景,可自定义 */
|
||||||
|
color: #DCDFE6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -42,6 +42,16 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<el-row :gutter="10" class="mb8">
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
icon="el-icon-plus"
|
||||||
|
size="mini"
|
||||||
|
@click="handleAddQuick"
|
||||||
|
v-hasPermi="['cus:main:add']"
|
||||||
|
>快速新增</el-button>
|
||||||
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
@ -143,87 +153,18 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 添加或修改客户信息对话框 -->
|
<!-- 添加或修改客户信息对话框 -->
|
||||||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
<draw-form ref="drawForm"></draw-form>
|
||||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
|
||||||
<el-form-item label="客户标签(多个英文逗号隔开)" prop="cusLabels">
|
|
||||||
<el-select v-model="form.cusLabels" placeholder="请选择客户标签(多个英文逗号隔开)">
|
|
||||||
<el-option
|
|
||||||
v-for="dict in dict.type.cus_label"
|
|
||||||
:key="dict.value"
|
|
||||||
:label="dict.label"
|
|
||||||
:value="dict.value"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="客户代码" prop="cusCode">
|
|
||||||
<el-input v-model="form.cusCode" placeholder="请输入客户代码" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="客户名称" prop="fullName">
|
|
||||||
<el-input v-model="form.fullName" placeholder="请输入客户名称" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="客户简称" prop="shortName">
|
|
||||||
<el-input v-model="form.shortName" placeholder="请输入客户简称" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="客户类型" prop="cusType">
|
|
||||||
<el-select v-model="form.cusType" placeholder="请选择客户类型">
|
|
||||||
<el-option
|
|
||||||
v-for="dict in dict.type.cus_type"
|
|
||||||
:key="dict.value"
|
|
||||||
:label="dict.label"
|
|
||||||
:value="dict.value"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="主营产品(多个英文逗号隔开)" prop="mainProds">
|
|
||||||
<el-select v-model="form.mainProds" placeholder="请选择主营产品(多个英文逗号隔开)">
|
|
||||||
<el-option
|
|
||||||
v-for="dict in dict.type.cus_main_product"
|
|
||||||
:key="dict.value"
|
|
||||||
:label="dict.label"
|
|
||||||
:value="dict.value"
|
|
||||||
></el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="企业网站" prop="siteUrl">
|
|
||||||
<el-input v-model="form.siteUrl" placeholder="请输入企业网站" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="备注" prop="remark">
|
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="附件" prop="files">
|
|
||||||
<file-upload v-model="form.files"/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="创建时间" prop="createdTime">
|
|
||||||
<el-date-picker clearable
|
|
||||||
v-model="form.createdTime"
|
|
||||||
type="date"
|
|
||||||
value-format="yyyy-MM-dd"
|
|
||||||
placeholder="请选择创建时间">
|
|
||||||
</el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="更新时间" prop="updatedTime">
|
|
||||||
<el-date-picker clearable
|
|
||||||
v-model="form.updatedTime"
|
|
||||||
type="date"
|
|
||||||
value-format="yyyy-MM-dd"
|
|
||||||
placeholder="请选择更新时间">
|
|
||||||
</el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<div slot="footer" class="dialog-footer">
|
|
||||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
|
||||||
<el-button @click="cancel">取 消</el-button>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { listMain, getMain, delMain, addMain, updateMain } from "@/api/cus/main";
|
import { listMain, getMain, delMain, addMain, updateMain } from "@/api/cus/main";
|
||||||
|
import DrawForm from './drawForm'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Main",
|
name: "Main",
|
||||||
dicts: ['cus_main_product', 'cus_label', 'cus_type'],
|
components: { DrawForm },
|
||||||
|
dicts: ['cus_main_product', 'cus_label', 'cus_type','sys_user_sex','cus_from','cus_level','cus_busi_type','cus_follow_step'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 遮罩层
|
// 遮罩层
|
||||||
@ -241,7 +182,7 @@ export default {
|
|||||||
// 客户信息表格数据
|
// 客户信息表格数据
|
||||||
mainList: [],
|
mainList: [],
|
||||||
// 弹出层标题
|
// 弹出层标题
|
||||||
title: "",
|
title: "快速新建客户",
|
||||||
// 是否显示弹出层
|
// 是否显示弹出层
|
||||||
open: false,
|
open: false,
|
||||||
// 查询参数
|
// 查询参数
|
||||||
@ -256,31 +197,69 @@ export default {
|
|||||||
country: null,
|
country: null,
|
||||||
mainProds: null,
|
mainProds: null,
|
||||||
},
|
},
|
||||||
|
//当前选中的联系人索引
|
||||||
|
chooseContactIndexs: [],
|
||||||
|
// 只显示必填项开关状态
|
||||||
|
onlyRequired: {
|
||||||
|
mainInfo: false,
|
||||||
|
contact: false,
|
||||||
|
},
|
||||||
// 表单参数
|
// 表单参数
|
||||||
form: {},
|
formData: {
|
||||||
|
mainInfo: {
|
||||||
|
cusCode: '',
|
||||||
|
fullName: '',
|
||||||
|
cusType: '',
|
||||||
|
country: '',
|
||||||
|
shortName: '',
|
||||||
|
zoneName: '',
|
||||||
|
mainProds: "",
|
||||||
|
siteUrl: '',
|
||||||
|
remark: "",
|
||||||
|
files: ""
|
||||||
|
},
|
||||||
|
contact: [
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
ifDefault: true,
|
||||||
|
nickName: '',
|
||||||
|
sex: '1',
|
||||||
|
birthday: '',
|
||||||
|
contactAddress: '',
|
||||||
|
email: '',
|
||||||
|
telephone: '',
|
||||||
|
telephonePre: '',
|
||||||
|
whatsApp: '',
|
||||||
|
whatsAppPre: '',
|
||||||
|
wechat: '',
|
||||||
|
qq: '',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 表单校验
|
||||||
|
//可选国家列表
|
||||||
|
countryList: [],
|
||||||
|
//可选时区列表
|
||||||
|
timeZoneList: [],
|
||||||
// 表单校验
|
// 表单校验
|
||||||
rules: {
|
rules: {
|
||||||
cusCode: [
|
cusCode: [
|
||||||
{ required: true, message: "客户代码不能为空", trigger: "blur" }
|
{ required: true, message: '请输入客户编码', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
fullName: [
|
fullName: [
|
||||||
{ required: true, message: "客户名称不能为空", trigger: "blur" }
|
{ required: true, message: '请输入客户名称', trigger: 'blur' }
|
||||||
],
|
|
||||||
shortName: [
|
|
||||||
{ required: true, message: "客户简称不能为空", trigger: "blur" }
|
|
||||||
],
|
],
|
||||||
cusType: [
|
cusType: [
|
||||||
{ required: true, message: "客户类型不能为空", trigger: "change" }
|
{ required: true, message: '请选择客户类型', trigger: 'blur' }
|
||||||
],
|
|
||||||
country: [
|
|
||||||
{ required: true, message: "国家/地区不能为空", trigger: "change" }
|
|
||||||
],
|
|
||||||
zoneName: [
|
|
||||||
{ required: true, message: "时区不能为空", trigger: "change" }
|
|
||||||
],
|
|
||||||
mainProds: [
|
|
||||||
{ required: true, message: "主营产品(多个英文逗号隔开)不能为空", trigger: "change" }
|
|
||||||
],
|
],
|
||||||
|
'contact': [
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
required: true,
|
||||||
|
message: '请至少添加一个联系人',
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -288,6 +267,7 @@ export default {
|
|||||||
this.getList();
|
this.getList();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
/** 查询客户信息列表 */
|
/** 查询客户信息列表 */
|
||||||
getList() {
|
getList() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
@ -297,34 +277,6 @@ export default {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 取消按钮
|
|
||||||
cancel() {
|
|
||||||
this.open = false;
|
|
||||||
this.reset();
|
|
||||||
},
|
|
||||||
// 表单重置
|
|
||||||
reset() {
|
|
||||||
this.form = {
|
|
||||||
id: null,
|
|
||||||
cusLabels: null,
|
|
||||||
cusCode: null,
|
|
||||||
fullName: null,
|
|
||||||
shortName: null,
|
|
||||||
cusType: null,
|
|
||||||
country: null,
|
|
||||||
zoneName: null,
|
|
||||||
mainProds: null,
|
|
||||||
siteUrl: null,
|
|
||||||
remark: null,
|
|
||||||
files: null,
|
|
||||||
delFlag: null,
|
|
||||||
creator: null,
|
|
||||||
createdTime: null,
|
|
||||||
updater: null,
|
|
||||||
updatedTime: null
|
|
||||||
};
|
|
||||||
this.resetForm("form");
|
|
||||||
},
|
|
||||||
/** 搜索按钮操作 */
|
/** 搜索按钮操作 */
|
||||||
handleQuery() {
|
handleQuery() {
|
||||||
this.queryParams.pageNum = 1;
|
this.queryParams.pageNum = 1;
|
||||||
@ -345,6 +297,10 @@ export default {
|
|||||||
handleAdd() {
|
handleAdd() {
|
||||||
this.$router.push({path:'/cus/newForm'})
|
this.$router.push({path:'/cus/newForm'})
|
||||||
},
|
},
|
||||||
|
/** 快速新增按钮操作 */
|
||||||
|
handleAddQuick() {
|
||||||
|
this.$refs.drawForm.open = true
|
||||||
|
},
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
handleUpdate(row) {
|
handleUpdate(row) {
|
||||||
this.reset();
|
this.reset();
|
||||||
@ -394,3 +350,5 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -536,7 +536,7 @@ function debounce(fn, delay = 100) {
|
|||||||
}, delay)
|
}, delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
import { getCode, addMain } from "@/api/cus/main";
|
||||||
// 在组件中引入
|
// 在组件中引入
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user