package com.vincent.rsf.server.manager.utils;
|
|
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.vincent.rsf.framework.common.Cools;
|
import com.vincent.rsf.framework.common.SpringUtils;
|
import com.vincent.rsf.server.common.service.RedisService;
|
import com.vincent.rsf.server.common.domain.PageResult;
|
import com.vincent.rsf.server.manager.entity.Companys;
|
import com.vincent.rsf.server.manager.entity.Warehouse;
|
import com.vincent.rsf.server.manager.entity.WarehouseAreas;
|
import com.vincent.rsf.server.manager.service.CompanysService;
|
import com.vincent.rsf.server.manager.service.WarehouseService;
|
import com.vincent.rsf.server.system.constant.DictTypeCode;
|
import com.vincent.rsf.server.system.entity.DictData;
|
import com.vincent.rsf.server.system.entity.User;
|
import com.vincent.rsf.server.system.service.DictDataService;
|
import com.vincent.rsf.server.system.service.UserService;
|
|
import java.lang.reflect.Field;
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Optional;
|
import java.util.Set;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.function.Consumer;
|
import java.util.function.Function;
|
import java.util.stream.Collectors;
|
import java.util.stream.Stream;
|
|
public class buildPageRowsUtils {
|
|
private static final String USER_NAME_CACHE_FLAG = "PAGE_ROWS_USER_NAME";
|
private static final String WAREHOUSE_NAME_CACHE_FLAG = "PAGE_ROWS_WAREHOUSE_NAME";
|
private static final String COMPANY_NAME_CACHE_FLAG = "PAGE_ROWS_COMPANY_NAME";
|
private static final int NAME_CACHE_TTL_SECONDS = 300;
|
private static final List<IdFieldMapping> COMMON_ID_FIELD_MAPPINGS = List.of(
|
new IdFieldMapping("tenantId", "tenantId$", com.vincent.rsf.server.system.service.TenantService.class, "name"),
|
new IdFieldMapping("deptId", "deptId$", com.vincent.rsf.server.system.service.DeptService.class, "name"),
|
new IdFieldMapping("dictTypeId", "dictTypeId$", com.vincent.rsf.server.system.service.DictTypeService.class, "name"),
|
new IdFieldMapping("userId", "userId$", UserService.class, "nickname"),
|
new IdFieldMapping("root", "root$", UserService.class, "username"),
|
new IdFieldMapping("warehouseId", "warehouseId$", WarehouseService.class, "name"),
|
new IdFieldMapping("warehouse", "warehouse$", WarehouseService.class, "name"),
|
new IdFieldMapping("area", "area$", com.vincent.rsf.server.manager.service.WarehouseAreasService.class, "name"),
|
new IdFieldMapping("areaId", "areaId$", com.vincent.rsf.server.manager.service.WarehouseAreasService.class, "name"),
|
new IdFieldMapping("shipperId", "shipperId$", CompanysService.class, "name"),
|
new IdFieldMapping("supplierId", "supplierId$", CompanysService.class, "name"),
|
new IdFieldMapping("splrId", "splrId$", CompanysService.class, "name"),
|
new IdFieldMapping("groupId", "groupId$", com.vincent.rsf.server.manager.service.MatnrGroupService.class, "name"),
|
new IdFieldMapping("locId", "locId$", com.vincent.rsf.server.manager.service.LocService.class, "code"),
|
new IdFieldMapping("locTypeId", "locTypeId$", com.vincent.rsf.server.manager.service.LocTypeService.class, "name")
|
);
|
private static final Map<Class<?>, Consumer<List<Object>>> SPECIAL_RECORD_ENRICHERS = createSpecialRecordEnrichers();
|
private static final Map<Class<?>, Map<String, Optional<Field>>> FIELD_CACHE = new ConcurrentHashMap<>();
|
private static final Map<Class<?>, Optional<Field>> ID_FIELD_CACHE = new ConcurrentHashMap<>();
|
|
public static <T> T rowsMap(T data) {
|
if (data == null) {
|
return null;
|
}
|
if (data instanceof Page<?> page) {
|
rowsMapCollection(page.getRecords());
|
return data;
|
}
|
if (data instanceof PageResult<?> pageResult) {
|
rowsMapCollection(pageResult.getRecords());
|
return data;
|
}
|
if (data instanceof Collection<?> collection) {
|
rowsMapCollection(collection);
|
return data;
|
}
|
if (data.getClass().isArray()) {
|
int length = java.lang.reflect.Array.getLength(data);
|
List<Object> records = new ArrayList<>(length);
|
for (int i = 0; i < length; i++) {
|
records.add(java.lang.reflect.Array.get(data, i));
|
}
|
rowsMapCollection(records);
|
return data;
|
}
|
rowsMapCollection(Collections.singletonList(data));
|
return data;
|
}
|
|
public static <T> Map<Long, String> userNameMap(List<T> records) {
|
if (Cools.isEmpty(records)) {
|
return Collections.emptyMap();
|
}
|
Set<Long> userIds = records.stream()
|
.filter(Objects::nonNull)
|
.flatMap(item -> Stream.of(
|
readLongId(item, "createBy"),
|
readLongId(item, "updateBy")
|
))
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
|
Map<Long, String> userNameMap = loadUserNameMap(userIds);
|
fillUserNameFields(records, userNameMap);
|
return userNameMap;
|
}
|
|
public static void warehouseAreasRowsMap(List<WarehouseAreas> records) {
|
if (Cools.isEmpty(records)) {
|
return;
|
}
|
Set<Long> userIds = records.stream()
|
.filter(Objects::nonNull)
|
.flatMap(item -> Stream.of(item.getCreateBy(), item.getUpdateBy()))
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
Set<Long> warehouseIds = records.stream()
|
.map(WarehouseAreas::getWarehouseId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
Set<Long> companyIds = records.stream()
|
.filter(Objects::nonNull)
|
.flatMap(item -> Stream.of(
|
item.getShipperId(),
|
item.getSupplierId() == null ? null : item.getSupplierId().longValue()
|
))
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
Set<String> typeValues = records.stream()
|
.map(WarehouseAreas::getType)
|
.filter(type -> !Cools.isEmpty(type))
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
|
Map<Long, String> userNameMap = loadUserNameMap(userIds);
|
Map<Long, String> warehouseNameMap = loadWarehouseNameMap(warehouseIds);
|
Map<Long, String> companyNameMap = loadCompanyNameMap(companyIds);
|
Map<String, String> typeLabelMap = loadDictLabelMap(typeValues, DictTypeCode.SYS_WARE_AREAS_TYPE);
|
|
records.stream()
|
.filter(Objects::nonNull)
|
.forEach(record -> {
|
record.setCreateBy$(userNameMap.get(record.getCreateBy()));
|
record.setUpdateBy$(userNameMap.get(record.getUpdateBy()));
|
record.setWarehouseId$(warehouseNameMap.get(record.getWarehouseId()));
|
record.setShipperId$(companyNameMap.get(record.getShipperId()));
|
record.setSupplierId$(record.getSupplierId() == null ? null : companyNameMap.get(record.getSupplierId().longValue()));
|
record.setType$(Cools.isEmpty(record.getType()) ? "" : typeLabelMap.get(record.getType()));
|
});
|
}
|
|
private static void rowsMapCollection(Collection<?> sourceRecords) {
|
if (Cools.isEmpty(sourceRecords)) {
|
return;
|
}
|
Map<Class<?>, List<Object>> recordsByClass = new LinkedHashMap<>();
|
for (Object record : sourceRecords) {
|
if (record == null) {
|
continue;
|
}
|
recordsByClass.computeIfAbsent(record.getClass(), key -> new ArrayList<>()).add(record);
|
}
|
recordsByClass.forEach(buildPageRowsUtils::rowsMapByClass);
|
}
|
|
private static void rowsMapByClass(Class<?> recordClass, List<Object> records) {
|
if (recordClass == null || Cools.isEmpty(records)) {
|
return;
|
}
|
if (WarehouseAreas.class.isAssignableFrom(recordClass)) {
|
warehouseAreasRowsMap(records.stream()
|
.map(WarehouseAreas.class::cast)
|
.collect(Collectors.toList()));
|
return;
|
}
|
userNameMap(records);
|
applyCommonIdFieldMappings(records);
|
Consumer<List<Object>> enricher = findSpecialRecordEnricher(recordClass);
|
if (enricher != null) {
|
enricher.accept(records);
|
}
|
fillUserRoleIds(records);
|
}
|
|
private static void applyCommonIdFieldMappings(List<Object> records) {
|
for (IdFieldMapping mapping : COMMON_ID_FIELD_MAPPINGS) {
|
fillFieldById(records, mapping.sourceField(), mapping.targetField(), mapping.serviceClass(), mapping.returnField());
|
}
|
}
|
|
private static Map<Class<?>, Consumer<List<Object>>> createSpecialRecordEnrichers() {
|
Map<Class<?>, Consumer<List<Object>>> enrichers = new LinkedHashMap<>();
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.system.entity.SerialRule", records -> fillDictField(records, "reset", "reset$", "sys_rule_type"));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.system.entity.SerialRuleItem", records -> fillDictField(records, "wkType", "wkType$", "sys_rule_item_type"));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.AsnOrderLog", records -> {
|
fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.DICT_ASN_EXCE_STATUS);
|
fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE);
|
fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.BasContainer", records -> fillDictField(records, "containerType", "containerType$", "sys_container_type"));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.BasStation", records -> {
|
fillDictField(records, "useStatus", "useStatus$", "sys_sta_use_stas");
|
fillDictIdsField(records, "containerType", "containerTypes$", "sys_container_type");
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.BasStationArea", records -> fillDictField(records, "useStatus", "useStatus$", "sys_sta_use_stas"));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.CheckDiff", records -> fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_CHECK_DIFF_EXCE_STATUS));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.CheckDiffItem", records -> fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_CHECK_DIFF_EXCE_STATUS));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Companys", records -> fillDictField(records, "type", "companys$", DictTypeCode.DICT_COMPANY_TYPE));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Delivery", records -> {
|
fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_PO_EXCE_STATUS);
|
fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE);
|
fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.DeviceSite", records -> {
|
fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_TASK_TYPE);
|
fillDictField(records, "device", "device$", DictTypeCode.DICT_SYS_DEVICE_TYPE);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Loc", buildPageRowsUtils::fillLocTypeNamesField);
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocAreaMatRela", records ->
|
fillFieldById(records, "matnrId", "matnrId$", com.vincent.rsf.server.manager.service.MatnrService.class, "name"));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocItem", records -> {
|
fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE);
|
fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocRevise", records -> fillDictField(records, "type", "type$", DictTypeCode.SYS_STOCK_REVISE_TYPE));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.LocTypeRela", records ->
|
fillFieldById(records, "locId", "areaId$", com.vincent.rsf.server.manager.service.LocService.class, "code"));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Purchase", records -> {
|
fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_PO_EXCE_STATUS);
|
fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE);
|
fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.QlyInspect", records -> {
|
fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE);
|
fillDictField(records, "isptStatus", "isptStatus$", DictTypeCode.DICT_QLY_INSPECT_STATUS);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.QlyIsptItem", records -> {
|
fillDictField(records, "isptStatus", "isptStatus$", DictTypeCode.DICT_QLY_INSPECT_STATUS);
|
fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Stock", records -> {
|
fillDictField(records, "type", "type$", DictTypeCode.DICT_SYS_ORDER_TYPE);
|
fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.StockItem", records ->
|
fillFieldById(records, "matnrId", "matnrId$", com.vincent.rsf.server.manager.service.MatnrService.class, "unit"));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Task", records -> {
|
fillDictFieldWithValue(records, "taskStatus", "taskStatus$", DictTypeCode.DICT_SYS_TASK_STATUS);
|
fillDictField(records, "warehType", "warehType$", DictTypeCode.DICT_SYS_DEVICE_TYPE);
|
fillStationNameWithId(records, "orgSite", "orgSite$");
|
fillStationNameWithId(records, "targSite", "targSite$");
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.TaskItem", records -> {
|
fillDictField(records, "orderType", "orderType$", DictTypeCode.DICT_SYS_ORDER_TYPE);
|
fillDictField(records, "wkType", "wkType$", DictTypeCode.DICT_SYS_BUSINESS_TYPE);
|
fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.TaskLog", records -> {
|
fillDictField(records, "taskStatus", "taskStatus$", DictTypeCode.DICT_SYS_TASK_STATUS);
|
fillDictField(records, "taskType", "taskType$", DictTypeCode.DICT_SYS_TASK_TYPE);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Transfer", records -> {
|
fillDictField(records, "type", "type$", DictTypeCode.SYS_TRANSFER_TYPE);
|
fillDictField(records, "exceStatus", "exceStatus$", DictTypeCode.DICT_ASN_EXCE_STATUS);
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaitPakin", records -> fillDictField(records, "ioStatus", "ioStatus$", DictTypeCode.SYS_ORDER_IN_STATUS));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaitPakinItem", records -> fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaitPakinItemLog", records -> {
|
fillFieldById(records, "pakinId", "pakinId$", com.vincent.rsf.server.manager.service.WaitPakinService.class, "id");
|
fillFieldById(records, "matnrId", "matnrId$", com.vincent.rsf.server.manager.service.MatnrService.class, "unit");
|
});
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WarehouseAreasItem", records -> fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.Wave", records -> fillDictFieldWithValue(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_WAVE_EXCE_STATUS));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaveItem", records -> fillDictFieldWithValue(records, "exceStatus", "exceStatus$", DictTypeCode.SYS_WAVE_ITEM_EXCE_STATUS));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WaveRule", records -> fillDictField(records, "type", "type$", DictTypeCode.SYS_WAVE_RULE_CODE));
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WkOrder", buildPageRowsUtils::fillWkOrderRows);
|
registerSpecialEnricher(enrichers, "com.vincent.rsf.server.manager.entity.WkOrderItem", records -> fillDictField(records, "isptResult", "isptResult$", DictTypeCode.DICT_INSPECT_RESULT));
|
return enrichers;
|
}
|
|
private static void registerSpecialEnricher(Map<Class<?>, Consumer<List<Object>>> enrichers, String className, Consumer<List<Object>> enricher) {
|
try {
|
enrichers.put(Class.forName(className), enricher);
|
} catch (ClassNotFoundException ignored) {
|
}
|
}
|
|
private static Consumer<List<Object>> findSpecialRecordEnricher(Class<?> recordClass) {
|
for (Map.Entry<Class<?>, Consumer<List<Object>>> entry : SPECIAL_RECORD_ENRICHERS.entrySet()) {
|
if (entry.getKey().isAssignableFrom(recordClass)) {
|
return entry.getValue();
|
}
|
}
|
return null;
|
}
|
|
private static void fillWkOrderRows(List<Object> records) {
|
fillDictField(records, "checkType", "checkType$", DictTypeCode.SYS_CHECK_TYPE);
|
fillDictField(records, "exceStatus", "exceStatus$", record -> Objects.equals(getStringFieldValue(record, "type"), com.vincent.rsf.server.manager.enums.OrderType.ORDER_CHECK.type)
|
? DictTypeCode.SYS_CHECK_EXCE_STATUS
|
: DictTypeCode.DICT_ASN_EXCE_STATUS, false);
|
fillComputedStringField(records, "wkType$", record -> com.vincent.rsf.server.manager.enums.OrderWorkType.getWorkDesc(getStringFieldValue(record, "wkType")));
|
}
|
|
private static void fillComputedStringField(List<Object> records, String targetField, Function<Object, String> valueResolver) {
|
if (Cools.isEmpty(records) || !hasField(records.get(0), targetField) || valueResolver == null) {
|
return;
|
}
|
for (Object record : records) {
|
writeStringField(record, targetField, valueResolver.apply(record));
|
}
|
}
|
|
private static void fillDictField(List<Object> records, String sourceField, String targetField, String dictTypeCode) {
|
fillDictField(records, sourceField, targetField, record -> dictTypeCode, false);
|
}
|
|
private static void fillDictFieldWithValue(List<Object> records, String sourceField, String targetField, String dictTypeCode) {
|
fillDictField(records, sourceField, targetField, record -> dictTypeCode, true);
|
}
|
|
private static void fillDictField(List<Object> records,
|
String sourceField,
|
String targetField,
|
Function<Object, String> dictTypeResolver,
|
boolean appendValue) {
|
if (Cools.isEmpty(records) || !hasField(records.get(0), targetField) || dictTypeResolver == null) {
|
return;
|
}
|
Map<String, Set<String>> valuesByType = new LinkedHashMap<>();
|
for (Object record : records) {
|
String dictTypeCode = dictTypeResolver.apply(record);
|
String value = normalizeStringValue(readFieldValue(record, sourceField));
|
if (Cools.isEmpty(dictTypeCode) || Cools.isEmpty(value)) {
|
continue;
|
}
|
valuesByType.computeIfAbsent(dictTypeCode, key -> new LinkedHashSet<>()).add(value);
|
}
|
if (valuesByType.isEmpty()) {
|
return;
|
}
|
Map<String, Map<String, String>> labelMapByType = new HashMap<>();
|
valuesByType.forEach((dictTypeCode, values) -> labelMapByType.put(dictTypeCode, loadDictLabelMap(values, dictTypeCode)));
|
for (Object record : records) {
|
String dictTypeCode = dictTypeResolver.apply(record);
|
String value = normalizeStringValue(readFieldValue(record, sourceField));
|
if (Cools.isEmpty(dictTypeCode) || Cools.isEmpty(value)) {
|
continue;
|
}
|
String label = labelMapByType.getOrDefault(dictTypeCode, Collections.emptyMap()).get(value);
|
if (label == null) {
|
continue;
|
}
|
writeStringField(record, targetField, appendValue ? value + "." + label : label);
|
}
|
}
|
|
private static void fillDictIdsField(List<Object> records, String sourceField, String targetField, String dictTypeCode) {
|
if (Cools.isEmpty(records) || !hasField(records.get(0), targetField)) {
|
return;
|
}
|
Set<String> values = new LinkedHashSet<>();
|
for (Object record : records) {
|
Object sourceValue = readFieldValue(record, sourceField);
|
if (sourceValue instanceof Collection<?> collection) {
|
collection.stream()
|
.map(buildPageRowsUtils::normalizeStringValue)
|
.filter(item -> !Cools.isEmpty(item))
|
.forEach(values::add);
|
}
|
}
|
if (values.isEmpty()) {
|
return;
|
}
|
List<?> dictDataList = listEntitiesByFieldIn(DictDataService.class, DictData.class, "value", values, Map.of("dictTypeCode", dictTypeCode));
|
Map<String, Long> dictIdMap = new HashMap<>();
|
for (Object dictData : dictDataList) {
|
String value = getStringFieldValue(dictData, "value");
|
Long id = getLongFieldValue(dictData, "id");
|
if (Cools.isEmpty(value) || id == null) {
|
continue;
|
}
|
dictIdMap.put(value, id);
|
}
|
for (Object record : records) {
|
Object sourceValue = readFieldValue(record, sourceField);
|
if (!(sourceValue instanceof Collection<?> collection)) {
|
continue;
|
}
|
List<Long> ids = collection.stream()
|
.map(buildPageRowsUtils::normalizeStringValue)
|
.map(dictIdMap::get)
|
.filter(Objects::nonNull)
|
.toList();
|
if (!ids.isEmpty()) {
|
writeField(record, targetField, ids);
|
}
|
}
|
}
|
|
private static void fillStationNameWithId(List<Object> records, String sourceField, String targetField) {
|
if (Cools.isEmpty(records) || !hasField(records.get(0), targetField)) {
|
return;
|
}
|
Set<String> stationNames = records.stream()
|
.map(record -> normalizeStringValue(readFieldValue(record, sourceField)))
|
.filter(item -> !Cools.isEmpty(item))
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (stationNames.isEmpty()) {
|
return;
|
}
|
List<?> stations = listEntitiesByFieldIn(
|
com.vincent.rsf.server.manager.service.BasStationService.class,
|
com.vincent.rsf.server.manager.entity.BasStation.class,
|
"stationName",
|
stationNames,
|
Collections.emptyMap()
|
);
|
Map<String, String> stationIdMap = new HashMap<>();
|
for (Object station : stations) {
|
String stationName = getStringFieldValue(station, "stationName");
|
String stationId = getStringFieldValue(station, "stationId");
|
if (Cools.isEmpty(stationName) || Cools.isEmpty(stationId)) {
|
continue;
|
}
|
stationIdMap.put(stationName, stationId);
|
}
|
for (Object record : records) {
|
String stationName = normalizeStringValue(readFieldValue(record, sourceField));
|
if (Cools.isEmpty(stationName)) {
|
continue;
|
}
|
String stationId = stationIdMap.get(stationName);
|
writeStringField(record, targetField, Cools.isEmpty(stationId) ? stationName : stationName + "(" + stationId + ")");
|
}
|
}
|
|
private static void fillLocTypeNamesField(List<Object> records) {
|
if (Cools.isEmpty(records) || !hasField(records.get(0), "typeIds$")) {
|
return;
|
}
|
Map<String, List<Long>> parsedIdsByValue = new HashMap<>();
|
Set<Long> allIds = new LinkedHashSet<>();
|
for (Object record : records) {
|
String value = normalizeStringValue(readFieldValue(record, "type"));
|
if (Cools.isEmpty(value)) {
|
continue;
|
}
|
List<Long> ids = parsedIdsByValue.computeIfAbsent(value, buildPageRowsUtils::parseLongIds);
|
allIds.addAll(ids);
|
}
|
if (allIds.isEmpty()) {
|
return;
|
}
|
Map<Long, String> nameMap = loadEntityFieldMap(com.vincent.rsf.server.manager.service.LocTypeService.class, allIds, "name");
|
for (Object record : records) {
|
String value = normalizeStringValue(readFieldValue(record, "type"));
|
List<Long> ids = value == null ? Collections.emptyList() : parsedIdsByValue.getOrDefault(value, Collections.emptyList());
|
if (ids.isEmpty()) {
|
continue;
|
}
|
List<String> names = ids.stream()
|
.map(nameMap::get)
|
.filter(item -> !Cools.isEmpty(item))
|
.toList();
|
if (!names.isEmpty()) {
|
writeStringField(record, "typeIds$", String.join(",", names));
|
}
|
}
|
}
|
|
private static List<Long> parseLongIds(String value) {
|
if (Cools.isEmpty(value)) {
|
return Collections.emptyList();
|
}
|
return Stream.of(value.split(","))
|
.map(String::trim)
|
.filter(item -> !item.isEmpty())
|
.map(item -> {
|
try {
|
return Long.parseLong(item);
|
} catch (NumberFormatException ignored) {
|
return null;
|
}
|
})
|
.filter(Objects::nonNull)
|
.toList();
|
}
|
|
private static String normalizeStringValue(Object value) {
|
if (value == null) {
|
return null;
|
}
|
String stringValue = String.valueOf(value).trim();
|
return stringValue.isEmpty() ? null : stringValue;
|
}
|
|
private static void fillUserRoleIds(List<Object> records) {
|
if (Cools.isEmpty(records) || !hasField(records.get(0), "userRoleIds")) {
|
return;
|
}
|
Set<Long> userIds = records.stream()
|
.map(record -> readLongId(record, "id"))
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (userIds.isEmpty()) {
|
return;
|
}
|
List<?> userRoles = listEntitiesByFieldIn(
|
com.vincent.rsf.server.system.service.UserRoleService.class,
|
com.vincent.rsf.server.system.entity.UserRole.class,
|
"userId",
|
userIds,
|
Collections.emptyMap()
|
);
|
Map<Long, List<Long>> userRoleMap = new HashMap<>();
|
for (Object userRole : userRoles) {
|
Long userId = getLongFieldValue(userRole, "userId");
|
Long roleId = getLongFieldValue(userRole, "roleId");
|
if (userId == null || roleId == null) {
|
continue;
|
}
|
userRoleMap.computeIfAbsent(userId, key -> new ArrayList<>()).add(roleId);
|
}
|
for (Object record : records) {
|
if (!hasField(record, "userRoleIds")) {
|
continue;
|
}
|
Long userId = readLongId(record, "id");
|
List<Long> roleIds = userId == null ? Collections.emptyList() : userRoleMap.getOrDefault(userId, Collections.emptyList());
|
writeField(record, "userRoleIds", roleIds.toArray(Long[]::new));
|
}
|
}
|
|
private static void fillFieldById(List<Object> records, String sourceField, String targetField, Class<?> serviceClass, String returnField) {
|
if (Cools.isEmpty(records) || !hasField(records.get(0), targetField) || !hasField(records.get(0), sourceField)) {
|
return;
|
}
|
Set<Long> ids = records.stream()
|
.map(record -> readLongId(record, sourceField))
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (ids.isEmpty()) {
|
return;
|
}
|
Map<Long, String> valueMap = loadEntityFieldMap(serviceClass, ids, returnField);
|
if (valueMap.isEmpty()) {
|
return;
|
}
|
for (Object record : records) {
|
if (!hasField(record, targetField)) {
|
continue;
|
}
|
writeStringField(record, targetField, valueMap.get(readLongId(record, sourceField)));
|
}
|
}
|
|
private static Map<Long, String> loadEntityFieldMap(Class<?> serviceClass, Set<Long> ids, String returnField) {
|
if (serviceClass == null || Cools.isEmpty(ids) || Cools.isEmpty(returnField)) {
|
return Collections.emptyMap();
|
}
|
IService<?> service = getServiceBean(serviceClass);
|
if (service == null) {
|
return Collections.emptyMap();
|
}
|
List<?> entities = service.listByIds(new ArrayList<>(ids));
|
if (Cools.isEmpty(entities)) {
|
return Collections.emptyMap();
|
}
|
Map<Long, String> valueMap = new HashMap<>();
|
for (Object entity : entities) {
|
Long id = readEntityId(entity);
|
Object value = readFieldValue(entity, returnField);
|
if (id == null || value == null) {
|
continue;
|
}
|
valueMap.put(id, String.valueOf(value));
|
}
|
return valueMap;
|
}
|
|
private static Long readEntityId(Object entity) {
|
if (entity == null) {
|
return null;
|
}
|
Field idField = getCachedIdField(entity.getClass());
|
if (idField != null) {
|
Object value = readFieldValue(entity, idField.getName());
|
if (value instanceof Number number) {
|
return number.longValue();
|
}
|
}
|
return getLongFieldValue(entity, "id");
|
}
|
|
public static String getDictLabel(String dictTypeCode, Object value) {
|
if (Cools.isEmpty(dictTypeCode) || value == null || Cools.isEmpty(String.valueOf(value))) {
|
return null;
|
}
|
Object dictData = getEntityByFields(
|
DictDataService.class,
|
DictData.class,
|
Map.of(
|
"dictTypeCode", dictTypeCode,
|
"value", value
|
)
|
);
|
return getStringFieldValue(dictData, "label");
|
}
|
|
public static String getDictLabelWithValue(String dictTypeCode, Object value) {
|
String label = getDictLabel(dictTypeCode, value);
|
if (label == null || value == null) {
|
return null;
|
}
|
return value + "." + label;
|
}
|
|
public static List<Long> getDictIds(String dictTypeCode, Collection<?> values) {
|
if (Cools.isEmpty(dictTypeCode) || Cools.isEmpty(values)) {
|
return Collections.emptyList();
|
}
|
List<?> dictDataList = listEntitiesByFieldIn(DictDataService.class, DictData.class, "value", values,
|
Map.of("dictTypeCode", dictTypeCode));
|
if (Cools.isEmpty(dictDataList)) {
|
return Collections.emptyList();
|
}
|
return dictDataList.stream()
|
.map(item -> getLongFieldValue(item, "id"))
|
.filter(Objects::nonNull)
|
.toList();
|
}
|
|
private static Long readLongId(Object record, String fieldName) {
|
if (record == null || Cools.isEmpty(fieldName)) {
|
return null;
|
}
|
Field field = getCachedField(record.getClass(), fieldName);
|
if (field == null) {
|
return null;
|
}
|
try {
|
Object value = field.get(record);
|
if (value instanceof Long) {
|
return (Long) value;
|
}
|
if (value instanceof Number) {
|
return ((Number) value).longValue();
|
}
|
if (value instanceof String && !((String) value).trim().isEmpty()) {
|
return Long.parseLong(((String) value).trim());
|
}
|
} catch (IllegalAccessException | NumberFormatException ignored) {
|
return null;
|
}
|
return null;
|
}
|
|
private static Map<Long, String> loadUserNameMap(Set<Long> userIds) {
|
RedisService redisService = getRedisService();
|
return loadNameMap(
|
userIds,
|
userId -> getCachedName(redisService, userId, USER_NAME_CACHE_FLAG),
|
missingUserIds -> SpringUtils.getBean(UserService.class).listByIds(missingUserIds),
|
User::getId,
|
User::getNickname,
|
loadedUserNameMap -> cacheNames(redisService, loadedUserNameMap, USER_NAME_CACHE_FLAG)
|
);
|
}
|
|
private static Map<Long, String> loadWarehouseNameMap(Set<Long> warehouseIds) {
|
RedisService redisService = getRedisService();
|
return loadNameMap(
|
warehouseIds,
|
id -> getCachedName(redisService, id, WAREHOUSE_NAME_CACHE_FLAG),
|
missingIds -> SpringUtils.getBean(WarehouseService.class).listByIds(missingIds),
|
Warehouse::getId,
|
Warehouse::getName,
|
loadedNameMap -> cacheNames(redisService, loadedNameMap, WAREHOUSE_NAME_CACHE_FLAG)
|
);
|
}
|
|
private static Map<Long, String> loadCompanyNameMap(Set<Long> companyIds) {
|
RedisService redisService = getRedisService();
|
return loadNameMap(
|
companyIds,
|
id -> getCachedName(redisService, id, COMPANY_NAME_CACHE_FLAG),
|
missingIds -> SpringUtils.getBean(CompanysService.class).listByIds(missingIds),
|
Companys::getId,
|
Companys::getName,
|
loadedNameMap -> cacheNames(redisService, loadedNameMap, COMPANY_NAME_CACHE_FLAG)
|
);
|
}
|
|
private static Map<String, String> loadDictLabelMap(Set<String> values, String dictTypeCode) {
|
if (Cools.isEmpty(values) || Cools.isEmpty(dictTypeCode)) {
|
return Collections.emptyMap();
|
}
|
List<String> normalizedValues = values.stream()
|
.filter(value -> !Cools.isEmpty(value))
|
.distinct()
|
.toList();
|
if (normalizedValues.isEmpty()) {
|
return Collections.emptyMap();
|
}
|
DictDataService dictDataService;
|
try {
|
dictDataService = SpringUtils.getBean(DictDataService.class);
|
} catch (Exception ignored) {
|
return Collections.emptyMap();
|
}
|
List<DictData> dictDataList = dictDataService.list(
|
new LambdaQueryWrapper<DictData>()
|
.eq(DictData::getDictTypeCode, dictTypeCode)
|
.in(DictData::getValue, normalizedValues)
|
);
|
if (Cools.isEmpty(dictDataList)) {
|
return Collections.emptyMap();
|
}
|
return dictDataList.stream()
|
.filter(Objects::nonNull)
|
.filter(item -> !Cools.isEmpty(item.getValue()) && item.getLabel() != null)
|
.collect(Collectors.toMap(DictData::getValue, DictData::getLabel, (left, right) -> left));
|
}
|
|
private static <E> Map<Long, String> loadNameMap(Set<Long> ids,
|
Function<Long, String> cacheGetter,
|
Function<List<Long>, List<E>> entityLoader,
|
Function<E, Long> idGetter,
|
Function<E, String> nameGetter,
|
Consumer<Map<Long, String>> cacheWriter) {
|
if (Cools.isEmpty(ids)) {
|
return Collections.emptyMap();
|
}
|
List<Long> normalizedIds = ids.stream()
|
.filter(Objects::nonNull)
|
.distinct()
|
.toList();
|
if (normalizedIds.isEmpty()) {
|
return Collections.emptyMap();
|
}
|
Map<Long, String> nameMap = new HashMap<>();
|
List<Long> missingIds = new ArrayList<>();
|
for (Long id : normalizedIds) {
|
String cachedName = cacheGetter.apply(id);
|
if (cachedName == null) {
|
missingIds.add(id);
|
continue;
|
}
|
nameMap.put(id, cachedName);
|
}
|
if (missingIds.isEmpty()) {
|
return nameMap;
|
}
|
List<E> loadedEntities = entityLoader.apply(missingIds);
|
if (loadedEntities == null) {
|
return nameMap;
|
}
|
Map<Long, String> loadedNameMap = loadedEntities.stream()
|
.filter(Objects::nonNull)
|
.filter(item -> idGetter.apply(item) != null && nameGetter.apply(item) != null)
|
.collect(Collectors.toMap(idGetter, nameGetter, (left, right) -> left));
|
nameMap.putAll(loadedNameMap);
|
cacheWriter.accept(loadedNameMap);
|
return nameMap;
|
}
|
|
private static RedisService getRedisService() {
|
try {
|
return SpringUtils.getBean(RedisService.class);
|
} catch (Exception ignored) {
|
return null;
|
}
|
}
|
|
private static IService<?> getServiceBean(Class<?> serviceClass) {
|
try {
|
Object bean = SpringUtils.getBean(serviceClass);
|
return bean instanceof IService<?> iService ? iService : null;
|
} catch (Exception ignored) {
|
return null;
|
}
|
}
|
|
private static Object getEntityByFields(Class<?> serviceClass, Class<?> entityClass, Map<String, Object> conditions) {
|
List<?> entityList = listEntitiesByFields(serviceClass, entityClass, conditions, false);
|
return Cools.isEmpty(entityList) ? null : entityList.get(0);
|
}
|
|
private static List<?> listEntitiesByFieldIn(Class<?> serviceClass,
|
Class<?> entityClass,
|
String matchFieldName,
|
Collection<?> matchValues,
|
Map<String, Object> extraConditions) {
|
if (serviceClass == null || entityClass == null || Cools.isEmpty(matchFieldName) || Cools.isEmpty(matchValues)) {
|
return Collections.emptyList();
|
}
|
IService<?> service = getServiceBean(serviceClass);
|
if (service == null) {
|
return Collections.emptyList();
|
}
|
QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
|
extraConditions.forEach((fieldName, value) -> queryWrapper.eq(resolveColumnName(entityClass, fieldName), value));
|
queryWrapper.in(resolveColumnName(entityClass, matchFieldName), matchValues);
|
return service.list((Wrapper) queryWrapper);
|
}
|
|
private static List<?> listEntitiesByFields(Class<?> serviceClass,
|
Class<?> entityClass,
|
Map<String, Object> conditions,
|
boolean all) {
|
if (serviceClass == null || entityClass == null || Cools.isEmpty(conditions)) {
|
return Collections.emptyList();
|
}
|
IService<?> service = getServiceBean(serviceClass);
|
if (service == null) {
|
return Collections.emptyList();
|
}
|
QueryWrapper<Object> queryWrapper = new QueryWrapper<>();
|
conditions.forEach((fieldName, value) -> queryWrapper.eq(resolveColumnName(entityClass, fieldName), value));
|
if (all) {
|
return service.list((Wrapper) queryWrapper);
|
}
|
Object entity = service.getOne((Wrapper) queryWrapper, false);
|
return entity == null ? Collections.emptyList() : Collections.singletonList(entity);
|
}
|
|
private static String resolveColumnName(Class<?> entityClass, String fieldName) {
|
Field field = getCachedField(entityClass, fieldName);
|
if (field == null) {
|
return camelToSnake(fieldName);
|
}
|
TableId tableId = field.getAnnotation(TableId.class);
|
if (tableId != null && !Cools.isEmpty(tableId.value())) {
|
return stripColumnQuotes(tableId.value());
|
}
|
TableField tableField = field.getAnnotation(TableField.class);
|
if (tableField != null && !Cools.isEmpty(tableField.value())) {
|
return stripColumnQuotes(tableField.value());
|
}
|
return camelToSnake(fieldName);
|
}
|
|
private static String stripColumnQuotes(String column) {
|
return column == null ? null : column.replace("`", "");
|
}
|
|
private static String camelToSnake(String value) {
|
if (Cools.isEmpty(value)) {
|
return value;
|
}
|
StringBuilder builder = new StringBuilder();
|
for (int i = 0; i < value.length(); i++) {
|
char current = value.charAt(i);
|
if (Character.isUpperCase(current)) {
|
if (i > 0) {
|
builder.append('_');
|
}
|
builder.append(Character.toLowerCase(current));
|
} else {
|
builder.append(current);
|
}
|
}
|
return builder.toString();
|
}
|
|
private static String getStringFieldValue(Object entity, String fieldName) {
|
Object value = readFieldValue(entity, fieldName);
|
return value == null ? null : String.valueOf(value);
|
}
|
|
private static Long getLongFieldValue(Object entity, String fieldName) {
|
Object value = readFieldValue(entity, fieldName);
|
if (value instanceof Long longValue) {
|
return longValue;
|
}
|
if (value instanceof Number number) {
|
return number.longValue();
|
}
|
if (value instanceof String stringValue && !stringValue.isBlank()) {
|
try {
|
return Long.parseLong(stringValue.trim());
|
} catch (NumberFormatException ignored) {
|
return null;
|
}
|
}
|
return null;
|
}
|
|
private static Object readFieldValue(Object entity, String fieldName) {
|
if (entity == null || Cools.isEmpty(fieldName)) {
|
return null;
|
}
|
Field field = getCachedField(entity.getClass(), fieldName);
|
if (field == null) {
|
return null;
|
}
|
try {
|
return field.get(entity);
|
} catch (IllegalAccessException ignored) {
|
return null;
|
}
|
}
|
|
private static String getCachedName(RedisService redisService, Long id, String cacheFlag) {
|
if (redisService == null || id == null) {
|
return null;
|
}
|
try {
|
String value = redisService.getValue(cacheFlag, String.valueOf(id));
|
return Cools.isEmpty(value) ? null : value;
|
} catch (Exception ignored) {
|
return null;
|
}
|
}
|
|
private static void cacheNames(RedisService redisService, Map<Long, String> nameMap, String cacheFlag) {
|
if (redisService == null || Cools.isEmpty(nameMap)) {
|
return;
|
}
|
nameMap.forEach((id, name) -> {
|
if (id == null || Cools.isEmpty(name)) {
|
return;
|
}
|
try {
|
redisService.setValue(cacheFlag, String.valueOf(id), name, NAME_CACHE_TTL_SECONDS);
|
} catch (Exception ignored) {
|
}
|
});
|
}
|
|
private static <T> void fillUserNameFields(List<T> records, Map<Long, String> userNameMap) {
|
if (Cools.isEmpty(records) || Cools.isEmpty(userNameMap)) {
|
return;
|
}
|
records.stream()
|
.filter(Objects::nonNull)
|
.forEach(record -> {
|
writeStringField(record, "createBy$", userNameMap.get(readLongId(record, "createBy")));
|
writeStringField(record, "updateBy$", userNameMap.get(readLongId(record, "updateBy")));
|
});
|
}
|
|
private static void writeStringField(Object record, String fieldName, String fieldValue) {
|
if (record == null || Cools.isEmpty(fieldName) || fieldValue == null) {
|
return;
|
}
|
writeField(record, fieldName, fieldValue);
|
}
|
|
private static void writeField(Object record, String fieldName, Object fieldValue) {
|
if (record == null || Cools.isEmpty(fieldName) || fieldValue == null) {
|
return;
|
}
|
Field field = getCachedField(record.getClass(), fieldName);
|
if (field == null) {
|
return;
|
}
|
try {
|
field.set(record, fieldValue);
|
} catch (IllegalAccessException ignored) {
|
}
|
}
|
|
private static Field getCachedField(Class<?> type, String fieldName) {
|
if (type == null || Cools.isEmpty(fieldName)) {
|
return null;
|
}
|
return FIELD_CACHE
|
.computeIfAbsent(type, key -> new ConcurrentHashMap<>())
|
.computeIfAbsent(fieldName, key -> Optional.ofNullable(findField(type, key)))
|
.orElse(null);
|
}
|
|
private static Field getCachedIdField(Class<?> type) {
|
if (type == null) {
|
return null;
|
}
|
return ID_FIELD_CACHE.computeIfAbsent(type, key -> Optional.ofNullable(findIdField(key))).orElse(null);
|
}
|
|
private static Field findField(Class<?> type, String fieldName) {
|
Field field = Cools.getField(type, fieldName);
|
if (field == null) {
|
return null;
|
}
|
try {
|
field.setAccessible(true);
|
} catch (Exception ignored) {
|
}
|
return field;
|
}
|
|
private static Field findIdField(Class<?> type) {
|
for (Class<?> current = type; current != null && !Object.class.equals(current); current = current.getSuperclass()) {
|
for (Field field : current.getDeclaredFields()) {
|
if (field.getAnnotation(TableId.class) == null) {
|
continue;
|
}
|
try {
|
field.setAccessible(true);
|
} catch (Exception ignored) {
|
}
|
return field;
|
}
|
}
|
return findField(type, "id");
|
}
|
|
private static boolean hasField(Object record, String fieldName) {
|
return record != null && !Cools.isEmpty(fieldName) && getCachedField(record.getClass(), fieldName) != null;
|
}
|
|
private record IdFieldMapping(String sourceField, String targetField, Class<?> serviceClass, String returnField) {
|
}
|
}
|