日志记录修改

This commit is contained in:
luojiaquan
2026-09-30 16:57:44 +08:00
parent 02c281fd07
commit 903d19cad1
9 changed files with 794 additions and 101 deletions
@@ -16,6 +16,17 @@ public class BmsCustomerLog extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 业务模块:客户档案 */
public static final String MODULE_MAIN = "main";
/** 业务模块:公司主体 */
public static final String MODULE_COMPANY = "company";
/** 业务模块:联系人 */
public static final String MODULE_CONTACT = "contact";
/** 业务模块:附件资料 */
public static final String MODULE_ATTACHMENT = "attachment";
/** 业务模块:绑定套餐 */
public static final String MODULE_PRICE_SET = "priceset";
/** 操作类型:新建 */
public static final String OP_INSERT = "1";
/** 操作类型:修改 */
@@ -35,6 +46,12 @@ public class BmsCustomerLog extends BaseEntity
/** 客户名称(操作时快照) */
private String customerName;
/** 业务模块(main/company/contact/attachment/priceset) */
private String bizModule;
/** 操作对象名称(公司全称/联系人姓名/文件名/套餐名) */
private String bizName;
/** 操作类型(1新建 2修改 3删除) */
private String operationType;
@@ -3,7 +3,12 @@ package com.bms.customer.customerinfo.service;
import java.util.List;
import com.bms.customer.customerinfo.domain.BmsCustomer;
import com.bms.customer.customerinfo.domain.BmsCustomerAttachment;
import com.bms.customer.customerinfo.domain.BmsCustomerCompany;
import com.bms.customer.customerinfo.domain.BmsCustomerContact;
import com.bms.customer.customerinfo.domain.BmsCustomerLog;
import com.bms.customer.customerinfo.domain.BmsCustomerPriceSet;
import com.bms.customer.customerinfo.domain.BmsPriceSetOption;
/**
* 客户业务操作日志Service接口
@@ -28,6 +33,60 @@ public interface IBmsCustomerLogService
*/
void recordDelete(BmsCustomer customer);
/**
* 记录新增公司主体
*/
void recordCompanyInsert(BmsCustomerCompany company);
/**
* 记录修改公司主体(字段级变更,无变更不记录)
*/
void recordCompanyUpdate(BmsCustomerCompany oldCompany, BmsCustomerCompany newCompany);
/**
* 记录删除公司主体
*/
void recordCompanyDelete(BmsCustomerCompany company);
/**
* 记录新增联系人
*/
void recordContactInsert(BmsCustomerContact contact);
/**
* 记录修改联系人(字段级变更,无变更不记录)
*/
void recordContactUpdate(BmsCustomerContact oldContact, BmsCustomerContact newContact);
/**
* 记录删除联系人
*/
void recordContactDelete(BmsCustomerContact contact);
/**
* 客户档案附件全量重建前后的差异记录(新增/删除/修改的文件逐条记录)
*
* @param oldList 重建前附件(客户档案模块)
* @param newList 重建后附件
*/
void recordAttachmentRebuild(List<BmsCustomerAttachment> oldList, List<BmsCustomerAttachment> newList);
/**
* 记录新增客户档案附件(随客户新建上传)
*/
void recordAttachmentInsert(BmsCustomerAttachment attachment);
/**
* 记录套餐绑定/更换(existing 为空=首次绑定)
*/
void recordPriceSetBind(BmsCustomer customer, BmsCustomerPriceSet existing,
BmsCustomerPriceSet bind, BmsPriceSetOption newSet);
/**
* 记录套餐解绑
*/
void recordPriceSetUnbind(BmsCustomerPriceSet bind);
/**
* 查询某客户的全部业务日志(时间倒序,含已解析的变更明细)
*/
@@ -1,7 +1,10 @@
package com.bms.customer.customerinfo.service.impl;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -12,9 +15,16 @@ import com.bms.common.core.domain.entity.SysUser;
import com.bms.common.utils.DateUtils;
import com.bms.common.utils.SecurityUtils;
import com.bms.customer.customerinfo.domain.BmsCustomer;
import com.bms.customer.customerinfo.domain.BmsCustomerAttachment;
import com.bms.customer.customerinfo.domain.BmsCustomerCompany;
import com.bms.customer.customerinfo.domain.BmsCustomerContact;
import com.bms.customer.customerinfo.domain.BmsCustomerLog;
import com.bms.customer.customerinfo.domain.BmsCustomerPriceSet;
import com.bms.customer.customerinfo.domain.BmsPriceSetOption;
import com.bms.customer.customerinfo.mapper.BmsCustomerLogMapper;
import com.bms.customer.customerinfo.service.IBmsCustomerLogService;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -30,6 +40,9 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
@Autowired
private BmsCustomerLogMapper bmsCustomerLogMapper;
private static final ThreadLocal<SimpleDateFormat> DATE_FMT =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
/** 业务类型字典 */
private static final Map<String, String> CUSTOMER_TYPE_MAP = Map.of(
"0", "直客", "1", "同行", "2", "集运");
@@ -41,6 +54,17 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
private static final Map<String, String> SETTLEMENT_TYPE_MAP = Map.of(
"0", "月结", "1", "周结", "2", "日结");
/** 联系人类型字典 */
private static final Map<String, String> CONTACT_TYPE_MAP = Map.of(
"0", "业务联系人", "1", "财务联系人", "2", "紧急联系人", "3", "其他");
/** 是否类字典 */
private static final Map<String, String> YES_NO_MAP = Map.of("0", "否", "1", "是");
/** 附件分类字典 */
private static final Map<String, String> ATTACHMENT_TYPE_MAP = Map.of(
"0", "附件资料", "1", "客户Logo", "2", "合同文件", "3", "其他");
/**
* 需要记录日志的主表字段(顺序即展示顺序)。
* requireNonBlank 为 true 的字段对应 update SQL 的 &lt;if test="x!=null and x!=''"&gt;,
@@ -66,6 +90,80 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
new FieldDef("productCodes", "绑定产品", BmsCustomer::getProductCodes, false, Function.identity()),
new FieldDef("remark", "备注", BmsCustomer::getRemark, false, Function.identity()));
/** 公司主体需记录的字段(顺序即展示顺序) */
private static final LinkedHashMap<String, String> COMPANY_FIELDS = new LinkedHashMap<>();
static
{
COMPANY_FIELDS.put("companyNameFull", "公司全称");
COMPANY_FIELDS.put("englishName", "英文名称");
COMPANY_FIELDS.put("creditCode", "统一社会信用代码");
COMPANY_FIELDS.put("legalPerson", "法定代表人");
COMPANY_FIELDS.put("legalPersonPhone", "法定代表人电话");
COMPANY_FIELDS.put("registeredCapital", "注册资本(万元)");
COMPANY_FIELDS.put("capitalCurrency", "注册资本币种");
COMPANY_FIELDS.put("paidInCapital", "实收资本(万元)");
COMPANY_FIELDS.put("establishDate", "成立日期");
COMPANY_FIELDS.put("businessTermStart", "营业期限起");
COMPANY_FIELDS.put("businessTermEnd", "营业期限止");
COMPANY_FIELDS.put("businessTermPermanent", "是否长期有效");
COMPANY_FIELDS.put("registrationAuthority", "登记机关");
COMPANY_FIELDS.put("registrationNumber", "注册号");
COMPANY_FIELDS.put("operatingStatus", "经营状态");
COMPANY_FIELDS.put("employeeCount", "员工人数");
COMPANY_FIELDS.put("businessScope", "经营范围");
COMPANY_FIELDS.put("shareholders", "主要股东");
COMPANY_FIELDS.put("companyPhone", "公司电话");
COMPANY_FIELDS.put("companyFax", "公司传真");
COMPANY_FIELDS.put("companyWebsite", "公司网址");
COMPANY_FIELDS.put("companyEmail", "公司邮箱");
COMPANY_FIELDS.put("registeredProvince", "注册省份");
COMPANY_FIELDS.put("registeredCity", "注册城市");
COMPANY_FIELDS.put("registeredDistrict", "注册区县");
COMPANY_FIELDS.put("registeredAddressDetail", "注册详细地址");
COMPANY_FIELDS.put("remark", "备注");
}
/** 联系人需记录的字段 */
private static final LinkedHashMap<String, String> CONTACT_FIELDS = new LinkedHashMap<>();
static
{
CONTACT_FIELDS.put("contactName", "联系人姓名");
CONTACT_FIELDS.put("position", "职位");
CONTACT_FIELDS.put("department", "所属部门");
CONTACT_FIELDS.put("phone", "手机号");
CONTACT_FIELDS.put("landline", "座机");
CONTACT_FIELDS.put("email", "电子邮箱");
CONTACT_FIELDS.put("wechat", "微信号");
CONTACT_FIELDS.put("qq", "QQ号");
CONTACT_FIELDS.put("country", "国家/地区");
CONTACT_FIELDS.put("province", "省份");
CONTACT_FIELDS.put("city", "城市");
CONTACT_FIELDS.put("district", "区/县");
CONTACT_FIELDS.put("contactAddress", "详细地址");
CONTACT_FIELDS.put("postalCode", "邮政编码");
CONTACT_FIELDS.put("contactType", "联系人类型");
CONTACT_FIELDS.put("isDefault", "是否默认");
CONTACT_FIELDS.put("sortOrder", "排序");
}
/** 附件需记录的字段 */
private static final LinkedHashMap<String, String> ATTACHMENT_FIELDS = new LinkedHashMap<>();
static
{
ATTACHMENT_FIELDS.put("fileName", "文件名称");
ATTACHMENT_FIELDS.put("attachmentType", "附件分类");
ATTACHMENT_FIELDS.put("sortOrder", "排序");
ATTACHMENT_FIELDS.put("remark", "备注");
}
private static final Map<String, Map<String, String>> FIELD_DICTS = Map.of(
"businessTermPermanent", YES_NO_MAP,
"contactType", CONTACT_TYPE_MAP,
"isDefault", YES_NO_MAP,
"attachmentType", ATTACHMENT_TYPE_MAP);
/* ============================== 客户主表 ============================== */
@Override
public void recordInsert(BmsCustomer customer)
{
@@ -82,7 +180,8 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
changes.add(new BmsCustomerLog.FieldChange(def.field, def.label, "", value));
}
}
saveLog(customer, BmsCustomerLog.OP_INSERT, changes);
saveLog(customer.getCustomerId(), customer.getCustomerCode(), customer.getCustomerName(),
BmsCustomerLog.MODULE_MAIN, null, BmsCustomerLog.OP_INSERT, changes);
}
@Override
@@ -117,8 +216,8 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
{
return;
}
// 日志快照以修改后的客户编码/名称为准
saveLog(newCustomer, BmsCustomerLog.OP_UPDATE, changes);
saveLog(newCustomer.getCustomerId(), newCustomer.getCustomerCode(), newCustomer.getCustomerName(),
BmsCustomerLog.MODULE_MAIN, null, BmsCustomerLog.OP_UPDATE, changes);
}
@Override
@@ -128,9 +227,236 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
{
return;
}
saveLog(customer, BmsCustomerLog.OP_DELETE, null);
saveLog(customer.getCustomerId(), customer.getCustomerCode(), customer.getCustomerName(),
BmsCustomerLog.MODULE_MAIN, null, BmsCustomerLog.OP_DELETE, null);
}
/* ============================== 公司主体 ============================== */
@Override
public void recordCompanyInsert(BmsCustomerCompany company)
{
if (company == null || company.getCustomerId() == null)
{
return;
}
saveLog(company.getCustomerId(), null, null, BmsCustomerLog.MODULE_COMPANY,
company.getCompanyNameFull(), BmsCustomerLog.OP_INSERT,
beanInsertChanges(company, COMPANY_FIELDS));
}
@Override
public void recordCompanyUpdate(BmsCustomerCompany oldCompany, BmsCustomerCompany newCompany)
{
if (oldCompany == null || newCompany == null || newCompany.getCustomerId() == null)
{
return;
}
List<BmsCustomerLog.FieldChange> changes = beanDiff(oldCompany, newCompany, COMPANY_FIELDS);
if (changes.isEmpty())
{
return;
}
String bizName = trimToNull(newCompany.getCompanyNameFull());
if (bizName == null)
{
bizName = oldCompany.getCompanyNameFull();
}
saveLog(newCompany.getCustomerId(), null, null, BmsCustomerLog.MODULE_COMPANY,
bizName, BmsCustomerLog.OP_UPDATE, changes);
}
@Override
public void recordCompanyDelete(BmsCustomerCompany company)
{
if (company == null || company.getCustomerId() == null)
{
return;
}
saveLog(company.getCustomerId(), null, null, BmsCustomerLog.MODULE_COMPANY,
company.getCompanyNameFull(), BmsCustomerLog.OP_DELETE, null);
}
/* ============================== 联系人 ============================== */
@Override
public void recordContactInsert(BmsCustomerContact contact)
{
if (contact == null || contact.getCustomerId() == null)
{
return;
}
saveLog(contact.getCustomerId(), null, null, BmsCustomerLog.MODULE_CONTACT,
contact.getContactName(), BmsCustomerLog.OP_INSERT,
beanInsertChanges(contact, CONTACT_FIELDS));
}
@Override
public void recordContactUpdate(BmsCustomerContact oldContact, BmsCustomerContact newContact)
{
if (oldContact == null || newContact == null || newContact.getCustomerId() == null)
{
return;
}
List<BmsCustomerLog.FieldChange> changes = beanDiff(oldContact, newContact, CONTACT_FIELDS);
if (changes.isEmpty())
{
return;
}
String bizName = trimToNull(newContact.getContactName());
if (bizName == null)
{
bizName = oldContact.getContactName();
}
saveLog(newContact.getCustomerId(), null, null, BmsCustomerLog.MODULE_CONTACT,
bizName, BmsCustomerLog.OP_UPDATE, changes);
}
@Override
public void recordContactDelete(BmsCustomerContact contact)
{
if (contact == null || contact.getCustomerId() == null)
{
return;
}
saveLog(contact.getCustomerId(), null, null, BmsCustomerLog.MODULE_CONTACT,
contact.getContactName(), BmsCustomerLog.OP_DELETE, null);
}
/* ============================== 附件 ============================== */
@Override
public void recordAttachmentInsert(BmsCustomerAttachment attachment)
{
if (attachment == null || attachment.getCustomerId() == null)
{
return;
}
saveLog(attachment.getCustomerId(), null, null, BmsCustomerLog.MODULE_ATTACHMENT,
attachment.getFileName(), BmsCustomerLog.OP_INSERT,
beanInsertChanges(attachment, ATTACHMENT_FIELDS));
}
@Override
public void recordAttachmentRebuild(List<BmsCustomerAttachment> oldListIn, List<BmsCustomerAttachment> newListIn)
{
List<BmsCustomerAttachment> oldList = safe(oldListIn);
List<BmsCustomerAttachment> newList = safe(newListIn);
Map<String, BmsCustomerAttachment> oldMap = new LinkedHashMap<>();
for (BmsCustomerAttachment a : oldList)
{
if (a.getFilePath() != null)
{
oldMap.put(a.getFilePath(), a);
}
}
Map<String, BmsCustomerAttachment> newMap = new LinkedHashMap<>();
for (BmsCustomerAttachment a : newList)
{
if (a.getFilePath() != null)
{
newMap.put(a.getFilePath(), a);
}
}
Long customerId = null;
if (!oldList.isEmpty())
{
customerId = oldList.get(0).getCustomerId();
}
if (!newList.isEmpty())
{
customerId = newList.get(0).getCustomerId();
}
if (customerId == null)
{
return;
}
// 新增的文件
for (Map.Entry<String, BmsCustomerAttachment> e : newMap.entrySet())
{
if (!oldMap.containsKey(e.getKey()))
{
saveLog(customerId, null, null, BmsCustomerLog.MODULE_ATTACHMENT,
e.getValue().getFileName(), BmsCustomerLog.OP_INSERT,
beanInsertChanges(e.getValue(), ATTACHMENT_FIELDS));
}
}
// 修改的文件(分类/排序/备注/文件名)
for (Map.Entry<String, BmsCustomerAttachment> e : newMap.entrySet())
{
BmsCustomerAttachment old = oldMap.get(e.getKey());
if (old == null)
{
continue;
}
List<BmsCustomerLog.FieldChange> changes = beanDiff(old, e.getValue(), ATTACHMENT_FIELDS);
if (!changes.isEmpty())
{
String fileName = trimToNull(e.getValue().getFileName());
saveLog(customerId, null, null, BmsCustomerLog.MODULE_ATTACHMENT,
fileName != null ? fileName : old.getFileName(), BmsCustomerLog.OP_UPDATE, changes);
}
}
// 删除的文件
for (Map.Entry<String, BmsCustomerAttachment> e : oldMap.entrySet())
{
if (!newMap.containsKey(e.getKey()))
{
saveLog(customerId, null, null, BmsCustomerLog.MODULE_ATTACHMENT,
e.getValue().getFileName(), BmsCustomerLog.OP_DELETE, null);
}
}
}
/* ============================== 套餐绑定 ============================== */
@Override
public void recordPriceSetBind(BmsCustomer customer, BmsCustomerPriceSet existing,
BmsCustomerPriceSet bind, BmsPriceSetOption newSet)
{
if (bind == null || bind.getCustomerId() == null || newSet == null)
{
return;
}
List<BmsCustomerLog.FieldChange> changes = new ArrayList<>();
changes.add(new BmsCustomerLog.FieldChange("priceSetName", "套餐",
existing == null ? "" : nz(existing.getPriceSetName()), nz(newSet.getPriceSetName())));
changes.add(new BmsCustomerLog.FieldChange("bindPriority", "优先级",
existing == null ? "" : numText(existing.getBindPriority()), numText(bind.getBindPriority())));
changes.add(new BmsCustomerLog.FieldChange("prBegindate", "生效日期",
existing == null ? "" : dateText(existing.getPrBegindate()), dateText(bind.getPrBegindate())));
changes.add(new BmsCustomerLog.FieldChange("prEnddate", "失效日期",
existing == null ? "长期" : dateTextOrLong(existing.getPrEnddate()), dateTextOrLong(bind.getPrEnddate())));
changes.add(new BmsCustomerLog.FieldChange("priceSetNote", "备注",
existing == null ? "" : nz(existing.getPriceSetNote()), nz(bind.getPriceSetNote())));
List<BmsCustomerLog.FieldChange> realChanges = new ArrayList<>();
for (BmsCustomerLog.FieldChange c : changes)
{
if (!Objects.equals(emptyToEmpty(c.getOldValue()), emptyToEmpty(c.getNewValue())))
{
realChanges.add(c);
}
}
saveLog(bind.getCustomerId(), customer == null ? null : customer.getCustomerCode(),
customer == null ? null : customer.getCustomerName(),
BmsCustomerLog.MODULE_PRICE_SET, newSet.getPriceSetName(),
existing == null ? BmsCustomerLog.OP_INSERT : BmsCustomerLog.OP_UPDATE, realChanges);
}
@Override
public void recordPriceSetUnbind(BmsCustomerPriceSet bind)
{
if (bind == null || bind.getCustomerId() == null)
{
return;
}
saveLog(bind.getCustomerId(), bind.getCustomerCode(), bind.getCustomerName(),
BmsCustomerLog.MODULE_PRICE_SET, bind.getPriceSetName(),
BmsCustomerLog.OP_DELETE, null);
}
/* ============================== 查询 ============================== */
@Override
public List<BmsCustomerLog> selectByCustomerId(Long customerId)
{
@@ -145,12 +471,18 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
return list;
}
private void saveLog(BmsCustomer customer, String operationType, List<BmsCustomerLog.FieldChange> changes)
/* ============================== 内部工具 ============================== */
private void saveLog(Long customerId, String customerCode, String customerName,
String module, String bizName, String operationType,
List<BmsCustomerLog.FieldChange> changes)
{
BmsCustomerLog log = new BmsCustomerLog();
log.setCustomerId(customer.getCustomerId());
log.setCustomerCode(customer.getCustomerCode());
log.setCustomerName(customer.getCustomerName());
log.setCustomerId(customerId);
log.setCustomerCode(customerCode);
log.setCustomerName(customerName);
log.setBizModule(module);
log.setBizName(bizName);
log.setOperationType(operationType);
if (changes != null)
{
@@ -170,6 +502,88 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
bmsCustomerLogMapper.insertBmsCustomerLog(log);
}
/** 新增场景:取所有非空字段作为初始值 */
private List<BmsCustomerLog.FieldChange> beanInsertChanges(Object bean, LinkedHashMap<String, String> fields)
{
List<BmsCustomerLog.FieldChange> changes = new ArrayList<>();
BeanWrapper bw = new BeanWrapperImpl(bean);
for (Map.Entry<String, String> f : fields.entrySet())
{
String value = displayValue(bw, f.getKey());
if (value != null && !value.isEmpty())
{
changes.add(new BmsCustomerLog.FieldChange(f.getKey(), f.getValue(), "", value));
}
}
return changes;
}
/** 修改场景:逐字段比对,返回变化项 */
private List<BmsCustomerLog.FieldChange> beanDiff(Object oldBean, Object newBean,
LinkedHashMap<String, String> fields)
{
List<BmsCustomerLog.FieldChange> changes = new ArrayList<>();
BeanWrapper oldBw = new BeanWrapperImpl(oldBean);
BeanWrapper newBw = new BeanWrapperImpl(newBean);
for (Map.Entry<String, String> f : fields.entrySet())
{
Object newRaw = newBw.getPropertyValue(f.getKey());
// 与 update 动态 SQL 保持一致:新值为 null 的字段本次不落库,不参与比对
if (newRaw == null)
{
continue;
}
Object oldRaw = oldBw.getPropertyValue(f.getKey());
if (!sameValue(oldRaw, newRaw))
{
changes.add(new BmsCustomerLog.FieldChange(f.getKey(), f.getValue(),
nz(displayValue(oldBw, f.getKey())), nz(displayValue(newBw, f.getKey()))));
}
}
return changes;
}
/** 字段值 -> 日志展示文本(字典翻译/日期格式化) */
private String displayValue(BeanWrapper bw, String field)
{
Object raw = bw.getPropertyValue(field);
if (raw == null)
{
return "";
}
if (raw instanceof Date)
{
return DATE_FMT.get().format((Date) raw);
}
String text = raw.toString();
if (text.isEmpty())
{
return "";
}
Map<String, String> dict = FIELD_DICTS.get(field);
if (dict != null)
{
String translated = dict.get(text);
return translated != null ? translated : text;
}
return text;
}
private static List<BmsCustomerAttachment> safe(List<BmsCustomerAttachment> list)
{
return list == null ? List.of() : list;
}
private static String emptyToEmpty(String s)
{
return s == null ? "" : s;
}
private static String nz(String s)
{
return s == null ? "" : s;
}
/** 人员字段展示:姓名(工号),缺姓名时只显示工号 */
private static String userDisplay(String code, String name)
{
@@ -195,6 +609,16 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
return num == null ? "" : num.toString();
}
private static String dateText(Date date)
{
return date == null ? "" : DATE_FMT.get().format(date);
}
private static String dateTextOrLong(Date date)
{
return date == null ? "长期" : DATE_FMT.get().format(date);
}
private static String trimToNull(String s)
{
if (s == null)
@@ -205,18 +629,32 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
return t.isEmpty() ? null : t;
}
/** 数值按大小比较(规避 BigDecimal 精度差异),其余按字符串比较 */
/** 数值按大小比较(规避 BigDecimal 精度差异),日期按时间比较,其余按字符串比较 */
private static boolean sameValue(Object a, Object b)
{
if (a instanceof BigDecimal && b instanceof BigDecimal)
{
return ((BigDecimal) a).compareTo((BigDecimal) b) == 0;
}
return Objects.equals(a == null ? null : a.toString(), b == null ? null : b.toString());
if (a instanceof Date && b instanceof Date)
{
return ((Date) a).getTime() == ((Date) b).getTime();
}
String sa = a == null ? null : a.toString();
String sb = b == null ? null : b.toString();
if ("".equals(sa))
{
sa = null;
}
if ("".equals(sb))
{
sb = null;
}
return Objects.equals(sa, sb);
}
/**
* 字段定义
* 主表字段定义
*/
private static final class FieldDef
{
@@ -9,6 +9,7 @@ import com.bms.customer.customerinfo.domain.BmsCustomer;
import com.bms.customer.customerinfo.domain.BmsCustomerPriceSet;
import com.bms.customer.customerinfo.domain.BmsPriceSetOption;
import com.bms.customer.customerinfo.mapper.BmsCustomerPriceSetMapper;
import com.bms.customer.customerinfo.service.IBmsCustomerLogService;
import com.bms.customer.customerinfo.service.IBmsCustomerPriceSetService;
import com.bms.customer.customerinfo.service.IBmsCustomerService;
@@ -27,6 +28,9 @@ public class BmsCustomerPriceSetServiceImpl implements IBmsCustomerPriceSetServi
@Autowired
private IBmsCustomerService customerService;
@Autowired
private IBmsCustomerLogService customerLogService;
@Override
public List<BmsCustomerPriceSet> selectBindList(Long customerId)
{
@@ -85,19 +89,37 @@ public class BmsCustomerPriceSetServiceImpl implements IBmsCustomerPriceSetServi
bind.setCustomerName(customer.getCustomerName());
BmsCustomerPriceSet existing = bindMapper.selectBindByCustomerId(bind.getCustomerId());
// selectBindByCustomerId 未关联套餐表,补取旧套餐名用于日志展示
if (existing != null && existing.getPriceSetId() != null)
{
BmsPriceSetOption oldSet = bindMapper.selectPriceSetOptionById(existing.getPriceSetId());
if (oldSet != null)
{
existing.setPriceSetName(oldSet.getPriceSetName());
}
}
int rows;
try
{
if (existing != null)
{
bind.setCustomerPricesetId(existing.getCustomerPricesetId());
return bindMapper.updateBind(bind);
rows = bindMapper.updateBind(bind);
}
else
{
rows = bindMapper.insertBind(bind);
}
return bindMapper.insertBind(bind);
}
catch (DuplicateKeyException e)
{
throw new ServiceException("该客户已存在套餐绑定,请勿重复绑定");
}
if (rows > 0)
{
customerLogService.recordPriceSetBind(customer, existing, bind, set);
}
return rows;
}
@Override
@@ -107,6 +129,24 @@ public class BmsCustomerPriceSetServiceImpl implements IBmsCustomerPriceSetServi
{
throw new ServiceException("请选择要解绑的记录");
}
return bindMapper.deleteBindByIds(customerPricesetIds);
// 删除前逐个取快照,用于解绑日志
List<BmsCustomerPriceSet> snapshots = new java.util.ArrayList<>();
for (Long id : customerPricesetIds)
{
BmsCustomerPriceSet snapshot = bindMapper.selectBindById(id);
if (snapshot != null)
{
snapshots.add(snapshot);
}
}
int rows = bindMapper.deleteBindByIds(customerPricesetIds);
if (rows > 0)
{
for (BmsCustomerPriceSet snapshot : snapshots)
{
customerLogService.recordPriceSetUnbind(snapshot);
}
}
return rows;
}
}
@@ -98,6 +98,15 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
*/
@Override
public void saveBmsCustomerAttachments(Long customerId, List<BmsCustomerAttachment> attachmentList)
{
saveBmsCustomerAttachments(customerId, attachmentList, false);
}
/**
* 批量保存客户附件。
* @param logInsert true=随客户新建上传,逐文件记新增日志;false=编辑页全量重建,日志由重建差异统一记录
*/
private void saveBmsCustomerAttachments(Long customerId, List<BmsCustomerAttachment> attachmentList, boolean logInsert)
{
if (attachmentList == null || attachmentList.isEmpty())
{
@@ -123,6 +132,10 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
item.setCreateBy(user.getUserName());
item.setCreateTime(DateUtils.getNowDate());
bmsCustomerMapper.insertBmsCustomerAttachment(item);
if (logInsert)
{
customerLogService.recordAttachmentInsert(item);
}
}
}
}
@@ -167,7 +180,12 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
{
bmsCustomerCompany.setDelFlag("0");
}
return bmsCustomerMapper.insertBmsCustomerCompany(bmsCustomerCompany);
int rows = bmsCustomerMapper.insertBmsCustomerCompany(bmsCustomerCompany);
if (rows > 0)
{
customerLogService.recordCompanyInsert(bmsCustomerCompany);
}
return rows;
}
/**
@@ -176,10 +194,17 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
@Override
public int updateBmsCustomerCompany(BmsCustomerCompany bmsCustomerCompany)
{
BmsCustomerCompany old = bmsCustomerCompany.getCompanyId() == null ? null
: bmsCustomerMapper.selectBmsCustomerCompanyByCompanyId(bmsCustomerCompany.getCompanyId());
SysUser user = SecurityUtils.getLoginUser().getUser();
bmsCustomerCompany.setUpdateBy(user.getUserName());
bmsCustomerCompany.setUpdateTime(DateUtils.getNowDate());
return bmsCustomerMapper.updateBmsCustomerCompany(bmsCustomerCompany);
int rows = bmsCustomerMapper.updateBmsCustomerCompany(bmsCustomerCompany);
if (rows > 0)
{
customerLogService.recordCompanyUpdate(old, bmsCustomerCompany);
}
return rows;
}
/**
@@ -191,7 +216,12 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
int rows = 0;
for (Long companyId : companyIds)
{
BmsCustomerCompany snapshot = bmsCustomerMapper.selectBmsCustomerCompanyByCompanyId(companyId);
rows += bmsCustomerMapper.deleteBmsCustomerCompanyByCompanyId(companyId);
if (snapshot != null)
{
customerLogService.recordCompanyDelete(snapshot);
}
}
return rows;
}
@@ -216,15 +246,18 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
}
if (item.getCompanyId() != null)
{
BmsCustomerCompany old = bmsCustomerMapper.selectBmsCustomerCompanyByCompanyId(item.getCompanyId());
item.setUpdateBy(user.getUserName());
item.setUpdateTime(DateUtils.getNowDate());
bmsCustomerMapper.updateBmsCustomerCompany(item);
customerLogService.recordCompanyUpdate(old, item);
}
else
{
item.setCreateBy(user.getUserName());
item.setCreateTime(DateUtils.getNowDate());
bmsCustomerMapper.insertBmsCustomerCompany(item);
customerLogService.recordCompanyInsert(item);
}
}
}
@@ -245,7 +278,7 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
int rows = bmsCustomerMapper.insertBmsCustomer(bmsCustomer);
if (rows > 0)
{
saveBmsCustomerAttachments(bmsCustomer.getCustomerId(), bmsCustomer.getAttachmentList());
saveBmsCustomerAttachments(bmsCustomer.getCustomerId(), bmsCustomer.getAttachmentList(), true);
saveBmsCustomerCompanies(bmsCustomer.getCustomerId(), bmsCustomer.getCompanyList());
saveBmsCustomerContacts(bmsCustomer.getCustomerId(), bmsCustomer.getContactList());
// 新建客户即初始化默认CNY账户:余额0、总额度1000 CNY,写INIT流水
@@ -271,6 +304,11 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
bmsCustomer.setUpdateBy(user.getUserName());
// 修改前先取旧值快照,用于业务日志记录字段级变更
BmsCustomer oldCustomer = bmsCustomerMapper.selectBmsCustomerByCustomerId(bmsCustomer.getCustomerId());
// 附件重建前取旧档案附件快照,重建后按文件差异记业务日志
BmsCustomerAttachment attachmentQuery = new BmsCustomerAttachment();
attachmentQuery.setCustomerId(bmsCustomer.getCustomerId());
attachmentQuery.setBizType(BmsCustomerAttachment.BIZ_TYPE_CUSTOMER);
List<BmsCustomerAttachment> oldAttachments = bmsCustomerMapper.selectBmsCustomerAttachmentList(attachmentQuery);
// 仅重建客户档案模块的附件,收款水单等其他业务模块的附件保留不动
bmsCustomerMapper.deleteBmsCustomerProfileAttachmentByCustomerId(bmsCustomer.getCustomerId());
if (bmsCustomer.getAttachmentList() != null)
@@ -286,10 +324,12 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
// 联系人采用增量 upsert
saveBmsCustomerContacts(bmsCustomer.getCustomerId(), bmsCustomer.getContactList());
int rows = bmsCustomerMapper.updateBmsCustomer(bmsCustomer);
// 业务日志:修改(字段级 修改前→修改后;无实际变更时不记录)
if (rows > 0)
{
// 业务日志:主表字段级修改(无实际变更时不记录)
customerLogService.recordUpdate(oldCustomer, bmsCustomer);
// 业务日志:附件新增/删除/修改差异
customerLogService.recordAttachmentRebuild(oldAttachments, bmsCustomer.getAttachmentList());
}
return rows;
}
@@ -384,7 +424,12 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
{
bmsCustomerContact.setDelFlag("0");
}
return bmsCustomerMapper.insertBmsCustomerContact(bmsCustomerContact);
int rows = bmsCustomerMapper.insertBmsCustomerContact(bmsCustomerContact);
if (rows > 0)
{
customerLogService.recordContactInsert(bmsCustomerContact);
}
return rows;
}
/**
@@ -393,10 +438,17 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
@Override
public int updateBmsCustomerContact(BmsCustomerContact bmsCustomerContact)
{
BmsCustomerContact old = bmsCustomerContact.getContactId() == null ? null
: bmsCustomerMapper.selectBmsCustomerContactByContactId(bmsCustomerContact.getContactId());
SysUser user = SecurityUtils.getLoginUser().getUser();
bmsCustomerContact.setUpdateBy(user.getUserName());
bmsCustomerContact.setUpdateTime(DateUtils.getNowDate());
return bmsCustomerMapper.updateBmsCustomerContact(bmsCustomerContact);
int rows = bmsCustomerMapper.updateBmsCustomerContact(bmsCustomerContact);
if (rows > 0)
{
customerLogService.recordContactUpdate(old, bmsCustomerContact);
}
return rows;
}
/**
@@ -408,7 +460,12 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
int rows = 0;
for (Long contactId : contactIds)
{
BmsCustomerContact snapshot = bmsCustomerMapper.selectBmsCustomerContactByContactId(contactId);
rows += bmsCustomerMapper.deleteBmsCustomerContactByContactId(contactId);
if (snapshot != null)
{
customerLogService.recordContactDelete(snapshot);
}
}
return rows;
}
@@ -433,15 +490,18 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService
}
if (item.getContactId() != null)
{
BmsCustomerContact old = bmsCustomerMapper.selectBmsCustomerContactByContactId(item.getContactId());
item.setUpdateBy(user.getUserName());
item.setUpdateTime(DateUtils.getNowDate());
bmsCustomerMapper.updateBmsCustomerContact(item);
customerLogService.recordContactUpdate(old, item);
}
else
{
item.setCreateBy(user.getUserName());
item.setCreateTime(DateUtils.getNowDate());
bmsCustomerMapper.insertBmsCustomerContact(item);
customerLogService.recordContactInsert(item);
}
}
}
@@ -7,6 +7,8 @@
<result property="customerId" column="customer_id" />
<result property="customerCode" column="customer_code" />
<result property="customerName" column="customer_name" />
<result property="bizModule" column="biz_module" />
<result property="bizName" column="biz_name" />
<result property="operationType" column="operation_type" />
<result property="changeContent" column="change_content" />
<result property="createBy" column="create_by" />
@@ -15,8 +17,8 @@
</resultMap>
<sql id="selectBmsCustomerLogVo">
select log_id, customer_id, customer_code, customer_name, operation_type, change_content,
create_by, create_by_name, create_time
select log_id, customer_id, customer_code, customer_name, biz_module, biz_name,
operation_type, change_content, create_by, create_by_name, create_time
from ctr_customer_log
</sql>
@@ -27,6 +29,8 @@
<if test="customerId != null">customer_id,</if>
<if test="customerCode != null">customer_code,</if>
<if test="customerName != null">customer_name,</if>
<if test="bizModule != null">biz_module,</if>
<if test="bizName != null">biz_name,</if>
<if test="operationType != null">operation_type,</if>
<if test="changeContent != null">change_content,</if>
<if test="createBy != null">create_by,</if>
@@ -37,6 +41,8 @@
<if test="customerId != null">#{customerId},</if>
<if test="customerCode != null">#{customerCode},</if>
<if test="customerName != null">#{customerName},</if>
<if test="bizModule != null">#{bizModule},</if>
<if test="bizName != null">#{bizName},</if>
<if test="operationType != null">#{operationType},</if>
<if test="changeContent != null">#{changeContent},</if>
<if test="createBy != null">#{createBy},</if>
@@ -0,0 +1,133 @@
<template>
<el-dialog
:model-value="modelValue"
@update:model-value="$emit('update:modelValue', $event)"
:title="`业务日志 - ${customerName || ''}`"
width="900px"
append-to-body
@open="handleOpen"
>
<div style="margin-bottom: 10px; color: #909399; font-size: 13px;">
客户编码:{{ customerCode || '-' }}
<span style="margin-left: 16px;">共 {{ logList.length }} 条日志(按操作时间倒序)</span>
</div>
<el-table v-loading="loading" :data="logList" border size="small" row-key="logId" :empty-text="'暂无业务日志'">
<el-table-column type="expand">
<template #default="scope">
<div style="padding: 8px 16px; background: #fafafa;">
<div v-if="!scope.row.changes || !scope.row.changes.length" style="color:#909399;">无字段明细</div>
<el-table v-else :data="scope.row.changes" border size="small">
<el-table-column label="字段" prop="fieldLabel" width="180" align="center" />
<el-table-column label="修改前" align="center">
<template #default="cell">
<span :style="{ color: cell.row.oldValue === '' ? '#909399' : '' }">{{ cell.row.oldValue === '' ? '(空)' : cell.row.oldValue }}</span>
</template>
</el-table-column>
<el-table-column label="修改后" align="center">
<template #default="cell">
<span :style="{ color: cell.row.newValue === '' ? '#909399' : '' }">{{ cell.row.newValue === '' ? '(空)' : cell.row.newValue }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column label="模块" align="center" width="92">
<template #default="scope">
<el-tag :type="moduleTagType(scope.row.bizModule)" size="small" effect="plain">{{ moduleLabel(scope.row.bizModule) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="76">
<template #default="scope">
<el-tag :type="opTagType(scope.row.operationType)" size="small">{{ opLabel(scope.row.operationType) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="对象" align="center" width="150" show-overflow-tooltip>
<template #default="scope">
<span :title="scope.row.bizName">{{ scope.row.bizName || '客户档案' }}</span>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" width="130">
<template #default="scope">{{ scope.row.createByName || scope.row.createBy || '-' }}</template>
</el-table-column>
<el-table-column label="操作时间" align="center" width="160">
<template #default="scope">{{ fmtTime(scope.row.createTime) }}</template>
</el-table-column>
<el-table-column label="变更摘要" align="center">
<template #default="scope">
<span>{{ rowSummary(scope.row) }}</span>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="$emit('update:modelValue', false)">关 闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { listCustomerLog } from "@/api/customersuppliermanagement/customerinfo/customer.js"
const { proxy } = getCurrentInstance()
const props = defineProps({
modelValue: { type: Boolean, default: false },
customerId: { type: [Number, String], default: null },
customerName: { type: String, default: '' },
customerCode: { type: String, default: '' }
})
defineEmits(['update:modelValue'])
const loading = ref(false)
const logList = ref([])
const MODULE_META = {
main: { label: '客户档案', tag: '' },
company: { label: '公司主体', tag: 'success' },
contact: { label: '联系人', tag: 'warning' },
attachment: { label: '附件', tag: 'info' },
priceset: { label: '绑定套餐', tag: 'danger' }
}
const OP_META = {
'1': { label: '新建', tag: 'success' },
'2': { label: '修改', tag: 'warning' },
'3': { label: '删除', tag: 'danger' }
}
const moduleLabel = (m) => MODULE_META[m]?.label || '客户档案'
const moduleTagType = (m) => MODULE_META[m]?.tag ?? ''
const opLabel = (op) => OP_META[op]?.label || op
const opTagType = (op) => OP_META[op]?.tag || 'info'
const fmtTime = (t) => t ? proxy.parseTime(t, '{y}-{m}-{d} {h}:{i}:{s}') : '-'
const changeSummary = (changes) => {
if (!changes || !changes.length) return '-'
return changes.slice(0, 3).map(c => c.fieldLabel).join('、') + (changes.length > 3 ? ` 等${changes.length}项` : '')
}
const rowSummary = (row) => {
const mod = moduleLabel(row.bizModule)
const obj = row.bizName ? `「${row.bizName}」` : ''
if (row.operationType === '1') {
return `新建${mod}${obj},录入 ${row.changes?.length || 0} 项信息`
}
if (row.operationType === '2') {
return changeSummary(row.changes)
}
return `${mod}${obj}被删除`
}
const handleOpen = async () => {
if (!props.customerId) return
loading.value = true
try {
const res = await listCustomerLog(props.customerId)
logList.value = res.data || []
} finally {
loading.value = false
}
}
</script>
@@ -10,6 +10,7 @@
</div>
<div class="head-code">客户编码:{{ form.customerCode || '保存后可维护子表数据' }}</div>
<div class="head-right">
<el-button v-if="!isAdd" icon="Document" v-hasPermi="['customersupplier:customerinfo:query']" @click="logOpen = true">日 志</el-button>
<el-button @click="goBack">取 消</el-button>
<el-button v-if="isAdd" type="primary" :loading="saving" v-hasPermi="['customersupplier:customerinfo:add']" @click="submitForm">保 存</el-button>
<el-button v-else type="primary" :loading="saving" v-hasPermi="['customersupplier:customerinfo:edit']" @click="submitForm">保 存</el-button>
@@ -711,6 +712,14 @@
</div>
</template>
</el-dialog>
<!-- 客户业务操作日志弹窗 -->
<customer-log-dialog
v-model="logOpen"
:customer-id="form.customerId"
:customer-name="form.customerName"
:customer-code="form.customerCode"
/>
</div>
</template>
@@ -719,6 +728,7 @@ import {
listCustomer, getCustomer, addCustomer, updateCustomer,
delCustomerCompany, delCustomerContact
} from '@/api/customersuppliermanagement/customerinfo/customer.js'
import CustomerLogDialog from '../components/CustomerLogDialog.vue'
import {
listCustomerPriceSet, listPriceSetOption,
saveCustomerPriceSet, delCustomerPriceSet
@@ -740,6 +750,7 @@ const { ensureProducts, findProduct } = useProducts()
const pageLoading = ref(false)
const saving = ref(false)
const activeTab = ref('base')
const logOpen = ref(false)
const customerId = computed(() => route.query.customerId ? Number(route.query.customerId) : null)
const isAdd = computed(() => !customerId.value)
@@ -197,61 +197,19 @@
/>
<!-- 客户业务操作日志弹窗 -->
<el-dialog v-model="logOpen" :title="`业务日志 - ${logCustomer.customerName || ''}`" width="820px" append-to-body>
<div style="margin-bottom: 10px; color: #909399; font-size: 13px;">
客户编码:{{ logCustomer.customerCode || '-' }}
<span style="margin-left: 16px;">共 {{ logList.length }} 条日志(按操作时间倒序)</span>
</div>
<el-table v-loading="logLoading" :data="logList" border size="small" row-key="logId" :empty-text="'暂无业务日志'">
<el-table-column type="expand">
<template #default="scope">
<div style="padding: 8px 16px; background: #fafafa;">
<div v-if="!scope.row.changes || !scope.row.changes.length" style="color:#909399;">无字段明细</div>
<el-table v-else :data="scope.row.changes" border size="small">
<el-table-column label="字段" prop="fieldLabel" width="180" align="center" />
<el-table-column label="修改前" align="center">
<template #default="cell">
<span :style="{ color: cell.row.oldValue === '' ? '#909399' : '' }">{{ cell.row.oldValue === '' ? '(空)' : cell.row.oldValue }}</span>
</template>
</el-table-column>
<el-table-column label="修改后" align="center">
<template #default="cell">
<span :style="{ color: cell.row.newValue === '' ? '#909399' : '' }">{{ cell.row.newValue === '' ? '(空)' : cell.row.newValue }}</span>
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column label="操作类型" align="center" width="90">
<template #default="scope">
<el-tag :type="opTagType(scope.row.operationType)" size="small">{{ opLabel(scope.row.operationType) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" width="150">
<template #default="scope">{{ scope.row.createByName || scope.row.createBy || '-' }}</template>
</el-table-column>
<el-table-column label="操作时间" align="center" width="170">
<template #default="scope">{{ fmtTime(scope.row.createTime) }}</template>
</el-table-column>
<el-table-column label="变更字段" align="center">
<template #default="scope">
<span v-if="scope.row.operationType === '1'">新建客户,录入 {{ scope.row.changes?.length || 0 }} 项信息</span>
<span v-else-if="scope.row.operationType === '2'">{{ changeSummary(scope.row.changes) }}</span>
<span v-else style="color:#f56c6c;">客户被删除</span>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="logOpen = false">关 闭</el-button>
</template>
</el-dialog>
<customer-log-dialog
v-model="logOpen"
:customer-id="logCustomer.customerId"
:customer-name="logCustomer.customerName"
:customer-code="logCustomer.customerCode"
/>
</div>
</template>
<script setup name="Customer">
import { listCustomer, delCustomer, listCustomerLog } from "@/api/customersuppliermanagement/customerinfo/customer.js"
import { listCustomer, delCustomer } from "@/api/customersuppliermanagement/customerinfo/customer.js"
import { useProducts, parseProductCodes } from '@/components/ProductSelect/useProducts'
import CustomerLogDialog from './components/CustomerLogDialog.vue'
import { useColumnSettings } from '@/utils/columnSettings'
const { proxy } = getCurrentInstance()
@@ -423,30 +381,8 @@ function handleExport() {
/** ========== 客户业务操作日志 ========== */
const logOpen = ref(false)
const logLoading = ref(false)
const logList = ref([])
const logCustomer = ref({})
const OP_META = {
'1': { label: '新建', tag: 'success' },
'2': { label: '修改', tag: 'warning' },
'3': { label: '删除', tag: 'danger' }
}
function opLabel(type) {
return OP_META[type]?.label || '未知'
}
function opTagType(type) {
return OP_META[type]?.tag || 'info'
}
function fmtTime(t) {
return t ? proxy.parseTime(t, '{y}-{m}-{d} {h}:{i}:{s}') : '-'
}
/** 修改日志的变更字段摘要 */
function changeSummary(changes) {
if (!changes || !changes.length) return '-'
return changes.map(c => c.fieldLabel).join('、')
}
/** 打开业务日志弹窗(操作列传 row;工具栏按钮取勾选行) */
function handleViewLog(row) {
const target = (row && row.customerId) ? row : selectedRows.value[0]
@@ -455,14 +391,7 @@ function handleViewLog(row) {
return
}
logCustomer.value = { customerId: target.customerId, customerName: target.customerName, customerCode: target.customerCode }
logList.value = []
logOpen.value = true
logLoading.value = true
listCustomerLog(target.customerId).then(res => {
logList.value = res.data || []
}).finally(() => {
logLoading.value = false
})
}
getList()