feat: 添加企业文件管理功能及相关任务类

refactor: 重构企业文件验证和移动逻辑

fix: 修复企业合规验证逻辑及路径处理问题

docs: 添加VerifyContext工具类及相关文档

style: 优化代码格式及注释
This commit is contained in:
2025-09-26 19:40:34 +08:00
parent a4db8a1644
commit 510952d72e
28 changed files with 1357 additions and 948 deletions

View File

@@ -72,10 +72,10 @@ public interface WebSocketClientTasker {
webSocketService.withSession(session -> {
try {
session.submitTask(this, locale, args);
holder.addMessage(Level.INFO, "已提交任务到服务器: " + getTaskName());
holder.info("已提交任务到服务器: " + getTaskName());
} catch (JsonProcessingException e) {
String errorMsg = "任务提交失败: " + e.getMessage();
holder.addMessage(Level.SEVERE, errorMsg);
holder.warn(errorMsg);
throw new RuntimeException("任务提交失败: " + e.getMessage(), e);
}
});

View File

@@ -75,10 +75,6 @@ public class CompanyWindowController
@Autowired
private CompanyService companyService;
@Autowired
private CompanyCustomerService companyCustomerService;
@Autowired
private VendorService vendorService;
public BorderPane root;
public TabPane tabPane;
@@ -95,7 +91,7 @@ public class CompanyWindowController
public Tab purchaseBillVoucherTab;
public Tab otherTab;
/*
*/
public TextField nameField;
public TextField shortNameField;
@@ -206,7 +202,8 @@ public class CompanyWindowController
logger.debug("onCustomerTabShown");
}
getLoadedFuture().thenAcceptAsync(company -> {
companyCustomerProperty.set(companyCustomerService.findByCompany(company));
CompanyCustomerVo customerVo = getCachedBean(CompanyCustomerService.class).findByCompany(company);
companyCustomerProperty.set(customerVo);
}).exceptionally(ex -> {
UITools.showExceptionAndWait(ex.getMessage(), ex);
return null;
@@ -242,6 +239,7 @@ public class CompanyWindowController
if (logger.isDebugEnabled()) {
logger.debug("onVendorTabShown company {}", company.getName());
}
VendorService vendorService = getBean(VendorService.class);
companyVendorProperty.set(vendorService.findByCompany(company));
}).exceptionally(ex -> {
UITools.showExceptionAndWait(ex.getMessage(), ex);
@@ -256,6 +254,7 @@ public class CompanyWindowController
CompanyCompositeUpdateTasker task = new CompanyCompositeUpdateTasker();
task.setCompany(getEntity());
UITools.showTaskDialogAndWait("更新企业信息", task, null);
refresh();
}
/**
@@ -266,6 +265,7 @@ public class CompanyWindowController
CompanyVerifyTasker task = new CompanyVerifyTasker();
task.setCompany(company);
UITools.showTaskDialogAndWait("企业合规性验证", task, null);
refresh();
}
public void onCompanyOpenInExplorerAction(ActionEvent event) {
@@ -276,7 +276,7 @@ public class CompanyWindowController
if (!StringUtils.hasText(path)) {
ButtonType buttonType = UITools.showConfirmation("目录未设置", "是否创建目录").join();
if (buttonType == ButtonType.OK) {
if (companyService.makePathAbsent(company)) {
if (companyService.makePathAbsent(company, (level, message) -> setStatus(message))) {
save(company);
}
} else {

View File

@@ -8,7 +8,6 @@ import org.springframework.util.StringUtils;
import com.ecep.contract.controller.company.AbstCompanyBasedTabSkin;
import com.ecep.contract.controller.company.CompanyWindowController;
import com.ecep.contract.model.CompanyOldName;
import com.ecep.contract.service.CompanyOldNameService;
import com.ecep.contract.vo.CompanyOldNameVo;
import com.ecep.contract.vo.CompanyVo;
@@ -23,19 +22,16 @@ import javafx.scene.control.Tab;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.DirectoryChooser;
import javafx.stage.Modality;
import javafx.util.converter.LocalDateStringConverter;
import lombok.Setter;
/**
*
* 公司基础信息标签页皮肤
*/
public class CompanyTabSkinBase
extends AbstCompanyBasedTabSkin
implements TabSkin {
@Setter
private CompanyOldNameService companyOldNameService;
public CompanyTabSkinBase(CompanyWindowController controller) {
super(controller);
@@ -49,7 +45,8 @@ public class CompanyTabSkinBase
@Override
public void initializeTab() {
LocalDateStringConverter localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
LocalDateStringConverter localDateStringConverter = new LocalDateStringConverter(
DateTimeFormatter.ISO_LOCAL_DATE, null);
controller.nameField.textProperty().bind(viewModel.getName());
controller.shortNameField.textProperty().bindBidirectional(viewModel.getShortName());
@@ -70,7 +67,8 @@ public class CompanyTabSkinBase
controller.regAddressField.textProperty().bindBidirectional(viewModel.getRegAddress());
controller.addressField.textProperty().bindBidirectional(viewModel.getAddress());
controller.registeredCapitalField.textProperty().bindBidirectional(viewModel.getRegisteredCapital());
controller.registeredCapitalCurrencyField.textProperty().bindBidirectional(viewModel.getRegisteredCapitalCurrency());
controller.registeredCapitalCurrencyField.textProperty()
.bindBidirectional(viewModel.getRegisteredCapitalCurrency());
controller.legalRepresentativeField.textProperty().bindBidirectional(viewModel.getLegalRepresentative());
controller.operationPeriodBeginField.setConverter(localDateStringConverter);
@@ -89,7 +87,7 @@ public class CompanyTabSkinBase
private void onCompanyPathCreatePathAction(ActionEvent event) {
CompanyVo company = getEntity();
if (getCompanyService().makePathAbsent(company)) {
if (getCompanyService().makePathAbsent(company, ((level, message) -> setStatus(message)))) {
save(company);
} else {
setStatus("目录存在或创建失败");
@@ -97,7 +95,33 @@ public class CompanyTabSkinBase
}
private void onCompanyPathChangePathAction(ActionEvent event) {
DirectoryChooser chooser = new DirectoryChooser();
CompanyVo entity = getEntity();
String path = entity.getPath();
File initialDirectory = null;
// 如果当前已经设置了目录并且路径有效,则设置初始目录为该目录
if (StringUtils.hasText(path)) {
File dir = new File(path);
if (dir.exists()) {
initialDirectory = dir;
}
}
// 如果没有有效的初始目录,则使用基础路径
if (initialDirectory == null) {
initialDirectory = getCompanyService().getBasePath();
}
if (initialDirectory != null) {
chooser.setInitialDirectory(initialDirectory);
}
File newDirectory = chooser.showDialog(getTab().getContent().getScene().getWindow());
if (newDirectory != null) {
entity.setPath(newDirectory.getAbsolutePath());
save(entity);
}
}
private void onCompanyPathSameAsNameAction(ActionEvent event) {
@@ -150,18 +174,16 @@ public class CompanyTabSkinBase
layout.getChildren().addAll(nameField, nameLabel, saveAsOldName, ambiguity, ambiguityLabel);
alert.setContentText("context");
alert.setHeaderText(null);
alert.setTitle("企业更名");
alert.getDialogPane().setContent(layout);
// alert.setResultConverter(param -> {
//
// return null;
// });
// alert.setResultConverter(param -> {
//
// return null;
// });
alert.setOnCloseRequest(dialogEvent -> {
ButtonType buttonType = alert.getResult();
@@ -206,9 +228,6 @@ public class CompanyTabSkinBase
}
private CompanyOldNameService getCompanyOldNameService() {
if (companyOldNameService == null) {
companyOldNameService = getBean(CompanyOldNameService.class);
}
return companyOldNameService;
return getCachedBean(CompanyOldNameService.class);
}
}

View File

@@ -126,18 +126,21 @@ public class CompanyTabSkinContract
contractTabToolBtn1.setOnAction(event -> {
CompletableFuture.runAsync(() -> {
// 计算主合同编号
ContractService contractService = getViewModelService();
for (ContractViewModel model : dataSet) {
ContractVo contract = getViewModelService().findById(model.getId().get());
ContractVo contract = contractService.findById(model.getId().get());
if (contract == null) {
continue;
}
try {
if (getViewModelService().updateParentCode(contract)) {
ContractVo updated = getViewModelService().save(contract);
if (contractService.updateParentCode(contract)) {
ContractVo updated = contractService.save(contract);
model.update(updated);
}
} catch (NoSuchElementException e) {
model.getParentCode().set(e.getMessage());
} catch (Exception e) {
setStatus("计算主合同编号失败 " + e.getMessage());
}
}
});

View File

@@ -6,36 +6,31 @@ import java.time.LocalDate;
import java.util.List;
import java.util.function.Consumer;
import com.ecep.contract.service.CompanyFileTypeService;
import com.ecep.contract.service.ContractFileTypeService;
import com.ecep.contract.vo.CompanyFileTypeLocalVo;
import com.ecep.contract.vo.CompanyFileVo;
import com.ecep.contract.vo.CompanyVo;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.DesktopUtils;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.MyProperties;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.controller.company.AbstCompanyTableTabSkin;
import com.ecep.contract.controller.company.CompanyWindowController;
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
import com.ecep.contract.controller.table.cell.CompanyFilePathTableCell;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyFile;
import com.ecep.contract.model.CompanyFileTypeLocal;
import com.ecep.contract.controller.table.cell.CompanyFileTypeTableCell;
import com.ecep.contract.service.CloudTycService;
import com.ecep.contract.service.CompanyFileService;
import com.ecep.contract.service.CompanyFileTypeService;
import com.ecep.contract.task.CompanyFileMoveTasker;
import com.ecep.contract.task.CompanyFileResetTasker;
import com.ecep.contract.task.CompanyFileRetrieveFromDownloadDirTasker;
import com.ecep.contract.util.FxmlPath;
import com.ecep.contract.util.UITools;
import com.ecep.contract.vm.CompanyFileViewModel;
import com.ecep.contract.vo.CompanyFileVo;
import com.ecep.contract.vo.CompanyVo;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.scene.control.Button;
@@ -53,7 +48,7 @@ public class CompanyTabSkinFile
implements TabSkin, EditableEntityTableTabSkin<CompanyFileVo, CompanyFileViewModel> {
public TableColumn<CompanyFileViewModel, Number> idColumn;
public TableColumn<CompanyFileViewModel, String> typeColumn;
public TableColumn<CompanyFileViewModel, CompanyFileType> typeColumn;
public TableColumn<CompanyFileViewModel, String> filePathColumn;
public TableColumn<CompanyFileViewModel, LocalDate> applyDateColumn;
public TableColumn<CompanyFileViewModel, LocalDate> expiringDateColumn;
@@ -65,9 +60,6 @@ public class CompanyTabSkinFile
public MenuItem fileTable_menu_del;
public MenuItem fileTable_menu_copy_as_matched_by_contract;
private final ObservableMap<CompanyFileType, CompanyFileTypeLocalVo> fileTypeLocalMap = FXCollections
.observableHashMap();
public CompanyTabSkinFile(CompanyWindowController controller) {
super(controller);
setDragAndDrop(true);
@@ -96,10 +88,12 @@ public class CompanyTabSkinFile
idColumn.setCellValueFactory(param -> param.getValue().getId());
typeColumn.setCellValueFactory(param -> Bindings.valueAt(fileTypeLocalMap, param.getValue().getType())
.map(CompanyFileTypeLocalVo::getValue));
typeColumn.setCellValueFactory(param -> param.getValue().getType());
typeColumn.setCellFactory(CompanyFileTypeTableCell.forTableColumn(getCachedBean(CompanyFileTypeService.class)));
filePathColumn.setCellValueFactory(param -> param.getValue().getFilePath());
filePathColumn.setCellFactory(param -> new CompanyFilePathTableCell<>(viewModel.getPath()));
applyDateColumn.setCellValueFactory(param -> param.getValue().getApplyDate());
expiringDateColumn.setCellValueFactory(param -> param.getValue().getExpiringDate());
@@ -107,85 +101,39 @@ public class CompanyTabSkinFile
fileTable_menu_del.setOnAction(this::onTableDeleteAction);
fileTable_menu_copy_as_matched_by_contract.setOnAction(this::onTableCopyAsMatchedByContractAction);
fileTable_menu_copy_as_matched_by_contract.setOnMenuValidation(this::onTableCopyAsMatchedMenuValidation);
fileTypeLocalMap.putAll(getCachedBean(CompanyFileTypeService.class).findAll(getLocale()));
}
private void onTableResetAction(ActionEvent event) {
runAsync(() -> {
if (getViewModelService().reBuildingFiles(getParent(), (level, msg) -> setStatus(msg))) {
loadTableDataSet();
}
});
// 创建本地任务
CompanyFileResetTasker tasker = new CompanyFileResetTasker();
tasker.setCompany(getParent());
UITools.showTaskDialogAndWait("重置公司文件", tasker, null);
if (tasker.isFilesUpdated()) {
loadTableDataSet();
}
}
/**
* 从 下载目录 中查找相关的资质文件
*/
private void onTableRetrieveFromDownloadDirAction(ActionEvent event) {
CompanyVo company = getParent();
MyProperties myProperties = getBean(MyProperties.class);
File dir = myProperties.getDownloadDirectory();
if (!dir.exists()) {
setStatus("下载目录 " + dir.getAbsolutePath() + " 不存在,请检查");
return;
}
setStatus("开始检索 下载 文件夹:" + dir.getAbsolutePath() + "...");
File[] files = dir.listFiles(File::isFile);
if (files == null) {
setStatus("检索 下载 文件夹失败");
return;
}
if (files.length == 0) {
setStatus("下载 文件夹没有文件");
return;
}
setStatus("下载 文件夹中共有文件 " + files.length + " 个文件");
if (getParentService().retrieveFromDownloadFiles(company, files, (level, msg) -> setStatus(msg))) {
// fixed if update
viewModel.update(company);
loadTableDataSet();
}
// 创建本地任务
CompanyFileRetrieveFromDownloadDirTasker tasker = new CompanyFileRetrieveFromDownloadDirTasker();
tasker.setCompany(getEntity());
UITools.showTaskDialogAndWait("从下载目录检索文件", tasker, null);
loadTableDataSet();
}
/**
* 把文件从 老系统中移到 \\10.84.209.8\项目信息\相关方信息 目录中
*/
private void onTableMoveFileAction(ActionEvent event) {
CompanyFileService companyFileService = getCompanyFileService();
CompanyVo company = getParent();
List<CompanyFileVo> list = companyFileService.findByCompany(company);
if (list.isEmpty()) {
return;
}
if (getParentService().makePathAbsent(company)) {
save(company);
}
String path = company.getPath();
if (!StringUtils.hasText(path)) {
setStatus("异常, 企业目录未设置");
return;
}
File companyPath = new File(path);
for (CompanyFileVo companyFile : list) {
String filePath = companyFile.getFilePath();
if (StringUtils.hasText(filePath)) {
File file = new File(filePath);
if (file.exists()) {
if (file.getParentFile().equals(companyPath)) {
continue;
}
File dest = new File(companyPath, file.getName());
if (file.renameTo(dest)) {
companyFile.setFilePath(dest.getAbsolutePath());
companyFileService.save(companyFile);
setStatus(file.getName() + " 移动到 " + companyPath.getName());
}
}
}
// 创建本地任务
CompanyFileMoveTasker tasker = new CompanyFileMoveTasker();
tasker.setCompany(getParent());
UITools.showTaskDialogAndWait("移动公司文件", tasker, null);
if (tasker.isFilesMoved()) {
loadTableDataSet();
}
}
@@ -195,7 +143,6 @@ public class CompanyTabSkinFile
private void onTableCopyAsMatchedByContractAction(ActionEvent event) {
UITools.showDialogAndWait("复制资信评估报告", "按当前评估报告复制一个合同中最匹配的", list -> {
getViewModelService().copyAsMatchedByContract(getParent(), list);
onTableCopyAsMatchedAction_(msg -> {
Platform.runLater(() -> {
list.add(msg);

View File

@@ -0,0 +1,86 @@
package com.ecep.contract.controller.table.cell;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.SpringApp;
import com.ecep.contract.service.CompanyFileTypeService;
import com.ecep.contract.vo.CompanyFileTypeLocalVo;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
/**
* 公司文件类型单元格,用于在表格中显示公司文件类型信息
*/
public class CompanyFileTypeTableCell<T> extends AsyncUpdateTableCell<T, CompanyFileType, CompanyFileTypeLocalVo> {
private CompanyFileTypeService companyFileTypeService;
/**
* 创建一个用于表格列的单元格工厂
*/
public static <T> Callback<TableColumn<T, CompanyFileType>, TableCell<T, CompanyFileType>> forTableColumn(
CompanyFileTypeService service) {
return param -> new CompanyFileTypeTableCell<>(service);
}
public CompanyFileTypeTableCell() {
}
public CompanyFileTypeTableCell(CompanyFileTypeService service) {
setService(service);
}
@Override
protected CompanyFileTypeService getServiceBean() {
if (companyFileTypeService == null) {
companyFileTypeService = SpringApp.getBean(CompanyFileTypeService.class);
}
return companyFileTypeService;
}
@Override
protected CompanyFileTypeLocalVo initialize() {
CompanyFileType item = getItem();
if (item == null) {
return null;
}
return getServiceBean().findByLocaleAndType(com.ecep.contract.Desktop.instance.getActiveEmployee().localeProperty().get(), item);
}
@Override
public String format(CompanyFileTypeLocalVo entity) {
if (entity != null && entity.getValue() != null) {
return entity.getValue();
}
CompanyFileType item = getItem();
if (item != null) {
// 根据枚举值返回对应的中文名称
switch (item) {
case General -> {
return "普通文件";
}
case CreditReport -> {
return "资信评估报告";
}
case BusinessLicense -> {
return "营业执照";
}
case QualificationCertificate -> {
return "资质证书";
}
case CreditInfoPublicityReport -> {
return "企业信用信息公示报告";
}
case OperationCertificate -> {
return "操作证";
}
case FrameworkAgreement -> {
return "框架协议";
}
default -> {
return item.name();
}
}
}
return "未知类型";
}
}

View File

@@ -24,6 +24,7 @@ public class ProxyObjectDeserializerModifier extends BeanDeserializerModifier {
}
@Override
@SuppressWarnings("unchecked")
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
// 检查是否是IdentityEntity的实现类

View File

@@ -48,200 +48,6 @@ public class CompanyFileService extends QueryService<CompanyFileVo, CompanyFileV
Pageable.unpaged()).getContent();
}
public boolean reBuildingFiles(CompanyVo company, MessageHolder holder) {
List<CompanyFileVo> dbFiles = findByCompany(company);
List<CompanyFileVo> retrieveFiles = new ArrayList<>();
boolean modfied = false;
Map<String, CompanyFileVo> map = new HashMap<>();
// 排除掉数据库中重复的
for (CompanyFileVo dbFile : dbFiles) {
String filePath = dbFile.getFilePath();
// 没有文件信息,无效记录,删除
if (!StringUtils.hasText(filePath)) {
delete(dbFile);
modfied = true;
continue;
}
// 目录不存在,删除
File dir = new File(filePath);
if (!dir.exists()) {
delete(dbFile);
modfied = true;
continue;
}
CompanyFileVo old = map.put(filePath, dbFile);
// 目录有重复删除
if (old != null) {
delete(old);
modfied = true;
}
}
Map<String, File> directoryMap = new HashMap<>();
// 公司目录
if (StringUtils.hasText(company.getPath())) {
File dir = new File(company.getPath());
directoryMap.put(company.getName(), dir);
}
// 获取所有曾用名
List<CompanyOldNameVo> oldNames = SpringApp.getBean(CompanyOldNameService.class).findAllByCompany(company);
for (CompanyOldNameVo companyOldName : oldNames) {
String path = companyOldName.getPath();
if (StringUtils.hasText(path)) {
File dir = new File(path);
directoryMap.put(companyOldName.getName(), dir);
}
}
for (Map.Entry<String, File> entry : directoryMap.entrySet()) {
String companyName = entry.getKey();
File dir = entry.getValue();
if (!StringUtils.hasText(companyName)) {
continue;
}
if (dir == null || !dir.exists()) {
continue;
}
File[] files = dir.listFiles();
if (files == null) {
// 文件系统出错或者没有相关文件
continue;
}
for (File file : files) {
// 只处理文件
if (!file.isFile() || FileUtils.isHiddenFile(file)) {
continue;
}
String filePath = file.getAbsolutePath();
if (!map.containsKey(filePath)) {
// 未记录
CompanyFileVo filled = fillFileType(file, holder);
retrieveFiles.add(filled);
}
}
}
holder.info("导入 " + retrieveFiles.size() + " 个文件");
if (retrieveFiles.isEmpty()) {
return modfied;
}
// update db
retrieveFiles.forEach(v -> {
v.setCompanyId(company.getId());
save(v);
});
return true;
}
/**
* 从文件名生成公司文件对象,文件已经存在公司对应的存储目录下
*
* @param file 文件
* @param holder 状态输出
* @return 公司文件对象
*/
private CompanyFileVo fillFileType(File file, MessageHolder holder) {
String fileName = file.getName();
CompanyFileVo companyFile = new CompanyFileVo();
companyFile.setType(CompanyFileType.General);
companyFile.setFilePath(file.getAbsolutePath());
fillApplyDateAndExpiringDateAbsent(file, companyFile);
// 天眼查 基础版企业信用报告
if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_BASIC_REPORT)
|| fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_MAJOR_REPORT)
|| fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_ANALYSIS_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
// 天眼查 企业信用信息公示报告
if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_CREDIT_REPORT)) {
companyFile.setType(CompanyFileType.CreditInfoPublicityReport);
return companyFile;
}
// 集团相关方平台 元素征信 企业征信报告
if (fileName.contains(CloudServiceConstant.RK_VENDOR_NAME)
&& fileName.contains(CloudServiceConstant.RK_ENTERPRISE_CREDIT_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
// 营业执照
if (fileName.contains(CompanyConstant.BUSINESS_LICENSE)) {
companyFile.setType(CompanyFileType.BusinessLicense);
return companyFile;
}
// 其他企业信用报告
if (fileName.contains(CompanyConstant.ENTERPRISE_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
return companyFile;
}
/**
* 补齐有效期
*/
private void fillExpiringDateAbsent(CompanyFileVo file) {
LocalDate expiringDate = file.getExpiringDate();
if (expiringDate == null) {
LocalDate applyDate = file.getApplyDate();
if (applyDate != null) {
expiringDate = applyDate.plusYears(1);
file.setExpiringDate(expiringDate);
}
}
}
private static void fillApplyDateAndExpiringDateAbsent(File file, CompanyFileVo companyFile) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate != null) {
return;
}
String fileName = file.getName();
Pattern pattern = Pattern.compile(MyDateTimeUtils.REGEX_DATE);
Matcher matcher = pattern.matcher(fileName);
while (matcher.find()) {
// 找到第一个日期,记作起始日期
String date = matcher.group();
try {
LocalDate n = LocalDate.parse(date);
companyFile.setApplyDate(n);
// 如果 截至日期未设置,则第二个日期记作截至日期(如有)
LocalDate expiringDate = companyFile.getExpiringDate();
if (expiringDate == null) {
while (matcher.find()) {
date = matcher.group();
try {
n = LocalDate.parse(date);
companyFile.setExpiringDate(n);
break;
} catch (Exception ignored) {
}
}
}
break;
} catch (Exception ignored) {
}
}
}
public void verify(CompanyVo company, LocalDate verifyDate, MessageHolder holder) {
// 查询公司的资信评估报告
List<CompanyFileVo> files = findFileByCompanyAndType(company, CompanyFileType.CreditReport);
@@ -295,197 +101,4 @@ public class CompanyFileService extends QueryService<CompanyFileVo, CompanyFileV
throw new UnsupportedOperationException("Unimplemented method 'copyAsMatchedByContract'");
}
/**
* 移动文件到企业目录下
*
* @param company 企业对象
* @param files 要被移动的文件集合,需要从中选择需要的
* @param holder 状态输出
*/
public boolean retrieveFromDownloadFiles(CompanyVo company, File[] files, MessageHolder holder) {
Map<String, File> map = new HashMap<>();
File home = new File(company.getPath());
map.put(company.getName(), home);
List<CompanyFileVo> retrieveFiles = new ArrayList<>();
List<CompanyOldNameVo> oldNames = SpringApp.getBean(CompanyOldNameService.class).findAllByCompany(company);
// 获取所有曾用名
for (CompanyOldNameVo companyOldName : oldNames) {
String name = companyOldName.getName();
if (!StringUtils.hasText(name)) {
continue;
}
File dir = null;
String path = companyOldName.getPath();
if (StringUtils.hasText(path)) {
dir = new File(path);
}
map.put(name, dir);
}
// 对所有文件进行遍历
for (int i = 0; i < files.length; i++) {
File file = files[i];
// 只处理文件
if (!file.isFile()) {
continue;
}
MessageHolder sub = holder.sub("[" + (i + 1) + "/" + files.length + "]");
String fileName = file.getName();
sub.info(fileName);
for (Map.Entry<String, File> entry : map.entrySet()) {
String companyName = entry.getKey();
// 必须要包含公司名称否则无法区分
if (!fileName.contains(companyName)) {
continue;
}
// 文件存储的目的地目录
File dir = entry.getValue();
if (dir == null) {
dir = home;
}
CompanyFileVo filled = fillDownloadFileType(company, file, companyName, dir, sub);
if (filled != null) {
retrieveFiles.add(filled);
}
}
}
holder.info("导入 " + retrieveFiles.size() + " 个文件");
if (retrieveFiles.isEmpty()) {
return false;
}
// update db
retrieveFiles.forEach(v -> {
v.setCompanyId(company.getId());
save(v);
});
return true;
}
/**
* 从文件名生成公司文件对象
* 文件从下载目录中导入
*
* @param company 公司对象
* @param file 导入的文件对象
* @param companyName 公司名称
* @param destDir 目标目录
* @param holder 状态输出
* @return 生成的公司文件对象如果无法转换则返回null
*/
private CompanyFileVo fillDownloadFileType(CompanyVo company, File file, String companyName, File destDir,
MessageHolder holder) {
String fileName = file.getName();
// 天眼查的报告
// 目前只有 基础版企业信用报告, 企业信用信息公示报告下载保存时的文件名中没有天眼查
if (CloudTycService.isTycReport(fileName)) {
CompanyFileVo companyFile = new CompanyFileVo();
companyFile.setType(CompanyFileType.CreditReport);
fillApplyDateAbsent(file, companyFile);
String destFileName = fileName;
// 重命名 基础版企业信用报告
for (String report : Arrays.asList(
CloudServiceConstant.TYC_ENTERPRISE_ANALYSIS_REPORT,
CloudServiceConstant.TYC_ENTERPRISE_BASIC_REPORT,
CloudServiceConstant.TYC_ENTERPRISE_MAJOR_REPORT)) {
if (fileName.contains(report)) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate == null) {
applyDate = LocalDate.now();
companyFile.setApplyDate(applyDate);
}
String formatted = MyDateTimeUtils.format(applyDate);
String extension = StringUtils.getFilenameExtension(fileName);
destFileName = String.format("%s_%s_%s_%s.%s",
companyName, CloudServiceConstant.TYC_NAME, report, formatted, extension);
}
}
// 重新设置 企业分析报告 未普通文件
// if (fileName.contains(CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT)) {
// companyFile.setType(General);
// }
File dest = new File(destDir, destFileName);
// 移动文件
if (!file.renameTo(dest)) {
// 移动失败时
holder.warn(fileName + " 无法移动到 " + dest.getAbsolutePath());
return null;
}
holder.info(fileName + " 移动到 " + dest.getAbsolutePath());
companyFile.setFilePath(dest.getAbsolutePath());
//
if (companyFile.getExpiringDate() == null) {
if (companyFile.getApplyDate() != null) {
companyFile.setExpiringDate(companyFile.getApplyDate().plusYears(1));
}
}
return companyFile;
}
// 企业信用信息公示报告
if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_CREDIT_REPORT)) {
CompanyFileVo companyFile = new CompanyFileVo();
companyFile.setType(CompanyFileType.CreditInfoPublicityReport);
fillApplyDateAbsent(file, companyFile);
File dest = new File(destDir, fileName);
// 移动文件
if (!file.renameTo(dest)) {
if (dest.exists()) {
// 尝试删除已经存在的文件
if (!dest.delete()) {
holder.warn("覆盖时,无法删除已存在的文件 " + dest.getAbsolutePath());
return null;
}
if (file.renameTo(dest)) {
List<CompanyFileVo> files = findByCompanyAndPath(company, dest.getAbsolutePath());
if (!files.isEmpty()) {
companyFile = files.getFirst();
}
} else {
holder.error(fileName + " 无法覆盖到 " + dest.getAbsolutePath());
return null;
}
} else {
holder.error(fileName + " 无法移动到 " + dest.getAbsolutePath());
return null;
}
}
holder.info(fileName + " 移动到 " + dest.getAbsolutePath());
companyFile.setFilePath(dest.getAbsolutePath());
return companyFile;
}
return null;
}
/**
* 当 ApplyDate 未设置时,尝试使用文件名中包含的日期
*/
private static void fillApplyDateAbsent(File file, CompanyFileVo companyFile) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate != null) {
return;
}
String fileName = file.getName();
// 从文件名中提取日期
LocalDate picked = MyDateTimeUtils.pickLocalDate(fileName);
if (picked != null) {
companyFile.setApplyDate(picked);
}
}
}

View File

@@ -6,7 +6,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.util.StringConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
@@ -16,13 +15,13 @@ import org.springframework.util.StringUtils;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.SpringApp;
import com.ecep.contract.constant.CompanyConstant;
import com.ecep.contract.model.Company;
import com.ecep.contract.util.FileUtils;
import com.ecep.contract.vm.CompanyViewModel;
import com.ecep.contract.vo.CompanyVo;
import javafx.util.StringConverter;
@Service
@CacheConfig(cacheNames = "company")
public class CompanyService extends QueryService<CompanyVo, CompanyViewModel> {
@@ -117,20 +116,22 @@ public class CompanyService extends QueryService<CompanyVo, CompanyViewModel> {
}
}
public boolean makePathAbsent(CompanyVo company) {
public boolean makePathAbsent(CompanyVo company, MessageHolder holder) {
String path = company.getPath();
if (StringUtils.hasText(path)) {
File file = new File(path);
if (file.exists()) {
// holder.error("存储目录已存在,请检查:" + file.getAbsolutePath());
return false;
}
}
File dir = makePath(company);
File dir = makePath(company, holder.sub("父级"));
if (dir == null) {
return false;
}
if (!dir.exists()) {
holder.info("父级目录不存在:" + dir.getAbsolutePath());
return false;
}
company.setPath(dir.getAbsolutePath());
@@ -144,71 +145,39 @@ public class CompanyService extends QueryService<CompanyVo, CompanyViewModel> {
* @param company 要创建的企业对象
* @return 目录
*/
public File makePath(CompanyVo company) {
public File makePath(CompanyVo company, MessageHolder holder) {
File basePath = getBasePath();
if (!basePath.exists()) {
holder.error("存储目录不存在:" + basePath.getAbsolutePath());
return null;
}
String companyName = company.getName();
String district = company.getDistrict();
if (StringUtils.hasText(district)) {
String parentPrefix = FileUtils.getParentPrefixByDistrict(district);
if (parentPrefix != null) {
File parent = new File(basePath, parentPrefix);
if (!parent.exists()) {
if (!parent.mkdir()) {
return null;
}
}
String fileName = FileUtils.escapeFileName(companyName);
File dir = new File(parent, fileName);
if (!dir.exists()) {
if (!dir.mkdir()) {
return null;
}
}
return dir;
if (!StringUtils.hasText(district)) {
holder.error("区域异常:未设置");
return null;
}
String parentPrefix = FileUtils.getParentPrefixByDistrict(district);
if (parentPrefix == null) {
holder.error("区域异常:" + district);
return null;
}
File parent = new File(basePath, parentPrefix);
if (!parent.exists()) {
if (!parent.mkdir()) {
holder.error("创建目录失败:" + parent.getAbsolutePath());
return null;
}
}
return null;
}
/**
* 移动文件到企业目录下
*
* @param company 企业对象
* @param files 要被移动的文件集合,需要从中选择需要的
* @param holder 状态输出
*/
public boolean retrieveFromDownloadFiles(CompanyVo company, File[] files, MessageHolder holder) {
//
boolean companyChanged = makePathAbsent(company);
if (!StringUtils.hasText(company.getPath())) {
// fixed 要退出,需要保存
if (companyChanged) {
save(company);
String fileName = FileUtils.escapeFileName(companyName);
File dir = new File(parent, fileName);
if (!dir.exists()) {
if (!dir.mkdir()) {
holder.error("创建目录失败:" + dir.getAbsolutePath());
return null;
}
holder.error("存储目录未设置,请检查");
return false;
}
File home = new File(company.getPath());
if (!home.exists()) {
// fixed 要退出,需要保存
if (companyChanged) {
company = save(company);
}
holder.error(company.getPath() + " 不存在,无法访问,请检查或者修改");
return false;
}
CompanyFileService fileService = SpringApp.getBean(CompanyFileService.class);
boolean retrieved = fileService.retrieveFromDownloadFiles(company, files, holder);
if (companyChanged) {
save(company);
}
return retrieved;
return dir;
}
@Override

View File

@@ -3,6 +3,7 @@ package com.ecep.contract.service;
import java.io.File;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
@@ -12,17 +13,17 @@ import org.springframework.cache.annotation.Caching;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.constant.ContractConstant;
import com.ecep.contract.util.ContractUtils;
import com.ecep.contract.util.ParamUtils;
import com.ecep.contract.vm.ContractViewModel;
import com.ecep.contract.vo.VendorVo;
import com.ecep.contract.vo.ContractFileVo;
import com.ecep.contract.vo.ContractVo;
import com.ecep.contract.vo.ProjectVo;
import io.micrometer.common.util.StringUtils;
import com.ecep.contract.vo.VendorVo;
@Service
@CacheConfig(cacheNames = "contract")
@@ -69,8 +70,21 @@ public class ContractService extends QueryService<ContractVo, ContractViewModel>
}
public boolean updateParentCode(ContractVo contract) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'updateParentCode'");
String parentCode = ContractUtils.getParentCode(contract.getCode());
if (!StringUtils.hasText(parentCode)) {
return false;
}
// fixed
if (Objects.equals(contract.getParentCode(), parentCode)) {
// 已经相同,跳过
return false;
}
ContractVo parent = findOneByProperty("code", parentCode);
if (parent == null) {
return false;
}
contract.setParentCode(parent.getCode());
return true;
}
@Cacheable(key = "'code-'+#p0")
@@ -105,7 +119,7 @@ public class ContractService extends QueryService<ContractVo, ContractViewModel>
public List<ContractVo> findAllBySaleContract(ContractVo contract) {
String parentCode = contract.getCode();
if (StringUtils.isEmpty(parentCode)) {
if (StringUtils.hasText(parentCode)) {
return List.of();
}
return findAll(ParamUtils.equal("parentCode", parentCode), Pageable.unpaged()).getContent();

View File

@@ -4,7 +4,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.WebSocketClientTasker;
import com.ecep.contract.vo.CompanyVo;
import lombok.Setter;
@@ -12,7 +12,7 @@ import lombok.Setter;
/**
* 合并更新
*/
public class CompanyCompositeUpdateTasker extends Tasker<Object> {
public class CompanyCompositeUpdateTasker extends Tasker<Object> implements WebSocketClientTasker {
private static final Logger logger = LoggerFactory.getLogger(CompanyCompositeUpdateTasker.class);
@Setter
private CompanyVo company;
@@ -20,14 +20,17 @@ public class CompanyCompositeUpdateTasker extends Tasker<Object> {
@Override
protected Object execute(MessageHolder holder) throws Exception {
updateTitle("合并更新 " + company.getName());
return callRemoteTask(holder, getLocale(), company.getId());
}
holder.debug("1. 从 " + CloudServiceConstant.RK_NAME + " 更新...");
updateProgress(0.1, 1);
holder.debug("2. 从 " + CloudServiceConstant.U8_NAME + " 更新...");
updateProgress(0.3, 1);
holder.debug("3. 从 " + CloudServiceConstant.TYC_NAME + " 更新...");
updateProgress(1, 1);
return null;
@Override
public String getTaskName() {
return "CompanyCompositeUpdateTasker";
}
@Override
public void updateProgress(long workDone, long max) {
super.updateProgress(workDone, max);
}
}

View File

@@ -0,0 +1,123 @@
package com.ecep.contract.task;
import java.io.File;
import org.springframework.util.StringUtils;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.service.CompanyFileService;
import com.ecep.contract.service.CompanyService;
import com.ecep.contract.vo.CompanyFileVo;
import com.ecep.contract.vo.CompanyVo;
import lombok.Getter;
import lombok.Setter;
/**
* 公司文件移动任务类
* 用于将文件从老系统中移动到指定的企业目录中
*/
public class CompanyFileMoveTasker extends Tasker<Boolean> {
@Getter
@Setter
private CompanyVo company;
@Getter
private boolean filesMoved = false;
@Override
protected Boolean execute(MessageHolder holder) throws Exception {
updateTitle("移动公司文件");
updateProgress(0, 100);
if (company == null) {
holder.error("公司对象为空");
updateProgress(100, 100);
return false;
}
try {
holder.info("开始移动公司文件:" + company.getName());
updateProgress(10, 100);
// 获取CompanyFileService
CompanyFileService companyFileService = getCachedBean(CompanyFileService.class);
CompanyService companyService = getCachedBean(CompanyService.class);
// 获取公司的所有文件
holder.info("获取公司文件列表...");
java.util.List<CompanyFileVo> list = companyFileService.findByCompany(company);
updateProgress(20, 100);
if (list.isEmpty()) {
holder.info("该公司没有文件需要移动");
updateProgress(100, 100);
return false;
}
holder.info("共有" + list.size() + "个文件需要处理");
// 确保公司目录存在
holder.info("检查并创建公司目录...");
if (companyService.makePathAbsent(company, holder)) {
company = companyService.save(company);
holder.info("公司目录已创建");
}
updateProgress(30, 100);
// 检查公司路径
String path = company.getPath();
if (!StringUtils.hasText(path)) {
holder.error("异常, 企业目录未设置");
updateProgress(100, 100);
return false;
}
File companyPath = new File(path);
int movedCount = 0;
int totalFiles = list.size();
// 逐个处理文件
for (int i = 0; i < list.size(); i++) {
CompanyFileVo companyFile = list.get(i);
String filePath = companyFile.getFilePath();
// 更新进度
updateProgress(30 + (i * 70) / totalFiles, 100);
if (StringUtils.hasText(filePath)) {
File file = new File(filePath);
if (file.exists()) {
if (file.getParentFile().equals(companyPath)) {
holder.info("文件已在目标位置:" + file.getName());
continue;
}
File dest = new File(companyPath, file.getName());
holder.info("移动文件:" + file.getName() + " -> " + companyPath.getName());
if (file.renameTo(dest)) {
companyFile.setFilePath(dest.getAbsolutePath());
companyFileService.save(companyFile);
holder.info("文件移动成功:" + file.getName());
movedCount++;
filesMoved = true;
} else {
holder.warn("文件移动失败:" + file.getName());
}
} else {
holder.warn("文件不存在:" + filePath);
}
}
}
holder.info("文件移动完成,成功移动" + movedCount + "个文件");
updateProgress(100, 100);
return filesMoved;
} catch (Exception e) {
holder.error("文件移动过程中发生错误:" + e.getMessage());
updateProgress(100, 100);
throw e;
}
}
}

View File

@@ -0,0 +1,274 @@
package com.ecep.contract.task;
import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.util.StringUtils;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.constant.CompanyConstant;
import com.ecep.contract.service.CompanyFileService;
import com.ecep.contract.service.CompanyOldNameService;
import com.ecep.contract.util.FileUtils;
import com.ecep.contract.vo.CompanyFileVo;
import com.ecep.contract.vo.CompanyOldNameVo;
import com.ecep.contract.vo.CompanyVo;
import lombok.Getter;
import lombok.Setter;
/**
* 公司文件重置任务类
* 用于本地执行公司文件重置操作不通过WebSocket调用远程服务
*/
public class CompanyFileResetTasker extends Tasker<Boolean> {
@Getter
@Setter
private CompanyVo company;
@Getter
@Setter
private boolean filesUpdated = false;
private CompanyFileService getCompanyFileService() {
return getCachedBean(CompanyFileService.class);
}
private CompanyOldNameService getCompanyOldNameService() {
return getCachedBean(CompanyOldNameService.class);
}
@Override
protected Boolean execute(MessageHolder holder) throws Exception {
updateTitle("重置公司文件");
updateProgress(0, 100);
if (company == null) {
holder.error("公司对象为空");
updateProgress(100, 100);
return false;
}
try {
holder.info("开始重置公司文件:" + company.getName());
updateProgress(10, 100);
boolean result = reBuildingFiles(company, holder);
if (result) {
holder.info("公司文件重置成功");
setFilesUpdated(true);
} else {
holder.info("公司文件重置完成,但没有更新任何文件");
setFilesUpdated(false);
}
updateProgress(100, 100);
return result;
} catch (Exception e) {
holder.error("公司文件重置失败:" + e.getMessage());
updateProgress(100, 100);
throw e;
}
}
public boolean reBuildingFiles(CompanyVo company, MessageHolder holder) {
CompanyFileService companyFileService = getCompanyFileService();
boolean modfied = false;
List<CompanyFileVo> dbFiles = companyFileService.findByCompany(company);
holder.debug("现有 " + dbFiles.size() + " 条文件记录");
Map<String, CompanyFileVo> map = new HashMap<>();
// 排除掉数据库中重复的
for (CompanyFileVo dbFile : dbFiles) {
String filePath = dbFile.getFilePath();
// 没有文件信息,无效记录,删除
if (!StringUtils.hasText(filePath)) {
companyFileService.delete(dbFile);
holder.info("删除无效记录:" + filePath);
modfied = true;
continue;
}
// 目录不存在,删除
File dir = new File(filePath);
if (!dir.exists()) {
companyFileService.delete(dbFile);
holder.info("删除不存在目录记录:" + filePath);
modfied = true;
continue;
}
CompanyFileVo old = map.put(filePath, dbFile);
// 目录有重复删除
if (old != null) {
companyFileService.delete(old);
holder.info("删除重复目录记录:" + filePath);
modfied = true;
}
}
Map<String, File> directoryMap = new HashMap<>();
// 公司目录
if (StringUtils.hasText(company.getPath())) {
File dir = new File(company.getPath());
directoryMap.put(company.getName(), dir);
}
// 获取所有曾用名
List<CompanyOldNameVo> oldNames = getCompanyOldNameService().findAllByCompany(company);
for (CompanyOldNameVo companyOldName : oldNames) {
String path = companyOldName.getPath();
if (StringUtils.hasText(path)) {
File dir = new File(path);
directoryMap.put(companyOldName.getName(), dir);
}
}
for (Map.Entry<String, File> entry : directoryMap.entrySet()) {
String companyName = entry.getKey();
File dir = entry.getValue();
if (!StringUtils.hasText(companyName)) {
continue;
}
if (dir == null || !dir.exists()) {
continue;
}
File[] files = dir.listFiles();
if (files == null) {
// 文件系统出错或者没有相关文件
continue;
}
holder.debug("目录 " + companyName + " 下有 " + files.length + " 个文件");
for (File file : files) {
// 只处理文件
if (!file.isFile() || FileUtils.isHiddenFile(file)) {
continue;
}
String filePath = file.getAbsolutePath();
if (!map.containsKey(filePath)) {
// 未记录
CompanyFileVo filled = fillFileType(file, holder);
filled.setCompanyId(company.getId());
companyFileService.save(filled);
holder.info("导入 " + file.getName() + " ");
modfied = true;
}
}
}
return modfied;
}
/**
* 从文件名生成公司文件对象,文件已经存在公司对应的存储目录下
*
* @param file 文件
* @param holder 状态输出
* @return 公司文件对象
*/
private CompanyFileVo fillFileType(File file, MessageHolder holder) {
String fileName = file.getName();
CompanyFileVo companyFile = new CompanyFileVo();
companyFile.setType(CompanyFileType.General);
companyFile.setFilePath(file.getAbsolutePath());
fillApplyDateAndExpiringDateAbsent(file, companyFile);
// 天眼查 基础版企业信用报告
if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_BASIC_REPORT)
|| fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_MAJOR_REPORT)
|| fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_ANALYSIS_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
// 天眼查 企业信用信息公示报告
if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_CREDIT_REPORT)) {
companyFile.setType(CompanyFileType.CreditInfoPublicityReport);
return companyFile;
}
// 集团相关方平台 元素征信 企业征信报告
if (fileName.contains(CloudServiceConstant.RK_VENDOR_NAME)
&& fileName.contains(CloudServiceConstant.RK_ENTERPRISE_CREDIT_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
// 营业执照
if (fileName.contains(CompanyConstant.BUSINESS_LICENSE)) {
companyFile.setType(CompanyFileType.BusinessLicense);
return companyFile;
}
// 其他企业信用报告
if (fileName.contains(CompanyConstant.ENTERPRISE_REPORT)) {
companyFile.setType(CompanyFileType.CreditReport);
fillExpiringDateAbsent(companyFile);
return companyFile;
}
return companyFile;
}
/**
* 补齐有效期
*/
private void fillExpiringDateAbsent(CompanyFileVo file) {
LocalDate expiringDate = file.getExpiringDate();
if (expiringDate == null) {
LocalDate applyDate = file.getApplyDate();
if (applyDate != null) {
expiringDate = applyDate.plusYears(1);
file.setExpiringDate(expiringDate);
}
}
}
private static void fillApplyDateAndExpiringDateAbsent(File file, CompanyFileVo companyFile) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate != null) {
return;
}
String fileName = file.getName();
Pattern pattern = Pattern.compile(MyDateTimeUtils.REGEX_DATE);
Matcher matcher = pattern.matcher(fileName);
while (matcher.find()) {
// 找到第一个日期,记作起始日期
String date = matcher.group();
try {
LocalDate n = LocalDate.parse(date);
companyFile.setApplyDate(n);
// 如果 截至日期未设置,则第二个日期记作截至日期(如有)
LocalDate expiringDate = companyFile.getExpiringDate();
if (expiringDate == null) {
while (matcher.find()) {
date = matcher.group();
try {
n = LocalDate.parse(date);
companyFile.setExpiringDate(n);
break;
} catch (Exception ignored) {
}
}
}
break;
} catch (Exception ignored) {
}
}
}
}

View File

@@ -0,0 +1,306 @@
package com.ecep.contract.task;
import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.ecep.contract.CompanyFileType;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.MyProperties;
import com.ecep.contract.constant.CloudServiceConstant;
import com.ecep.contract.service.CloudTycService;
import com.ecep.contract.service.CompanyFileService;
import com.ecep.contract.service.CompanyOldNameService;
import com.ecep.contract.vo.CompanyFileVo;
import com.ecep.contract.vo.CompanyOldNameVo;
import com.ecep.contract.vo.CompanyVo;
import lombok.Getter;
import lombok.Setter;
/**
* 从下载目录检索公司文件的本地任务器
* 用于在客户端本地执行从下载目录检索相关资质文件的操作
*/
public class CompanyFileRetrieveFromDownloadDirTasker extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(CompanyFileRetrieveFromDownloadDirTasker.class);
@Getter
@Setter
private CompanyVo company;
@Getter
@Setter
private String downloadDirPath;
@Getter
@Setter
private boolean companyPathChanged = false;
private CompanyFileService getCompanyFileService() {
return getCachedBean(CompanyFileService.class);
}
private CompanyOldNameService getCompanyOldNameService() {
return getCachedBean(CompanyOldNameService.class);
}
@Override
protected Object execute(MessageHolder holder) throws Exception {
updateTitle("从下载目录检索文件");
// 获取下载目录
File dir;
if (StringUtils.hasText(downloadDirPath)) {
dir = new File(downloadDirPath);
} else {
// 如果没有提供下载目录,则使用配置中的
MyProperties myProperties = getBean(MyProperties.class);
dir = myProperties.getDownloadDirectory();
}
// 检查下载目录是否存在
if (!dir.exists()) {
String errorMsg = "下载目录 " + dir.getAbsolutePath() + " 不存在,请检查";
holder.warn(errorMsg);
return false;
}
// 开始检索下载文件夹
holder.info("开始检索 下载 文件夹:" + dir.getAbsolutePath() + "...");
File[] files = dir.listFiles(File::isFile);
// 检查检索是否成功
if (files == null) {
String errorMsg = "检索 下载 文件夹失败";
holder.error(errorMsg);
return false;
}
// 检查文件夹是否有文件
if (files.length == 0) {
String errorMsg = "下载 文件夹没有文件";
holder.info(errorMsg);
return false;
}
// 报告文件夹中的文件数量
holder.info("下载 文件夹中共有文件 " + files.length + " 个文件");
updateProgress(20, 100);
//
companyPathChanged = getCompanyService().makePathAbsent(company, holder);
if (companyPathChanged) {
holder.info("企业目录已创建或更新:" + company.getPath());
company = getCompanyService().save(company);
}
updateProgress(25, 100);
// 检查企业目录是否存在
if (!StringUtils.hasText(company.getPath())) {
holder.error("企业存储目录未设置,请检查");
return false;
}
// 检查企业目录是否存在
File home = new File(company.getPath());
if (!home.exists()) {
holder.error(company.getPath() + " 不存在,无法访问,请检查或者修改");
return false;
}
// 获取所有曾用名
List<CompanyOldNameVo> oldNames = getCompanyOldNameService().findAllByCompany(company);
holder.info("企业曾用名共有 " + oldNames.size() + "");
// 按照 企业名字 移动到对应的曾用名目录
Map<String, File> oldNameOfDir = new HashMap<>();
oldNameOfDir.put(company.getName(), home);
toMap(oldNames, oldNameOfDir);
updateProgress(30, 100);
// 执行文件检索操作
for (int i = 0; i < files.length; i++) {
updateProgress(30 + (i * 50) / files.length, 100);
File file = files[i];
// 只处理文件
if (!file.isFile()) {
continue;
}
MessageHolder sub = holder.sub("[" + (i + 1) + "/" + files.length + "]");
String fileName = file.getName();
for (Map.Entry<String, File> entry : oldNameOfDir.entrySet()) {
String companyName = entry.getKey();
// 必须要包含公司名称否则无法区分
if (!fileName.contains(companyName)) {
sub.debug(fileName);
continue;
}
// 文件存储的目的地目录
File destPath = entry.getValue();
if (destPath == null) {
destPath = home;
}
sub.info(fileName + " -> " + destPath);
CompanyFileVo filled = fillDownloadFileType(company, file, companyName, destPath, sub);
if (filled != null) {
filled.setCompanyId(company.getId());
getCompanyFileService().save(filled);
holder.info("导入 " + fileName + "" + destPath.getAbsolutePath());
}
}
}
updateProgress(100, 100);
return null;
}
void toMap(List<CompanyOldNameVo> oldNames, Map<String, File> oldNameOfDir) {
for (CompanyOldNameVo oldName : oldNames) {
String name = oldName.getName();
if (!StringUtils.hasText(name)) {
continue;
}
File dir = null;
String path = oldName.getPath();
if (StringUtils.hasText(path)) {
dir = new File(path);
}
oldNameOfDir.put(name, dir);
}
}
/**
* 从文件名生成公司文件对象
* 文件从下载目录中导入
*
* @param company 公司对象
* @param file 导入的文件对象
* @param companyName 公司名称
* @param destDir 目标目录
* @param holder 状态输出
* @return 生成的公司文件对象如果无法转换则返回null
*/
private CompanyFileVo fillDownloadFileType(CompanyVo company, File file, String companyName, File destDir,
MessageHolder holder) {
String fileName = file.getName();
// 天眼查的报告
// 目前只有 基础版企业信用报告, 企业信用信息公示报告下载保存时的文件名中没有天眼查
if (CloudTycService.isTycReport(fileName)) {
CompanyFileVo companyFile = new CompanyFileVo();
companyFile.setType(CompanyFileType.CreditReport);
fillApplyDateAbsent(file, companyFile);
String destFileName = fileName;
// 重命名 基础版企业信用报告
for (String report : Arrays.asList(
CloudServiceConstant.TYC_ENTERPRISE_ANALYSIS_REPORT,
CloudServiceConstant.TYC_ENTERPRISE_BASIC_REPORT,
CloudServiceConstant.TYC_ENTERPRISE_MAJOR_REPORT)) {
if (fileName.contains(report)) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate == null) {
applyDate = LocalDate.now();
companyFile.setApplyDate(applyDate);
}
String formatted = MyDateTimeUtils.format(applyDate);
String extension = StringUtils.getFilenameExtension(fileName);
destFileName = String.format("%s_%s_%s_%s.%s",
companyName, CloudServiceConstant.TYC_NAME, report, formatted, extension);
}
}
// 重新设置 企业分析报告 未普通文件
// if (fileName.contains(CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT)) {
// companyFile.setType(General);
// }
File dest = new File(destDir, destFileName);
// 移动文件
if (!file.renameTo(dest)) {
// 移动失败时
holder.warn(fileName + " 无法移动到 " + dest.getAbsolutePath());
return null;
}
holder.info(fileName + " 移动到 " + dest.getAbsolutePath());
companyFile.setFilePath(dest.getAbsolutePath());
//
if (companyFile.getExpiringDate() == null) {
if (companyFile.getApplyDate() != null) {
companyFile.setExpiringDate(companyFile.getApplyDate().plusYears(1));
}
}
return companyFile;
}
// 企业信用信息公示报告
if (fileName.contains(CloudServiceConstant.TYC_ENTERPRISE_CREDIT_REPORT)) {
CompanyFileVo companyFile = new CompanyFileVo();
companyFile.setType(CompanyFileType.CreditInfoPublicityReport);
fillApplyDateAbsent(file, companyFile);
File dest = new File(destDir, fileName);
// 移动文件
if (!file.renameTo(dest)) {
if (dest.exists()) {
// 尝试删除已经存在的文件
if (!dest.delete()) {
holder.warn("覆盖时,无法删除已存在的文件 " + dest.getAbsolutePath());
return null;
}
if (file.renameTo(dest)) {
List<CompanyFileVo> files = getCompanyFileService().findByCompanyAndPath(company,
dest.getAbsolutePath());
if (!files.isEmpty()) {
companyFile = files.getFirst();
}
} else {
holder.error(fileName + " 无法覆盖到 " + dest.getAbsolutePath());
return null;
}
} else {
holder.error(fileName + " 无法移动到 " + dest.getAbsolutePath());
return null;
}
}
holder.info(fileName + " 移动到 " + dest.getAbsolutePath());
companyFile.setFilePath(dest.getAbsolutePath());
return companyFile;
}
return null;
}
/**
* 当 ApplyDate 未设置时,尝试使用文件名中包含的日期
*/
private static void fillApplyDateAbsent(File file, CompanyFileVo companyFile) {
LocalDate applyDate = companyFile.getApplyDate();
if (applyDate != null) {
return;
}
String fileName = file.getName();
// 从文件名中提取日期
LocalDate picked = MyDateTimeUtils.pickLocalDate(fileName);
if (picked != null) {
companyFile.setApplyDate(picked);
}
}
}

View File

@@ -1,20 +1,35 @@
package com.ecep.contract.task;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.WebSocketClientTasker;
import com.ecep.contract.vo.CompanyVo;
import lombok.Getter;
import lombok.Setter;
public class CompanyVerifyTasker extends Tasker<Object> {
public class CompanyVerifyTasker extends Tasker<Object> implements WebSocketClientTasker {
@Getter
@Setter
private CompanyVo company;
@Getter
@Setter
boolean passed = false;
@Override
protected Object execute(MessageHolder holder) throws Exception {
updateTitle("验证企业是否符合合规要求");
return null;
return callRemoteTask(holder, getLocale(), company.getId());
}
@Override
public String getTaskName() {
return "CompanyVerifyTasker";
}
@Override
public void updateProgress(long workDone, long max) {
super.updateProgress(workDone, max);
}
}

View File

@@ -50,7 +50,7 @@ public abstract class Tasker<T> extends Task<T> {
@SuppressWarnings("unchecked")
K bean = (K) cachedMap.get(requiredType);
if (bean == null) {
bean = getBean(requiredType);
bean = SpringApp.getBean(requiredType);
cachedMap.put(requiredType, bean);
}
return bean;