拆分模块
This commit is contained in:
29
client/src/main/java/com/ecep/contract/AppV2.java
Normal file
29
client/src/main/java/com/ecep/contract/AppV2.java
Normal file
@@ -0,0 +1,29 @@
|
||||
package com.ecep.contract;
|
||||
|
||||
import javafx.application.Application;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Created by Administrator on 2017/4/16.
|
||||
*/
|
||||
public class AppV2 {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AppV2.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
Application.launch(Desktop.class, args);
|
||||
done();
|
||||
}
|
||||
|
||||
private static void done() {
|
||||
logger.info("done");
|
||||
try {
|
||||
Desktop.shutdown();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
System.out.println("AppV2.done");
|
||||
}
|
||||
|
||||
public static final String DEFAULT_HOST = "10.84.209.154";
|
||||
}
|
||||
266
client/src/main/java/com/ecep/contract/Desktop.java
Normal file
266
client/src/main/java/com/ecep/contract/Desktop.java
Normal file
@@ -0,0 +1,266 @@
|
||||
package com.ecep.contract;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.controller.LoginWidowController;
|
||||
import com.ecep.contract.task.TaskMonitorCenter;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CurrentEmployee;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.StageStyle;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* JavaFx 应用程序
|
||||
*
|
||||
* @author ecep
|
||||
* Created by ecep on 2017/05/08.
|
||||
*/
|
||||
public class Desktop extends Application {
|
||||
public static final Logger logger = LoggerFactory.getLogger(Desktop.class);
|
||||
public static Desktop instance;
|
||||
|
||||
public static void shutdown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("shutdown");
|
||||
}
|
||||
if (instance != null) {
|
||||
try {
|
||||
instance.stop();
|
||||
} catch (Throwable e) {
|
||||
logger.error("shutdown error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ScheduledExecutorService scheduledExecutorService = null;
|
||||
private final TaskMonitorCenter taskMonitorCenter = new TaskMonitorCenter();
|
||||
|
||||
private final SimpleIntegerProperty sessionId = new SimpleIntegerProperty(0);
|
||||
@Getter
|
||||
private final CurrentEmployee activeEmployee = new CurrentEmployee();
|
||||
|
||||
public void setActiveEmployeeId(int activeEmployeeId) {
|
||||
activeEmployee.getId().set(activeEmployeeId);
|
||||
}
|
||||
|
||||
public int getActiveEmployeeId() {
|
||||
return activeEmployee.getId().get();
|
||||
}
|
||||
|
||||
public int getSessionId() {
|
||||
return sessionId.get();
|
||||
}
|
||||
|
||||
public void setSessionId(int sessionId) {
|
||||
this.sessionId.set(sessionId);
|
||||
}
|
||||
|
||||
public ScheduledExecutorService getExecutorService() {
|
||||
if (scheduledExecutorService == null) {
|
||||
scheduledExecutorService = Executors.newScheduledThreadPool(3);
|
||||
}
|
||||
return scheduledExecutorService;
|
||||
}
|
||||
|
||||
public TaskMonitorCenter getTaskMonitorCenter() {
|
||||
return taskMonitorCenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("start");
|
||||
}
|
||||
if (instance != null) {
|
||||
logger.error("Desktop already started");
|
||||
}
|
||||
instance = this;
|
||||
|
||||
URL resource = getClass().getResource("/ui/start_lamp.fxml");
|
||||
FXMLLoader loader = new FXMLLoader(resource);
|
||||
primaryStage.setTitle("CMS");
|
||||
primaryStage.initStyle(StageStyle.TRANSPARENT);
|
||||
|
||||
Parent root = loader.load();
|
||||
Scene scene = new Scene(root);
|
||||
scene.getStylesheets().add("/ui/start_lamp.css");
|
||||
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setOnShown(e -> {
|
||||
System.out.println("primaryStage#OnShown");
|
||||
});
|
||||
primaryStage.show();
|
||||
System.out.println("Desktop.start -> primaryStage.show()");
|
||||
|
||||
try {
|
||||
startSpringApp(primaryStage, root, loader);
|
||||
} catch (Exception e) {
|
||||
UITools.showExceptionAndWait("启动失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> runAsync(Runnable runnable) {
|
||||
return CompletableFuture.runAsync(runnable, getExecutorService());
|
||||
}
|
||||
|
||||
private void startSpringApp(Stage primaryStage, Parent root, FXMLLoader loader) {
|
||||
System.out.println("Desktop.startSpringApp");
|
||||
// 更新窗口标题
|
||||
Node titleNode = root.lookup("#title");
|
||||
if (titleNode != null) {
|
||||
primaryStage.setTitle(((Text) titleNode).getText());
|
||||
}
|
||||
|
||||
Node lookup = root.lookup("#logBox");
|
||||
if (!(lookup instanceof VBox logBox)) {
|
||||
throw new RuntimeException("启动界面加载失败, #logger 类型错误");
|
||||
}
|
||||
|
||||
ScrollPane logPane = (ScrollPane) root.lookup("#logPane");
|
||||
|
||||
logBox.getChildren().clear();
|
||||
MessageHolder holder = (level, message) -> {
|
||||
Text text = new Text(message);
|
||||
if (Level.WARNING == level) { // warning
|
||||
text.setFill(Color.YELLOW);
|
||||
} else if (Level.SEVERE == level) {// error
|
||||
text.setFill(Color.RED);
|
||||
} else if (Level.FINE == level) { // debug
|
||||
text.setFill(Color.GRAY);
|
||||
} else {
|
||||
text.setFill(Color.WHITE);
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
logBox.getChildren().add(text);
|
||||
logPane.layout();
|
||||
logPane.setVvalue(1.0);
|
||||
});
|
||||
};
|
||||
|
||||
holder.info("启动中,请稍后...");
|
||||
|
||||
runAsync(() -> {
|
||||
try {
|
||||
//
|
||||
holder.info("读取配置文件...");
|
||||
Properties properties = new Properties();
|
||||
File configFile = new File("config.properties");
|
||||
if (configFile.exists()) {
|
||||
holder.debug("读取配置文件 " + configFile.getName() + "...");
|
||||
try (FileInputStream input = new FileInputStream(configFile)) {
|
||||
properties.load(input);
|
||||
holder.info("配置文件读取成功.");
|
||||
} catch (IOException e) {
|
||||
holder.error("读取失败:" + e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
runAsync(() -> {
|
||||
SpringApp.launch(properties, holder);
|
||||
ConfigurableListableBeanFactory beanFactory = SpringApp.context.getBeanFactory();
|
||||
|
||||
beanFactory.registerSingleton("scheduledExecutorService", getExecutorService());
|
||||
beanFactory.registerSingleton("taskMonitorCenter", taskMonitorCenter);
|
||||
});
|
||||
|
||||
try {
|
||||
LoginWidowController controller = new LoginWidowController();
|
||||
controller.setHolder(holder);
|
||||
controller.setPrimaryStage(primaryStage);
|
||||
controller.setProperties(properties);
|
||||
while (true) {
|
||||
controller.tryLogin();
|
||||
break;
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("login in");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
holder.error("登录失败:" + e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
holder.error(e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
System.out.println("Desktop.startSpringApp.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("stop");
|
||||
}
|
||||
CompletableFuture<Void> future = BaseController.shutdown();
|
||||
future.orTimeout(5, TimeUnit.SECONDS);
|
||||
future.exceptionally(e -> {
|
||||
logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
});
|
||||
future.thenRun(() -> {
|
||||
SpringApp.shutdown();
|
||||
try {
|
||||
shutdownExecutorService();
|
||||
super.stop();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("stopped");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void shutdownExecutorService() {
|
||||
List<Runnable> runnableList = scheduledExecutorService.shutdownNow();
|
||||
for (Runnable runnable : runnableList) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("shutdown runnable = {}", runnable);
|
||||
}
|
||||
if (runnable instanceof FutureTask<?> future) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("runnable as future, isCancelled() = {}, isDone() = {}", future.isCancelled(),
|
||||
future.isDone());
|
||||
}
|
||||
if (future.cancel(true)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("runnable as future canceled");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scheduledExecutorService.close();
|
||||
}
|
||||
}
|
||||
76
client/src/main/java/com/ecep/contract/DesktopUtils.java
Normal file
76
client/src/main/java/com/ecep/contract/DesktopUtils.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package com.ecep.contract;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class DesktopUtils {
|
||||
|
||||
/**
|
||||
* 在默认浏览器中打开指定的URL。
|
||||
* <p>
|
||||
* 该函数使用JavaFX的HostServices类来调用系统默认的浏览器,并打开传入的URL。
|
||||
*
|
||||
* @param url 要在浏览器中打开的URL字符串。该参数不能为空,且应为有效的URL格式。
|
||||
*/
|
||||
public static void showInBrowse(String url) {
|
||||
Desktop.instance.getHostServices().showDocument(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在系统的文件资源管理器中打开指定的文件夹。
|
||||
* <p>
|
||||
* 该方法首先尝试使用 java.awt.Desktop API 打开文件夹。如果该 API 不支持,
|
||||
* 则在 Windows 系统中使用 explorer.exe 打开文件夹。
|
||||
*
|
||||
* @param dir 要打开的文件夹对象。如果为 null 或无效路径,可能会抛出异常。
|
||||
* @throws RuntimeException 如果使用 java.awt.Desktop 打开文件夹时发生 IOException,
|
||||
* 则将其包装为 RuntimeException 抛出。
|
||||
*/
|
||||
public static void showInExplorer(File dir) {
|
||||
if (java.awt.Desktop.isDesktopSupported()) {
|
||||
try {
|
||||
java.awt.Desktop.getDesktop().open(dir);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// 在Windows中使用explorer.exe打开文件夹,路径用双引号括起来
|
||||
Process process = Runtime.getRuntime().exec(
|
||||
new String[] { "explorer.exe", "\"" + dir.getAbsolutePath() + "\"" }, null, new File("."));
|
||||
// process.waitFor();
|
||||
} catch (IOException e) {
|
||||
if (Desktop.logger.isDebugEnabled()) {
|
||||
Desktop.logger.debug("Unable open {}", dir.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkAndShowInExplorer(String path, Consumer<String> consumer) {
|
||||
if (!StringUtils.hasText(path)) {
|
||||
consumer.accept("文件/目录为空,无法打开");
|
||||
return;
|
||||
}
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
if (file.isFile()) {
|
||||
consumer.accept("文件 " + file.getAbsolutePath() + " 不存在,请确认");
|
||||
} else {
|
||||
consumer.accept("目录 " + file.getAbsolutePath() + " 不存在,请确认");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
showInExplorer(file);
|
||||
consumer.accept("打开文件/目录 " + path);
|
||||
} catch (Exception e) {
|
||||
consumer.accept("打开文件错误:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
7
client/src/main/java/com/ecep/contract/Main.java
Normal file
7
client/src/main/java/com/ecep/contract/Main.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package com.ecep.contract;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
}
|
||||
}
|
||||
252
client/src/main/java/com/ecep/contract/SpringApp.java
Normal file
252
client/src/main/java/com/ecep/contract/SpringApp.java
Normal file
@@ -0,0 +1,252 @@
|
||||
package com.ecep.contract;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.ConfigurableBootstrapContext;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringApplicationHook;
|
||||
import org.springframework.boot.SpringApplicationRunListener;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
|
||||
import org.springframework.boot.context.metrics.buffering.StartupTimeline;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.metrics.StartupStep;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableAsync
|
||||
@EnableCaching
|
||||
public class SpringApp {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpringApp.class);
|
||||
|
||||
public static SpringApplication application;
|
||||
public static ConfigurableApplicationContext context;
|
||||
|
||||
public static <T> T getBean(Class<T> requiredType) throws BeansException {
|
||||
return context.getBean(requiredType);
|
||||
}
|
||||
|
||||
public static void launch(Properties properties, MessageHolder holder) {
|
||||
application = new SpringApplication(SpringApp.class);
|
||||
BufferingApplicationStartup startup = new BufferingApplicationStartup(2000);
|
||||
application.setApplicationStartup(startup);
|
||||
//
|
||||
holder.debug("应用程序环境准备中...");
|
||||
SpringApplication.withHook(new Hook(holder), () -> {
|
||||
// 动态地注册或修改这些组件和配置
|
||||
application.addBootstrapRegistryInitializer(registry -> {
|
||||
//
|
||||
System.out.println("registry = " + registry);
|
||||
|
||||
});
|
||||
application.addListeners(event -> {
|
||||
logger.debug("SpringApp.launch ApplicationListener, event:{}", event);
|
||||
});
|
||||
|
||||
application.addInitializers(app -> {
|
||||
logger.debug("SpringApp.launch ApplicationContextInitializer");
|
||||
ConfigurableEnvironment environment = app.getEnvironment();
|
||||
logger.debug("environment = {}", environment);
|
||||
PropertySource<?> dynamicProperties = environment.getPropertySources().get("dynamicProperties");
|
||||
if (dynamicProperties != null) {
|
||||
logger.debug("dynamicProperties = {}", dynamicProperties);
|
||||
}
|
||||
environment.getPropertySources().addLast(new PropertiesPropertySource("dynamicProperties", properties));
|
||||
// app.getBeanFactory().registerSingleton("dataSource", dataSource());
|
||||
logger.debug("app = {}", app);
|
||||
});
|
||||
|
||||
startup.start("");
|
||||
context = application.run();
|
||||
logger.debug("SpringApp.launch application.run().");
|
||||
Duration between = Duration.between(startup.getBufferedTimeline().getStartTime(), Instant.now());
|
||||
holder.info("应用程序环境加载完成... " + between);
|
||||
});
|
||||
CompletableFuture.runAsync(() -> {
|
||||
// 在这里调用 startup 性能分析
|
||||
analyzeStartupPerformance(startup);
|
||||
}, Desktop.instance.getExecutorService());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析启动性能数据并输出到日志
|
||||
*/
|
||||
private static void analyzeStartupPerformance(BufferingApplicationStartup startup) {
|
||||
// 获取所有记录的事件
|
||||
StartupTimeline timeline = startup.getBufferedTimeline();
|
||||
if (timeline == null || timeline.getEvents().isEmpty()) {
|
||||
logger.warn("StartupTimeline 为空或没有事件!");
|
||||
return;
|
||||
}
|
||||
logger.info("总共有 {} 个事件", timeline.getEvents().size());
|
||||
|
||||
// 找出与 Bean 初始化相关的步骤
|
||||
timeline.getEvents().stream()
|
||||
.filter(event -> event.getStartupStep().getName().startsWith("spring.beans."))
|
||||
.sorted((a, b) -> Long.compare(b.getDuration().toMillis(), a.getDuration().toMillis()))
|
||||
.limit(30)
|
||||
.forEach(event -> {
|
||||
String name = event.getStartupStep().getName();
|
||||
long duration = event.getDuration().toMillis();
|
||||
logger.info("Bean 初始化阶段: {} - 耗时: {} ms", name, duration);
|
||||
|
||||
for (StartupStep.Tag tag : event.getStartupStep().getTags()) {
|
||||
if ("beanName".equals(tag.getKey())) {
|
||||
logger.info(" └── Bean 名称: {}", tag.getValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static String getMessage(String code, Object[] args, Locale locale) {
|
||||
return context.getMessage(code, args, locale);
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
System.out.println("SpringApp.shutdown");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("shutdown");
|
||||
}
|
||||
if (context != null) {
|
||||
if (context.isRunning()) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isRunning() {
|
||||
return context != null && context.isRunning();
|
||||
}
|
||||
|
||||
static class Hook implements SpringApplicationHook, SpringApplicationRunListener {
|
||||
MessageHolder holder;
|
||||
|
||||
Hook(MessageHolder holder) {
|
||||
this.holder = holder;
|
||||
}
|
||||
|
||||
public void debug(String msg) {
|
||||
holder.debug(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void starting(ConfigurableBootstrapContext bootstrapContext) {
|
||||
logger.debug("Desktop.starting");
|
||||
debug("Spring Application 启动中...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
|
||||
ConfigurableEnvironment environment) {
|
||||
logger.debug("Desktop.environmentPrepared");
|
||||
debug("初始化 Environment 中,请稍后...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextPrepared(ConfigurableApplicationContext context) {
|
||||
logger.debug("Desktop.contextPrepared");
|
||||
debug("Spring Application Context 预处理中,请稍后...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextLoaded(ConfigurableApplicationContext context) {
|
||||
logger.debug("Desktop.contextLoaded");
|
||||
debug("Spring Application Context 初始化完毕,请稍后...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
logger.debug("Desktop.started");
|
||||
debug("Spring Application 启动完毕.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
logger.debug("Desktop.ready");
|
||||
debug("Spring Application ready.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(ConfigurableApplicationContext context, Throwable exception) {
|
||||
logger.error("Desktop.failed", exception);
|
||||
holder.error("Spring Application 启动失败(" + exception.getMessage() + ").");
|
||||
UITools.showExceptionAndWait("启动失败", exception);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpringApplicationRunListener getRunListener(SpringApplication springApplication) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void handleClosedEvent(ContextClosedEvent event) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("handleClosedEvent={}", event);
|
||||
}
|
||||
Desktop.shutdown();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CacheManager cacheManager() {
|
||||
// return new ConcurrentMapCacheManager("myCache");
|
||||
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
|
||||
cacheManager.setAsyncCacheMode(true);
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(
|
||||
DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
|
||||
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(
|
||||
DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
|
||||
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
|
||||
objectMapper.registerModule(javaTimeModule);
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ScheduledExecutorService scheduledExecutorService() {
|
||||
return Desktop.instance.getExecutorService();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.service.ViewModelService;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.stage.WindowEvent;
|
||||
import lombok.Getter;
|
||||
|
||||
public abstract class AbstEntityBasedController<T extends IdentityEntity, TV extends IdentityViewModel<T>, Skin extends ManagerSkin>
|
||||
extends BaseController {
|
||||
|
||||
public TableView<TV> table;
|
||||
|
||||
@Getter
|
||||
private Skin skin;
|
||||
|
||||
protected abstract Skin createDefaultSkin();
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
if (skin == null) {
|
||||
skin = createDefaultSkin();
|
||||
}
|
||||
skin.install();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHiding(WindowEvent windowEvent) {
|
||||
if (skin != null) {
|
||||
skin.dispose();
|
||||
}
|
||||
super.onHiding(windowEvent);
|
||||
}
|
||||
|
||||
public abstract ViewModelService<T, TV> getViewModelService();
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.RefreshableSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.service.ViewModelService;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.BaseViewModel;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.stage.WindowEvent;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public abstract class AbstEntityController<T extends IdentityEntity, TV extends IdentityViewModel<T>>
|
||||
extends BaseController {
|
||||
|
||||
/**
|
||||
* 保存按钮
|
||||
*/
|
||||
public Button saveBtn;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected TV viewModel;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
protected CompletableFuture<T> loadedFuture;
|
||||
private final ObservableList<TabSkin> tabSkins = FXCollections.observableArrayList();
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
Class<?> aClass = getClass();
|
||||
super.onShown(windowEvent);
|
||||
loadedFuture = CompletableFuture.supplyAsync(() -> {
|
||||
T entity = loadEntity();
|
||||
if (entity == null) {
|
||||
// fixed, bind change if new view model create
|
||||
if (viewModel != null) {
|
||||
viewModel.bindListener();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
setStatus();
|
||||
viewModel.update(entity);
|
||||
});
|
||||
viewModel.bindListener();
|
||||
return entity;
|
||||
});
|
||||
|
||||
registerTabSkins();
|
||||
if (saveBtn != null) {
|
||||
saveBtn.disableProperty().bind(createTabSkinChangedBindings().not());
|
||||
saveBtn.setOnAction(event -> saveTabSkins());
|
||||
}
|
||||
|
||||
installTabSkins();
|
||||
}
|
||||
|
||||
protected T loadEntity() {
|
||||
return getViewModelService().findById(viewModel.getId().get());
|
||||
}
|
||||
|
||||
public T getEntity() {
|
||||
return getLoadedFuture().join();
|
||||
}
|
||||
|
||||
protected void setEntity(T entity) {
|
||||
loadedFuture = CompletableFuture.completedFuture(entity);
|
||||
BaseViewModel.updateInFxApplicationThread(entity, viewModel);
|
||||
}
|
||||
|
||||
protected T saveEntity(T entity) {
|
||||
return getViewModelService().save(entity);
|
||||
}
|
||||
|
||||
public T save(T entity) {
|
||||
T saved = saveEntity(entity);
|
||||
setEntity(saved);
|
||||
return saved;
|
||||
}
|
||||
|
||||
protected void registerTabSkins() {
|
||||
}
|
||||
|
||||
protected <K extends AbstEntityBasedTabSkin<?, ?, ?>> K registerTabSkin(Tab tab, Function<Tab, K> func) {
|
||||
K f = func.apply(tab);
|
||||
if (f != null) {
|
||||
tabSkins.add(f);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
protected void installTabSkins() {
|
||||
for (TabSkin tabSkin : tabSkins) {
|
||||
try {
|
||||
tabSkin.install();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(tabSkin + ".install", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveTabSkins() {
|
||||
for (TabSkin tabSkin : tabSkins) {
|
||||
try {
|
||||
tabSkin.save();
|
||||
} catch (Exception e) {
|
||||
UITools.showExceptionAndWait("Tab" + tabSkin.getTab().getText() + " 保存失败,请检查", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TabSkin getTabSkin(Tab tab) {
|
||||
for (TabSkin tabSkin : tabSkins) {
|
||||
if (tabSkin.getTab() == tab) {
|
||||
return tabSkin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BooleanBinding createTabSkinChangedBindings() {
|
||||
return Bindings.createBooleanBinding(() -> {
|
||||
for (TabSkin tabSkin : tabSkins) {
|
||||
if (tabSkin.changeProperty().get()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, tabSkins.stream().map(TabSkin::changeProperty).toArray(BooleanProperty[]::new));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <C> C getTabSkin(Class<C> skinClass) {
|
||||
for (TabSkin tabSkin : tabSkins) {
|
||||
if (tabSkin.getClass().isAssignableFrom(skinClass)) {
|
||||
return (C) tabSkin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onHidden(WindowEvent windowEvent) {
|
||||
if (viewModel != null) {
|
||||
try {
|
||||
viewModel.unBindListener();
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
uninstallTabSkins();
|
||||
super.onHidden(windowEvent);
|
||||
}
|
||||
|
||||
protected void uninstallTabSkins() {
|
||||
tabSkins.forEach(TabSkin::dispose);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新
|
||||
*
|
||||
* @param button 按钮
|
||||
*/
|
||||
public void refreshByButton(Button button) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
button.setDisable(true);
|
||||
refresh().whenComplete((v, ex) -> {
|
||||
button.setDisable(false);
|
||||
if (ex != null) {
|
||||
setStatus(ex.getMessage());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> refresh() {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
T entity = loadEntity();
|
||||
|
||||
Platform.runLater(() -> {
|
||||
setEntity(entity);
|
||||
|
||||
List<RefreshableSkin> list = tabSkins.stream()
|
||||
.filter(v -> v instanceof RefreshableSkin)
|
||||
.map(v -> ((RefreshableSkin) v)).toList();
|
||||
|
||||
if (list.isEmpty()) {
|
||||
future.complete(null);
|
||||
return;
|
||||
}
|
||||
|
||||
CompletableFuture.allOf(list
|
||||
.stream()
|
||||
.map(RefreshableSkin::refresh)
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(CompletableFuture<?>[]::new))
|
||||
.whenComplete((v, ex) -> {
|
||||
if (ex != null) {
|
||||
future.completeExceptionally(ex);
|
||||
} else {
|
||||
future.complete(null);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
public abstract ViewModelService<T, TV> getViewModelService();
|
||||
}
|
||||
@@ -0,0 +1,587 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.controller.table.TableTabSkin;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.service.ViewModelService;
|
||||
import com.ecep.contract.util.TableViewUtils;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Bounds;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyCodeCombination;
|
||||
import javafx.scene.input.KeyCombination;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
|
||||
/**
|
||||
* 实体管理器皮肤
|
||||
* 提供了实体管理器的基本功能,如查询、新增、删除、修改、分页等
|
||||
*
|
||||
* @param <T> Entity 的类型
|
||||
* @param <TV> Entity 对应的ViewModel
|
||||
* @param <SKIN> Skin 的类型
|
||||
* @param <C>
|
||||
*/
|
||||
public abstract class AbstEntityManagerSkin<T extends IdentityEntity, TV extends IdentityViewModel<T>, SKIN extends ManagerSkin, C extends AbstManagerWindowController<T, TV, SKIN>>
|
||||
implements ManagerSkin, TableTabSkin<T, TV>, EditableEntityTableTabSkin<T, TV> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstEntityManagerSkin.class);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected C controller;
|
||||
|
||||
protected CompletableFuture<Void> loadedFuture;
|
||||
protected ObservableList<TV> dataSet = FXCollections.observableArrayList();
|
||||
|
||||
protected PageRequest currentPageable = PageRequest.ofSize(25);
|
||||
protected final SimpleIntegerProperty currentPageNumber = new SimpleIntegerProperty();
|
||||
// 是否允许调整表格高度
|
||||
private boolean allowResize = true;
|
||||
// 记录延时任务信息
|
||||
private ScheduledFuture<?> loadTableDataSetFuture;
|
||||
|
||||
public AbstEntityManagerSkin(C controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableView<TV> getTableView() {
|
||||
return controller.table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(String message, Throwable ex) {
|
||||
if (controller != null) {
|
||||
controller.handleException(message, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(message, ex);
|
||||
}
|
||||
UITools.showExceptionAndWait(message, ex);
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
return controller.getLocale();
|
||||
}
|
||||
|
||||
public void install() {
|
||||
onShown();
|
||||
|
||||
// 注册 F5 和 Ctrl+R 刷新快捷键
|
||||
KeyCodeCombination ctrlRCombination = new KeyCodeCombination(KeyCode.R, KeyCombination.SHORTCUT_DOWN);
|
||||
KeyCodeCombination f5Combination = new KeyCodeCombination(KeyCode.F5);
|
||||
getTableView().addEventHandler(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (ctrlRCombination.match(event) || f5Combination.match(event)) {
|
||||
System.out.println("loadTableDataSetFuture = " + loadTableDataSetFuture);
|
||||
if (loadTableDataSetFuture == null) {
|
||||
loadTableDataSet(false);
|
||||
}
|
||||
event.consume();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onShown() {
|
||||
if (loadedFuture == null) {
|
||||
loadedFuture = runAsync(() -> {
|
||||
Platform.runLater(() -> {
|
||||
getTableView().setItems(dataSet);
|
||||
});
|
||||
initializeSearchBar();
|
||||
initializeTable();
|
||||
initializeFooter();
|
||||
TableView<TV> table = getTableView();
|
||||
// 视图更新时
|
||||
table.layoutBoundsProperty().addListener(this::resizeTable);
|
||||
|
||||
// 启用行编辑功能
|
||||
if (!table.isEditable()) {
|
||||
TableViewUtils.bindDoubleClicked(table, this::onTableRowDoubleClickedAction);
|
||||
}
|
||||
|
||||
if (table.contextMenuProperty().get() == null) {
|
||||
ContextMenu contextMenu = new ContextMenu();
|
||||
createContextMenu(contextMenu);
|
||||
table.setContextMenu(contextMenu);
|
||||
}
|
||||
|
||||
table.setSortPolicy(v -> {
|
||||
if (loadTableDataSetFuture == null) {
|
||||
loadTableDataSet(false);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
loadTableDataSet(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeSearchBar() {
|
||||
if (controller.searchKeyField != null) {
|
||||
controller.searchKeyField.setOnKeyReleased(event -> {
|
||||
if (event.getCode() == KeyCode.ENTER) {
|
||||
controller.searchBtn.fire();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (controller.searchBtn != null) {
|
||||
controller.searchBtn.setOnAction(this::onSearchAction);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeFooter() {
|
||||
currentPageNumber.addListener(this::currentPageNumberListener);
|
||||
|
||||
//
|
||||
controller.currentPageNumberField.textProperty().bindBidirectional(currentPageNumber,
|
||||
new NumberStringConverter());
|
||||
controller.previousPageBtn.setOnAction(event -> {
|
||||
try {
|
||||
currentPageable = currentPageable.previous();
|
||||
loadTableDataSet(true);
|
||||
} catch (Exception e) {
|
||||
logger.warn("previous page error", e);
|
||||
}
|
||||
});
|
||||
controller.nextPageBtn.setOnAction(event -> {
|
||||
try {
|
||||
currentPageable = currentPageable.next();
|
||||
loadTableDataSet(true);
|
||||
} catch (Exception e) {
|
||||
logger.warn("next page error", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void currentPageNumberListener(Object obj, Number old, Number newValue) {
|
||||
int page = newValue.intValue();
|
||||
if (page < 0) {
|
||||
page = 0;
|
||||
}
|
||||
if (currentPageable.getPageNumber() == page) {
|
||||
return;
|
||||
}
|
||||
currentPageable = currentPageable.withPage(page);
|
||||
loadTableDataSet(false);
|
||||
}
|
||||
|
||||
public void onSearchAction(ActionEvent event) {
|
||||
currentPageable = currentPageable.withPage(0);
|
||||
loadTableDataSet(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表格高度重新计算分页的页大小
|
||||
*/
|
||||
private void resizeTable(Object observable, Bounds old, Bounds newBounds) {
|
||||
if (!allowResize) {
|
||||
return;
|
||||
}
|
||||
double tableHeight = newBounds.getHeight();
|
||||
if (tableHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
TableView<TV> table = getTableView();
|
||||
Node lookup = table.lookup("TableRow");
|
||||
if (lookup != null) {
|
||||
double rowHeight = lookup.prefHeight(-1);
|
||||
int rows = (int) Math.round(table.getHeight() / rowHeight) - 1;
|
||||
// 只有当行数变化超过一定阈值时才重新加载数据
|
||||
int currentRows = currentPageable.getPageSize();
|
||||
if (Math.abs(rows - currentRows) <= 2) {
|
||||
return; // 避免微小变化导致频繁刷新
|
||||
}
|
||||
|
||||
int pageNumber = (int) Math.abs(currentPageable.getOffset() / rows);
|
||||
if (currentPageable.getPageNumber() == pageNumber && currentPageable.getPageSize() == rows) {
|
||||
return;
|
||||
}
|
||||
currentPageable = PageRequest.of(pageNumber, rows);
|
||||
loadTableDataSet(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
MenuItem item2 = new MenuItem("刷新");
|
||||
item2.setOnAction(this::onTableRefreshAction);
|
||||
|
||||
contextMenu.getItems().add(item2);
|
||||
|
||||
if (this instanceof EditableEntityTableTabSkin) {
|
||||
MenuItem item1 = new MenuItem("新建");
|
||||
item1.setOnAction(this::onTableCreateNewAction);
|
||||
|
||||
MenuItem item3 = new MenuItem("删除");
|
||||
item3.setOnAction(this::onTableDeleteAction);
|
||||
|
||||
contextMenu.getItems().addAll(item1, item3);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onTableCreateNewAction(ActionEvent event) {
|
||||
TV viewModel = createNewViewModel();
|
||||
dataSet.add(viewModel);
|
||||
}
|
||||
|
||||
protected void onTableRefreshAction(ActionEvent event) {
|
||||
loadTableDataSet(false);
|
||||
}
|
||||
|
||||
protected void onTableDeleteAction(ActionEvent event) {
|
||||
ObservableList<TV> selectedItems = getTableView().getSelectionModel().getSelectedItems();
|
||||
if (selectedItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!UITools.showConfirmDialog("删除行", "确认删除选中的" + selectedItems.size() + "条数据?")) {
|
||||
return;
|
||||
}
|
||||
for (TV selectedItem : new ArrayList<>(selectedItems)) {
|
||||
if (deleteRow(selectedItem)) {
|
||||
dataSet.remove(selectedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理单元格编辑事件
|
||||
*
|
||||
* @param <K>
|
||||
* @param event
|
||||
* @param propGetter
|
||||
*/
|
||||
protected <K> void acceptCellEditEvent(TableColumn.CellEditEvent<TV, K> event,
|
||||
Function<TV, Property<K>> propGetter) {
|
||||
TV row = event.getRowValue();
|
||||
Property<K> property = propGetter.apply(row);
|
||||
property.setValue(event.getNewValue());
|
||||
try {
|
||||
saveRowData(row);
|
||||
} catch (Exception e) {
|
||||
handleException("保存出错", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean deleteRow(TV row) {
|
||||
ViewModelService<T, TV> service = getViewModelService();
|
||||
T entity = service.findById(row.getId().get());
|
||||
if (entity != null) {
|
||||
try {
|
||||
service.delete(entity);
|
||||
return true;
|
||||
} catch (UnsupportedOperationException e) {
|
||||
handleException("删除出错,此操作不支持", e);
|
||||
} catch (Exception e) {
|
||||
handleException("删除出错", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected T createNewEntity(TV row) {
|
||||
ViewModelService<T, TV> service = getViewModelService();
|
||||
if (service != null) {
|
||||
T entity = service.createNewEntity();
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected TV createNewViewModel() {
|
||||
ViewModelService<T, TV> service = getViewModelService();
|
||||
if (service != null) {
|
||||
TV model = service.createNewViewModel();
|
||||
if (model != null) {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void saveRowData(TV row) {
|
||||
ViewModelService<T, TV> service = getViewModelService();
|
||||
if (service == null) {
|
||||
handleException("ViewModelService is null", new RuntimeException());
|
||||
return;
|
||||
}
|
||||
row.saveInFxApplicationThread(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载行数据
|
||||
*
|
||||
* @param row
|
||||
* @return
|
||||
*/
|
||||
public T loadRowData(TV row) {
|
||||
if (row.getId() == null) {
|
||||
return null;
|
||||
}
|
||||
T entity = getViewModelService().findById(row.getId().get());
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除行数据
|
||||
*
|
||||
* @param entity
|
||||
*/
|
||||
public void deleteRowData(T entity) {
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
ViewModelService<T, TV> service = getViewModelService();
|
||||
getViewModelService().delete(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存行数据
|
||||
*
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public T saveRowData(T entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
ViewModelService<T, TV> service = getViewModelService();
|
||||
return getViewModelService().save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadTableDataSet() {
|
||||
loadTableDataSet(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载表格数据
|
||||
* 延时任务未执行前,再次调用此函数时,重新延时
|
||||
*
|
||||
* @param reloadNow 是否立即刷新,立即刷新将直接submit一个任务到 Executor,否则 schedule 一个618毫秒的延时任务
|
||||
*/
|
||||
public void loadTableDataSet(boolean reloadNow) {
|
||||
if (loadTableDataSetFuture != null) {
|
||||
loadTableDataSetFuture.cancel(true);
|
||||
}
|
||||
loadTableDataSetFuture = getExecutorService().schedule(() -> {
|
||||
try {
|
||||
_reloadTableData().thenRun(() -> loadTableDataSetFuture = null).exceptionally(this::handleException);
|
||||
} catch (Exception ex) {
|
||||
handleException("加载表格数据出错", ex);
|
||||
}
|
||||
}, reloadNow ? 0 : 618, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> _reloadTableData() {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
Platform.runLater(() -> {
|
||||
allowResize = false; // 禁用调整
|
||||
dataSet.clear();
|
||||
runAsync(() -> {
|
||||
controller.setStatus("载入中...");
|
||||
List<TV> models = loadTableData();
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
updateTableDataSet(models);
|
||||
allowResize = true; // 恢复调整
|
||||
future.complete(null);
|
||||
} catch (Exception e) {
|
||||
allowResize = true; // 恢复调整
|
||||
future.completeExceptionally(e);
|
||||
}
|
||||
});
|
||||
}).exceptionally(ex -> {
|
||||
future.completeExceptionally(ex);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新表格数据
|
||||
*
|
||||
* @param models
|
||||
*/
|
||||
protected void updateTableDataSet(List<TV> models) {
|
||||
long timeMillis = System.currentTimeMillis();
|
||||
// 清除所有选择状态,避免选择状态混乱
|
||||
if (getTableView() != null && getTableView().getSelectionModel() != null) {
|
||||
getTableView().getSelectionModel().clearSelection();
|
||||
}
|
||||
|
||||
// 先清空再设置新数据,避免数据叠加
|
||||
dataSet.clear();
|
||||
if (models != null) {
|
||||
dataSet.addAll(models);
|
||||
}
|
||||
|
||||
// 强制刷新表格布局
|
||||
if (getTableView() != null) {
|
||||
getTableView().requestLayout();
|
||||
getTableView().refresh();
|
||||
}
|
||||
|
||||
long timeCost = System.currentTimeMillis() - timeMillis;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("update table dataSet cost: {} ms", timeCost);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载表格数据
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected List<TV> loadTableData() {
|
||||
Map<String, Object> params = getSpecification();
|
||||
ViewModelService<T, TV> service = getViewModelService();
|
||||
long timeMillis = System.currentTimeMillis();
|
||||
Page<T> page = service.findAll(params, getPageable());
|
||||
long timeCost = System.currentTimeMillis() - timeMillis;
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("load table data cost: {} ms", timeCost);
|
||||
}
|
||||
if (timeCost > 1000) {
|
||||
controller.setStatus("used " + timeCost + " ms");
|
||||
}
|
||||
updateFooter(page);
|
||||
return page.map(service::from).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取ViewModelService
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected ViewModelService<T, TV> getViewModelService() {
|
||||
ViewModelService<T, TV> service = controller.getViewModelService();
|
||||
if (service == null) {
|
||||
throw new IllegalArgumentException("ViewModelService is null");
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询条件
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> getSpecification() {
|
||||
TextField field = controller.searchKeyField;
|
||||
if (field != null) {
|
||||
return getViewModelService().getSpecification(field.getText());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取查询条件
|
||||
*
|
||||
* @param searchText
|
||||
* @return
|
||||
*/
|
||||
protected Map<String, Object> getSpecification(String searchText) {
|
||||
return getViewModelService().getSpecification(searchText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当表格行被双击时触发
|
||||
*
|
||||
* @param item 被双击的行数据
|
||||
*/
|
||||
protected void onTableRowDoubleClickedAction(TV item) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新页脚
|
||||
*
|
||||
* @param page
|
||||
*/
|
||||
protected void updateFooter(Page<T> page) {
|
||||
Platform.runLater(() -> {
|
||||
controller.previousPageBtn.setDisable(!page.hasPrevious());
|
||||
controller.nextPageBtn.setDisable(!page.hasNext());
|
||||
currentPageNumber.set(page.getNumber());
|
||||
controller.setStatus(
|
||||
(page.getNumber() + 1) + "/" + page.getTotalPages() + " 页, 总 " + page.getTotalElements() + " 条");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表格排序
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<Sort.Order> getTableOrders() {
|
||||
return TableViewUtils.getOrders(getTableView());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表格排序
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Sort getSortByTable() {
|
||||
if (getTableView() == null) {
|
||||
return Sort.unsorted();
|
||||
}
|
||||
return Sort.by(getTableOrders());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分页参数
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Pageable getPageable() {
|
||||
Sort sort = getSortByTable();
|
||||
return currentPageable.withSort(sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示在当前窗口为父窗口的新窗口
|
||||
*
|
||||
* @param <Controller> 控制器类型
|
||||
* @param clz 控制器类
|
||||
* @param model 数据
|
||||
*/
|
||||
protected <Controller extends AbstEntityController<T, TV>> void showInOwner(Class<Controller> clz, TV model) {
|
||||
BaseController.show(clz, model, getTableView().getScene().getWindow());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
public abstract class AbstManagerWindowController<T extends IdentityEntity, TV extends IdentityViewModel<T>, Skin extends ManagerSkin>
|
||||
extends AbstEntityBasedController<T, TV, Skin> {
|
||||
|
||||
// searcher
|
||||
@FXML
|
||||
public TextField searchKeyField;
|
||||
@FXML
|
||||
public Button searchBtn;
|
||||
|
||||
@FXML
|
||||
public HBox footer;
|
||||
// paging
|
||||
@FXML
|
||||
public Button previousPageBtn;
|
||||
@FXML
|
||||
public Button nextPageBtn;
|
||||
@FXML
|
||||
public TextField currentPageNumberField;
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
// fixed fx:include uninitialized issue
|
||||
previousPageBtn = (Button) footer.lookup("#previousPageBtn");
|
||||
nextPageBtn = (Button) footer.lookup("#nextPageBtn");
|
||||
currentPageNumberField = (TextField) footer.lookup("#currentPageNumberField");
|
||||
leftStatusLabel = (Label) footer.lookup("#leftStatusLabel");
|
||||
|
||||
//
|
||||
super.onShown(windowEvent);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.util.FxmlUtils;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.service.EmployeeService;
|
||||
import com.ecep.contract.service.SysConfService;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CurrentEmployee;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import lombok.Getter;
|
||||
|
||||
public class BaseController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BaseController.class);
|
||||
public static HashMap<String, Stage> stages = new HashMap<>();
|
||||
|
||||
public static <T extends BaseController> CompletableFuture<Void> show(Class<T> clz, Window owner) {
|
||||
return show(clz, owner, null);
|
||||
}
|
||||
|
||||
public static <T extends BaseController> CompletableFuture<Void> show(Class<T> clz, Window owner,
|
||||
Consumer<T> consumer) {
|
||||
String key = clz.getName();
|
||||
if (toFront(key)) {
|
||||
return null;
|
||||
}
|
||||
FxmlPath annotation = clz.getAnnotation(FxmlPath.class);
|
||||
if (annotation == null) {
|
||||
throw new RuntimeException("@FxmlPath is required");
|
||||
}
|
||||
|
||||
return FxmlUtils.newLoaderAsyncWithRunLater(annotation.value(), null, loader -> {
|
||||
T controller = loader.getController();
|
||||
if (consumer != null) {
|
||||
consumer.accept(controller);
|
||||
}
|
||||
controller.show(loader, owner, Modality.NONE, key);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K extends IdentityEntity, M extends IdentityViewModel<K>, T extends BaseController> void show(
|
||||
Class<T> clz, M viewModel, Window owner) {
|
||||
String key = getKey(clz, viewModel);
|
||||
if (toFront(key)) {
|
||||
return;
|
||||
}
|
||||
FxmlPath annotation = clz.getAnnotation(FxmlPath.class);
|
||||
if (annotation == null) {
|
||||
throw new RuntimeException("@FxmlPath is required");
|
||||
}
|
||||
|
||||
FxmlUtils.newLoaderAsyncWithRunLater(annotation.value(), null, loader -> {
|
||||
T controller = loader.getController();
|
||||
if (controller instanceof AbstEntityController<?, ?>) {
|
||||
((AbstEntityController<?, M>) controller).setViewModel(viewModel);
|
||||
}
|
||||
controller.show(loader, owner, Modality.NONE, key);
|
||||
});
|
||||
}
|
||||
|
||||
private static <V> String getKey(Class<?> clz, V viewModel) {
|
||||
PropertyDescriptor idProperty = BeanUtils.getPropertyDescriptor(viewModel.getClass(), "id");
|
||||
if (idProperty != null) {
|
||||
Method readMethod = idProperty.getReadMethod();
|
||||
if (readMethod != null) {
|
||||
try {
|
||||
Object object = readMethod.invoke(viewModel);
|
||||
if (object instanceof ObservableValue<?> value) {
|
||||
return clz.getName() + "#" + value.getValue();
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return clz.getName() + "#" + viewModel.hashCode();
|
||||
}
|
||||
|
||||
public static void show(Class<?> clz, String resource, Window owner) {
|
||||
String key = clz.getName();
|
||||
if (toFront(key)) {
|
||||
return;
|
||||
}
|
||||
FxmlUtils.newLoaderAsyncWithRunLater(resource, null, loader -> {
|
||||
BaseController controller = loader.getController();
|
||||
controller.show(loader, owner, Modality.NONE, key);
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean toFront(String key) {
|
||||
Stage stage = stages.get(key);
|
||||
if (stage != null) {
|
||||
stage.toFront();
|
||||
if (!stage.isShowing()) {
|
||||
stage.show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static CompletableFuture<Void> shutdown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("shutdown");
|
||||
}
|
||||
// 关闭所有窗口
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
ArrayList<Stage> list = new ArrayList<>(stages.values());
|
||||
if (list.isEmpty()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("no stage should to close.");
|
||||
}
|
||||
future.complete(null);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("try to close stages {}.", list);
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
for (Stage stage : list) {
|
||||
System.out.println("stage = " + stage);
|
||||
stage.close();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("stage close {}", stage);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("stage close error", e);
|
||||
}
|
||||
future.complete(null);
|
||||
});
|
||||
}
|
||||
return future;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> runAsync(Runnable runnable) {
|
||||
return CompletableFuture.runAsync(runnable, Desktop.instance.getExecutorService())
|
||||
.exceptionally(this::handleException);
|
||||
}
|
||||
|
||||
/**
|
||||
* 窗口标题
|
||||
*/
|
||||
@Getter
|
||||
private final StringProperty title = new SimpleStringProperty("窗口");
|
||||
/**
|
||||
* 窗口是否已经请求关闭
|
||||
*/
|
||||
@Getter
|
||||
private boolean closeRequested = false;
|
||||
/**
|
||||
* 用于管理窗口的Key
|
||||
*/
|
||||
private String stageKey;
|
||||
public Label leftStatusLabel;
|
||||
public Label rightStatusLabel;
|
||||
private Employee currentUser;
|
||||
|
||||
private HashMap<Class<?>, Object> cachedBeans = new HashMap<>();
|
||||
|
||||
public <T> T getBean(Class<T> requiredType) throws BeansException {
|
||||
return SpringApp.getBean(requiredType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getCachedBean(Class<T> requiredType) throws BeansException {
|
||||
Object object = cachedBeans.get(requiredType);
|
||||
if (object == null) {
|
||||
object = getBean(requiredType);
|
||||
cachedBeans.put(requiredType, object);
|
||||
}
|
||||
return (T) object;
|
||||
}
|
||||
|
||||
public SysConfService getConfService() {
|
||||
return getCachedBean(SysConfService.class);
|
||||
}
|
||||
|
||||
public EmployeeService getEmployeeService() {
|
||||
return getCachedBean(EmployeeService.class);
|
||||
}
|
||||
|
||||
public Employee getCurrentUser() {
|
||||
if (currentUser == null) {
|
||||
currentUser = getEmployeeService().findById(Desktop.instance.getActiveEmployeeId());
|
||||
}
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
public CurrentEmployee getCurrentEmployee() {
|
||||
return Desktop.instance.getActiveEmployee();
|
||||
}
|
||||
|
||||
public Locale getLocale() {
|
||||
CurrentEmployee currentEmployee = getCurrentEmployee();
|
||||
if (currentEmployee == null) {
|
||||
return Locale.getDefault();
|
||||
}
|
||||
return currentEmployee.localeProperty().get();
|
||||
}
|
||||
|
||||
public String getMessage(String code, Object... args) {
|
||||
return SpringApp.getMessage(code, args, getLocale());
|
||||
}
|
||||
|
||||
protected void setStatus() {
|
||||
setStatus(Strings.EMPTY);
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
if (leftStatusLabel == null) {
|
||||
return;
|
||||
}
|
||||
Platform.runLater(() -> leftStatusLabel.textProperty().set(status));
|
||||
}
|
||||
|
||||
public void setRightStatus(String status) {
|
||||
if (rightStatusLabel == null) {
|
||||
return;
|
||||
}
|
||||
Platform.runLater(() -> rightStatusLabel.textProperty().set(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* FXML loader 载入时会自动运行此函数
|
||||
*/
|
||||
public void initialize() {
|
||||
|
||||
}
|
||||
|
||||
public void show(Stage stage) {
|
||||
stage.titleProperty().bind(title);
|
||||
stage.setOnShown(this::onShown);
|
||||
stage.setOnShowing(this::onShowing);
|
||||
stage.setOnCloseRequest(this::onCloseRequest);
|
||||
stage.setOnHiding(this::onHiding);
|
||||
stage.setOnHidden(this::onHidden);
|
||||
stage.show();
|
||||
}
|
||||
|
||||
public Stage show(FXMLLoader loader, Window owner, Modality modality) {
|
||||
Scene scene = new Scene(loader.getRoot());
|
||||
Stage stage = new Stage();
|
||||
if (owner != null) {
|
||||
stage.initOwner(owner);
|
||||
stage.initModality(modality);
|
||||
}
|
||||
stage.setScene(scene);
|
||||
show(stage);
|
||||
|
||||
return stage;
|
||||
}
|
||||
|
||||
protected Stage show(FXMLLoader loader, Window window, Modality modality, String stageKey) {
|
||||
Stage stage = show(loader, window, modality);
|
||||
stages.put(stageKey, stage);
|
||||
this.stageKey = stageKey;
|
||||
return stage;
|
||||
}
|
||||
|
||||
public void onShowing(WindowEvent windowEvent) {
|
||||
|
||||
}
|
||||
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
setStatus("");
|
||||
setRightStatus("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当窗口要关闭前
|
||||
*
|
||||
* @param windowEvent event
|
||||
*/
|
||||
public void onCloseRequest(WindowEvent windowEvent) {
|
||||
closeRequested = true;
|
||||
}
|
||||
|
||||
public void onHiding(WindowEvent windowEvent) {
|
||||
|
||||
}
|
||||
|
||||
public void onHidden(WindowEvent windowEvent) {
|
||||
if (stageKey != null) {
|
||||
stages.remove(stageKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理错误
|
||||
*
|
||||
* @param ex 错误信息
|
||||
* @return Void
|
||||
*/
|
||||
public Void handleException(Throwable ex) {
|
||||
handleException(ex.getMessage(), ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
public void handleException(String message, Throwable ex) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(message, ex);
|
||||
}
|
||||
UITools.showExceptionAndWait(message, ex);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.controller.company.CompanyWindowController;
|
||||
import com.ecep.contract.controller.table.cell.CompanyTableCell;
|
||||
import com.ecep.contract.controller.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.model.CloudRk;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.service.CloudRkService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.vm.CloudRkViewModel;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import lombok.Setter;
|
||||
|
||||
public class CloudRkManagerSkin
|
||||
extends AbstEntityManagerSkin<CloudRk, CloudRkViewModel, CloudRkManagerSkin, CloudRkManagerWindowController> {
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
|
||||
public CloudRkManagerSkin(CloudRkManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
CloudRkService getCloudRkService() {
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
|
||||
CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = SpringApp.getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
controller.companyColumn.setCellValueFactory(param -> param.getValue().getCompany());
|
||||
controller.companyColumn.setCellFactory(param -> new CompanyTableCell<>(getCompanyService()));
|
||||
|
||||
controller.cloudIdColumn.setCellValueFactory(param -> param.getValue().getCloudId());
|
||||
|
||||
controller.latestUpdateColumn.setCellValueFactory(param -> param.getValue().getLatestUpdate());
|
||||
controller.latestUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.cloudLatestColumn.setCellValueFactory(param -> param.getValue().getCloudLatest());
|
||||
controller.cloudLatestColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.cloudBlackListUpdatedColumn
|
||||
.setCellValueFactory(param -> param.getValue().getCloudBlackListUpdated());
|
||||
controller.cloudBlackListUpdatedColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.cloudEntUpdateColumn.setCellValueFactory(param -> param.getValue().getCloudEntUpdate());
|
||||
controller.cloudEntUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.autoUpdateColumn.setCellValueFactory(param -> param.getValue().getAutoUpdate());
|
||||
controller.autoUpdateColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.autoUpdateColumn));
|
||||
|
||||
controller.descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
|
||||
}
|
||||
|
||||
private void onAutoUpdateColumnEditCommit(TableColumn.CellEditEvent<CloudRkViewModel, Boolean> event) {
|
||||
CloudRkViewModel row = event.getRowValue();
|
||||
row.getAutoUpdate().set(event.getNewValue());
|
||||
saveRowData(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
MenuItem item2 = new MenuItem("刷新");
|
||||
item2.setOnAction(this::onTableRefreshAction);
|
||||
|
||||
MenuItem item3 = new MenuItem("清空备注");
|
||||
item3.setOnAction(this::onTableClearDescriptionAction);
|
||||
|
||||
contextMenu.getItems().addAll(item2, item3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请空选择行的注释
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
public void onTableClearDescriptionAction(ActionEvent event) {
|
||||
ObservableList<CloudRkViewModel> selectedItems = getTableView().getSelectionModel().getSelectedItems();
|
||||
if (selectedItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
CloudRkService service = getCloudRkService();
|
||||
for (CloudRkViewModel selectedItem : selectedItems) {
|
||||
selectedItem.getDescription().set("");
|
||||
selectedItem.saveInFxApplicationThread(service);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CloudRkViewModel item) {
|
||||
Company company = item.getCompany().get();
|
||||
if (!Hibernate.isInitialized(item)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
}
|
||||
CompanyWindowController.show(company, getTableView().getScene().getWindow());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.Message;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.model.CloudRk;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.service.CloudRkService;
|
||||
import com.ecep.contract.task.CloudRkSyncTask;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CloudRkViewModel;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/cloud/rk_manager.fxml")
|
||||
public class CloudRkManagerWindowController
|
||||
extends AbstManagerWindowController<CloudRk, CloudRkViewModel, CloudRkManagerSkin> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CloudRkManagerWindowController.class);
|
||||
|
||||
public static void show() {
|
||||
show(CloudRkManagerWindowController.class, null);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CloudRkService cloudRkService;
|
||||
|
||||
public TableColumn<CloudRkViewModel, Number> idColumn;
|
||||
public TableColumn<CloudRkViewModel, LocalDateTime> latestUpdateColumn;
|
||||
|
||||
public TableColumn<CloudRkViewModel, Company> companyColumn;
|
||||
public TableColumn<CloudRkViewModel, String> cloudIdColumn;
|
||||
public TableColumn<CloudRkViewModel, LocalDateTime> cloudLatestColumn;
|
||||
public TableColumn<CloudRkViewModel, LocalDateTime> cloudBlackListUpdatedColumn;
|
||||
public TableColumn<CloudRkViewModel, LocalDateTime> cloudEntUpdateColumn;
|
||||
public TableColumn<CloudRkViewModel, Boolean> autoUpdateColumn;
|
||||
public TableColumn<CloudRkViewModel, String> descriptionColumn;
|
||||
|
||||
@Override
|
||||
protected CloudRkManagerSkin createDefaultSkin() {
|
||||
return new CloudRkManagerSkin(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().set("数据源:集团相关方");
|
||||
}
|
||||
|
||||
private void initializeTask(Task<Object> task, String prefix, Consumer<String> consumer) {
|
||||
task.setOnScheduled(e -> {
|
||||
consumer.accept("正在从相关方平台同步" + prefix + ",请稍后...");
|
||||
});
|
||||
task.setOnRunning(e -> {
|
||||
consumer.accept("开始" + prefix + "...");
|
||||
});
|
||||
task.setOnSucceeded(e -> {
|
||||
consumer.accept(prefix + "完成...");
|
||||
});
|
||||
task.exceptionProperty().addListener((observable, oldValue, newValue) -> {
|
||||
consumer.accept(newValue.getMessage());
|
||||
logger.error("{} 发生异常", prefix, newValue);
|
||||
});
|
||||
SpringApp.getBean(ScheduledExecutorService.class).submit(task);
|
||||
consumer.accept("任务已创建...");
|
||||
}
|
||||
|
||||
public void onDataRepairAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
public void onSyncAction(ActionEvent event) {
|
||||
CloudRkSyncTask task = new CloudRkSyncTask();
|
||||
UITools.showTaskDialogAndWait("同步数据", task, consumer -> {
|
||||
initializeTask(task, "同步数据", msg -> consumer.accept(Message.info(msg)));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloudRkService getViewModelService() {
|
||||
return cloudRkService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.cloud.tyc.CloudTycService;
|
||||
import com.ecep.contract.controller.company.CompanyWindowController;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.model.CloudTyc;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.ui.table.cell.CompanyTableCell;
|
||||
import com.ecep.contract.ui.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.vm.CloudTycInfoViewModel;
|
||||
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import lombok.Setter;
|
||||
|
||||
public class CloudTycManagerSkin
|
||||
extends
|
||||
AbstEntityManagerSkin<CloudTyc, CloudTycInfoViewModel, CloudTycManagerSkin, CloudTycManagerWindowController> {
|
||||
@Setter
|
||||
private CloudTycService cloudTycService;
|
||||
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
|
||||
public CloudTycManagerSkin(CloudTycManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
CloudTycService getCloudTycService() {
|
||||
if (cloudTycService == null) {
|
||||
cloudTycService = getBean(CloudTycService.class);
|
||||
}
|
||||
return cloudTycService;
|
||||
}
|
||||
|
||||
CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = SpringApp.getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<CloudTycInfoViewModel> loadTableData() {
|
||||
String searchText = controller.searchKeyField.getText();
|
||||
Specification<CloudTyc> spec = null;
|
||||
if (StringUtils.hasText(searchText)) {
|
||||
|
||||
Specification<CloudTyc> companySpec = (root, query, builder) -> {
|
||||
Path<Object> company = root.get("company");
|
||||
return builder.or(
|
||||
builder.like(company.get("name"), "%" + searchText + "%"),
|
||||
builder.like(company.get("shortName"), "%" + searchText + "%"));
|
||||
};
|
||||
|
||||
Specification<CloudTyc> cloudIdSpec = (root, query, builder) -> {
|
||||
return builder.like(root.get("cloudId"), "%" + searchText + "%");
|
||||
};
|
||||
|
||||
spec = Specification.anyOf(companySpec, cloudIdSpec);
|
||||
}
|
||||
|
||||
Page<CloudTyc> page = getCloudTycService().findAll(spec, getPageable());
|
||||
updateFooter(page);
|
||||
return page.map(CloudTycInfoViewModel::from).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
controller.companyColumn.setCellValueFactory(param -> param.getValue().getCompany());
|
||||
controller.companyColumn.setCellFactory(param -> new CompanyTableCell<>(getCompanyService()));
|
||||
|
||||
controller.cloudIdColumn.setCellValueFactory(param -> param.getValue().getCloudId());
|
||||
|
||||
controller.latestUpdateColumn.setCellValueFactory(param -> param.getValue().getLatest());
|
||||
controller.latestUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.cloudLatestColumn.setCellValueFactory(param -> param.getValue().getCloudLatest());
|
||||
controller.cloudLatestColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.scoreColumn.setCellValueFactory(param -> param.getValue().getScore());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
MenuItem item2 = new MenuItem("刷新");
|
||||
item2.setOnAction(this::onTableRefreshAction);
|
||||
|
||||
MenuItem item3 = new MenuItem("清空备注");
|
||||
item3.setOnAction(this::onTableClearDescriptionAction);
|
||||
|
||||
contextMenu.getItems().addAll(item2, item3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请空选择行的注释
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
public void onTableClearDescriptionAction(ActionEvent event) {
|
||||
ObservableList<CloudTycInfoViewModel> selectedItems = getTableView().getSelectionModel().getSelectedItems();
|
||||
if (selectedItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (CloudTycInfoViewModel selectedItem : selectedItems) {
|
||||
CloudTyc cloudTyc = getCloudTycService().findById(selectedItem.getId().get());
|
||||
// selectedItem.getDescription().set("");
|
||||
if (selectedItem.copyTo(cloudTyc)) {
|
||||
CloudTyc saved = getCloudTycService().save(cloudTyc);
|
||||
selectedItem.update(saved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CloudTycInfoViewModel item) {
|
||||
Company company = item.getCompany().get();
|
||||
if (!Hibernate.isInitialized(item)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
}
|
||||
CompanyWindowController.show(company, getTableView().getScene().getWindow());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.cloud.CloudBaseInfo;
|
||||
import com.ecep.contract.cloud.CloudInfo;
|
||||
import com.ecep.contract.cloud.tyc.CloudTycService;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.model.CloudTyc;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.vm.CloudTycInfoViewModel;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* 天眼查信息管理窗口控制器
|
||||
*/
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/cloud/tyc_manager.fxml")
|
||||
public class CloudTycManagerWindowController
|
||||
extends AbstManagerWindowController<CloudTyc, CloudTycInfoViewModel, CloudTycManagerSkin> {
|
||||
|
||||
public static void show() {
|
||||
show(CloudTycManagerWindowController.class, null);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CloudTycService cloudTycService;
|
||||
|
||||
@Autowired
|
||||
private CompanyService companyService;
|
||||
|
||||
@FXML
|
||||
public TableColumn<CloudTycInfoViewModel, Number> idColumn;
|
||||
@FXML
|
||||
public TableColumn<CloudTycInfoViewModel, LocalDateTime> latestUpdateColumn;
|
||||
|
||||
@FXML
|
||||
public TableColumn<CloudTycInfoViewModel, Company> companyColumn;
|
||||
@FXML
|
||||
public TableColumn<CloudTycInfoViewModel, String> cloudIdColumn;
|
||||
@FXML
|
||||
public TableColumn<CloudTycInfoViewModel, LocalDateTime> cloudLatestColumn;
|
||||
@FXML
|
||||
public TableColumn<CloudTycInfoViewModel, Number> scoreColumn;
|
||||
|
||||
@FXML
|
||||
public TableColumn<CloudTycInfoViewModel, String> descriptionColumn;
|
||||
|
||||
@Override
|
||||
public CloudTycService getViewModelService() {
|
||||
return cloudTycService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CloudTycManagerSkin createDefaultSkin() {
|
||||
return new CloudTycManagerSkin(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("数据源:天眼查");
|
||||
}
|
||||
|
||||
boolean copyTo(CloudInfo v, CloudBaseInfo cloudRk) {
|
||||
boolean modified = false;
|
||||
if (!Objects.equals(cloudRk.getLatestUpdate(), v.getLatestUpdate())) {
|
||||
cloudRk.setLatestUpdate(v.getLatestUpdate());
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (!Objects.equals(cloudRk.getCloudId(), v.getCloudId())) {
|
||||
cloudRk.setCloudId(v.getCloudId());
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (!Objects.equals(cloudRk.getCompany(), v.getCompany())) {
|
||||
cloudRk.setCompany(v.getCompany());
|
||||
modified = true;
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.model.BaseEnumEntity;
|
||||
import com.ecep.contract.model.BasedEntity;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.model.NamedEntity;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ListCell;
|
||||
|
||||
public class ComboBoxUtils {
|
||||
|
||||
static String formatEntity(Object t) {
|
||||
if (t == null) {
|
||||
return "全部";
|
||||
}
|
||||
if (t instanceof BasedEntity e) {
|
||||
return e.toPrettyString();
|
||||
}
|
||||
if (t instanceof BaseEnumEntity<?> e) {
|
||||
return e.getValue();
|
||||
}
|
||||
if (t instanceof NamedEntity named) {
|
||||
return named.getName();
|
||||
}
|
||||
return t.toString();
|
||||
}
|
||||
|
||||
static <T> T fromString(List<T> dataset, String string) {
|
||||
if (dataset == null) {
|
||||
// 没办法识别
|
||||
return null;
|
||||
}
|
||||
if (!StringUtils.hasText(string)) {
|
||||
// 没办法识别
|
||||
return null;
|
||||
}
|
||||
for (T t : dataset) {
|
||||
if (t == null) {
|
||||
continue;
|
||||
}
|
||||
if (t instanceof BasedEntity e) {
|
||||
if (e.toPrettyString().equals(string)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if (t instanceof BaseEnumEntity<?> e) {
|
||||
if (e.getValue().equals(string)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if (t instanceof NamedEntity named) {
|
||||
if (named.getName().equals(string)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if (t.toString().equals(string)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static
|
||||
class ComboBoxStringConverter<T> extends javafx.util.StringConverter<T> {
|
||||
private final List<T> dataset;
|
||||
|
||||
public ComboBoxStringConverter(ObservableList<T> list) {
|
||||
dataset = list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(T t) {
|
||||
return formatEntity(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T fromString(String string) {
|
||||
return ComboBoxUtils.fromString(dataset, string);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void initialComboBox(ComboBox<T> comboBox, List<T> items, boolean hasNull) {
|
||||
ObservableList<T> list = FXCollections.observableArrayList();
|
||||
if (hasNull) {
|
||||
list.add(null);
|
||||
}
|
||||
list.addAll(items);
|
||||
|
||||
comboBox.setItems(list);
|
||||
comboBox.setConverter(new ComboBoxStringConverter<>(list));
|
||||
}
|
||||
|
||||
static class EntityStringConverter<T> extends javafx.util.StringConverter<T> {
|
||||
private final List<T> dataset;
|
||||
|
||||
EntityStringConverter(List<T> dataset) {
|
||||
this.dataset = dataset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(T t) {
|
||||
return formatEntity(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T fromString(String string) {
|
||||
return ComboBoxUtils.fromString(dataset, string);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends IdentityEntity & NamedEntity> void initialComboBox(
|
||||
ComboBox<T> comboBox, Property<T> property, List<T> dataSet, boolean hasNull
|
||||
) {
|
||||
ObservableList<T> list = FXCollections.observableArrayList();
|
||||
if (hasNull) {
|
||||
list.add(null);
|
||||
}
|
||||
list.addAll(dataSet);
|
||||
|
||||
comboBox.setItems(list);
|
||||
comboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
property.setValue(newValue);
|
||||
});
|
||||
EntityStringConverter<T> converter = new EntityStringConverter<>(dataSet);
|
||||
comboBox.setConverter(converter);
|
||||
comboBox.valueProperty().bindBidirectional(property);
|
||||
}
|
||||
|
||||
public static <K> void bindComboBox(ComboBox<K> comboBox, Property<K> property) {
|
||||
property.addListener((observable, oldValue, newValue) -> {
|
||||
comboBox.setValue(newValue);
|
||||
// comboBox.getItems().stream().filter(k->k.equals(newValue)).findFirst().ifPresent(comboBox::setValue);
|
||||
});
|
||||
|
||||
comboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue == null) {
|
||||
property.setValue(null);
|
||||
return;
|
||||
}
|
||||
property.setValue(newValue);
|
||||
});
|
||||
}
|
||||
|
||||
public static <K extends Enum<?>, T extends BaseEnumEntity<K>> void bindComboBox(ComboBox<T> comboBox, Property<K> property, List<T> dataSet) {
|
||||
property.addListener((observable, oldValue, newValue) -> {
|
||||
dataSet.stream().filter(l -> l.getType() == newValue).findFirst().ifPresent(comboBox::setValue);
|
||||
});
|
||||
|
||||
comboBox.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue == null) {
|
||||
property.setValue(null);
|
||||
return;
|
||||
}
|
||||
property.setValue(newValue.getType());
|
||||
});
|
||||
|
||||
// comboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
// if (newValue == null) {
|
||||
// property.setValue(null);
|
||||
// return;
|
||||
// }
|
||||
// property.setValue(newValue.getType());
|
||||
// });
|
||||
|
||||
comboBox.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(T item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
} else {
|
||||
setText(item.getValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
K value = property.getValue();
|
||||
if (value != null) {
|
||||
dataSet.stream().filter(l -> l.getType() == value).findFirst().ifPresent(comboBox::setValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import com.ecep.contract.vm.CurrentEmployee;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class CurrentEmployeeInitialedEvent extends ApplicationEvent {
|
||||
private final CurrentEmployee employee;
|
||||
|
||||
public CurrentEmployeeInitialedEvent(CurrentEmployee employee) {
|
||||
super(employee);
|
||||
this.employee = employee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CurrentEmployee getSource() {
|
||||
return employee;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.util.FxmlUtils;
|
||||
import org.controlsfx.control.TaskProgressView;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.CurrentEmployeeInitialedEvent;
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.DesktopUtils;
|
||||
import com.ecep.contract.cloud.old.OldVersionService;
|
||||
import com.ecep.contract.cloud.rk.CloudRkManagerWindowController;
|
||||
import com.ecep.contract.cloud.rk.CloudRkService;
|
||||
import com.ecep.contract.cloud.tyc.CloudTycManagerWindowController;
|
||||
import com.ecep.contract.cloud.u8.ContractSyncTask;
|
||||
import com.ecep.contract.cloud.u8.YongYouU8ManagerWindowController;
|
||||
import com.ecep.contract.cloud.u8.YongYouU8Service;
|
||||
import com.ecep.contract.ds.company.controller.CompanyManagerWindowController;
|
||||
import com.ecep.contract.ds.contract.controller.ContractManagerWindowController;
|
||||
import com.ecep.contract.ds.customer.controller.CompanyCustomerManagerWindowController;
|
||||
import com.ecep.contract.ds.other.controller.bank.BankManagerWindowController;
|
||||
import com.ecep.contract.ds.other.controller.department.DepartmentManagerWindowController;
|
||||
import com.ecep.contract.ds.other.controller.employee.EmployeeManagerWindowController;
|
||||
import com.ecep.contract.ds.other.controller.inventory.InventoryManagerWindowController;
|
||||
import com.ecep.contract.ds.other.controller.permission.EmployeeFunctionsManagerWindowController;
|
||||
import com.ecep.contract.ds.other.controller.permission.EmployeeRoleManagerWindowController;
|
||||
import com.ecep.contract.ds.project.controller.ProjectManagerWindowController;
|
||||
import com.ecep.contract.ds.vendor.controller.CompanyVendorManagerWindowController;
|
||||
import com.ecep.contract.vm.CurrentEmployee;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/home.fxml")
|
||||
public class HomeWindowController extends BaseController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(HomeWindowController.class);
|
||||
|
||||
public static CompletableFuture<Void> show() {
|
||||
return show(HomeWindowController.class, null);
|
||||
}
|
||||
|
||||
// searcher
|
||||
public VBox root;
|
||||
public Label statusLabel;
|
||||
public Button openCompanyManagerWindow;
|
||||
public Button openProjectManagerWindow;
|
||||
public Button openContractManagerWindow;
|
||||
public Button openVendorManagerWindow;
|
||||
public Button openCustomManagerWindow;
|
||||
public TaskProgressView<Task<?>> taskProgressView;
|
||||
public Label taskMonitorLabel;
|
||||
public Label employeeStatusLabel;
|
||||
|
||||
public void initialize() {
|
||||
openCompanyManagerWindow.setOnAction(event -> showInOwner(CompanyManagerWindowController.class));
|
||||
openProjectManagerWindow.setOnAction(event -> showInOwner(ProjectManagerWindowController.class));
|
||||
openContractManagerWindow.setOnAction(event -> showInOwner(ContractManagerWindowController.class));
|
||||
openVendorManagerWindow.setOnAction(event -> showInOwner(CompanyVendorManagerWindowController.class));
|
||||
openCustomManagerWindow.setOnAction(event -> showInOwner(CompanyCustomerManagerWindowController.class));
|
||||
}
|
||||
|
||||
private <T extends BaseController> void showInOwner(Class<T> clz) {
|
||||
show(clz, root.getScene().getWindow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().set("销售与采购流程管理");
|
||||
// ((TaskProgressViewSkin<Task<?>>)taskProgressView.getSkin()).
|
||||
taskProgressView.setRetainTasks(false);
|
||||
Node listView = taskProgressView.getSkin().getNode().lookup("ListView");
|
||||
Node placeholder = ((ListView<?>) listView).getPlaceholder();
|
||||
((Label) placeholder).setText("没有运行的任务");
|
||||
|
||||
employeeStatusLabel.textProperty().bind(Desktop.instance.getActiveEmployee().getName());
|
||||
Desktop.instance.getTaskMonitorCenter().bindStatusLabel(taskMonitorLabel);
|
||||
Desktop.instance.getActiveEmployee().initialize();
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void onCurrentEmployeeInitialed(CurrentEmployeeInitialedEvent event) {
|
||||
CurrentEmployee currentEmployee = event.getEmployee();
|
||||
if (currentEmployee.isSystemAdministrator()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("You are administrator, try schedule sync tasks.");
|
||||
}
|
||||
Desktop.instance.getExecutorService().schedule(() -> {
|
||||
try {
|
||||
getBean(OldVersionService.class).scheduledTasks(taskProgressView);
|
||||
} catch (BeansException ignored) {
|
||||
}
|
||||
try {
|
||||
getBean(YongYouU8Service.class).scheduledTasks(taskProgressView);
|
||||
} catch (BeansException ignored) {
|
||||
}
|
||||
try {
|
||||
getBean(CloudRkService.class).scheduledTasks(taskProgressView);
|
||||
} catch (BeansException ignored) {
|
||||
}
|
||||
}, 15, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHiding(WindowEvent windowEvent) {
|
||||
super.onHiding(windowEvent);
|
||||
List<Task<?>> tasks = new ArrayList<>(taskProgressView.getTasks());
|
||||
for (Task<?> task : tasks) {
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
// scheduledExecutorService.shutdown();
|
||||
// scheduledExecutorService.shutdownNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden(WindowEvent windowEvent) {
|
||||
System.out.println("windowEvent = " + windowEvent);
|
||||
super.onHidden(windowEvent);
|
||||
|
||||
// Platform.exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开 配置 窗口
|
||||
*/
|
||||
public void openConfigWindow(ActionEvent actionEvent) {
|
||||
FxmlUtils.newLoaderAsyncWithRunLater("/ui/configs.fxml", null, loader -> {
|
||||
Scene scene = new Scene(loader.getRoot());
|
||||
Stage stage = new Stage();
|
||||
stage.initOwner(root.getScene().getWindow());
|
||||
stage.initModality(Modality.NONE);
|
||||
stage.setTitle("选项");
|
||||
stage.setScene(scene);
|
||||
stage.show();
|
||||
});
|
||||
}
|
||||
|
||||
public void createNewU8ContractSyncTaskAction(ActionEvent event) {
|
||||
try {
|
||||
ContractSyncTask task = new ContractSyncTask();
|
||||
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
|
||||
} catch (Exception e) {
|
||||
handleException("创建U8合同同步任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void openInBrowse(ActionEvent event) {
|
||||
MenuItem source = (MenuItem) event.getSource();
|
||||
String url = (String) source.getUserData();
|
||||
DesktopUtils.showInBrowse(url);
|
||||
}
|
||||
|
||||
public void openGroupRKResourceWindow(ActionEvent event) {
|
||||
CloudRkManagerWindowController.show();
|
||||
}
|
||||
|
||||
public void openTycResourceWindow(ActionEvent event) {
|
||||
CloudTycManagerWindowController.show();
|
||||
}
|
||||
|
||||
public void openYongYouResourceWindow(ActionEvent event) {
|
||||
YongYouU8ManagerWindowController.show();
|
||||
}
|
||||
|
||||
public void onShowEmployeeManagerWindowAction(ActionEvent event) {
|
||||
showInOwner(EmployeeManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onShowDepartmentManagerWindowAction(ActionEvent event) {
|
||||
showInOwner(DepartmentManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onShowRolesManagerWindowAction(ActionEvent event) {
|
||||
showInOwner(EmployeeRoleManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onShowFunctionManagerWindowAction(ActionEvent event) {
|
||||
showInOwner(EmployeeFunctionsManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onShowBankManagerWindowAction(ActionEvent event) {
|
||||
showInOwner(BankManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onShowInventoryManagerWindowAction(ActionEvent event) {
|
||||
showInOwner(InventoryManagerWindowController.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开任务监控中心窗口
|
||||
*/
|
||||
public void onShowTaskMonitorWindowAction(ActionEvent event) {
|
||||
showInOwner(TaskMonitorViewController.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import static com.ecep.contract.AppV2.DEFAULT_DB_DATABASE;
|
||||
import static com.ecep.contract.AppV2.DEFAULT_DB_HOST;
|
||||
import static com.ecep.contract.AppV2.DEFAULT_DB_PASSWORD;
|
||||
import static com.ecep.contract.AppV2.DEFAULT_DB_PORT;
|
||||
import static com.ecep.contract.AppV2.DEFAULT_DB_USERNAME;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.MessageHolder;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.ds.other.controller.HomeWindowController;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.PasswordField;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.stage.Stage;
|
||||
import lombok.Setter;
|
||||
|
||||
public class LoginWidowController implements MessageHolder {
|
||||
private static final Logger logger = LoggerFactory.getLogger(LoginWidowController.class);
|
||||
@Setter
|
||||
MessageHolder holder;
|
||||
@Setter
|
||||
Stage primaryStage;
|
||||
@Setter
|
||||
Properties properties;
|
||||
|
||||
@Override
|
||||
public void addMessage(Level level, String message) {
|
||||
holder.addMessage(level, message);
|
||||
}
|
||||
|
||||
private void storeProperties() {
|
||||
try (FileOutputStream fos = new FileOutputStream("config.properties")) {
|
||||
// 保存到文件
|
||||
properties.store(fos, "Updated config.properties");
|
||||
info("配置文件已更新!");
|
||||
} catch (java.io.IOException e) {
|
||||
error("保存配置文件失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
String getHost() {
|
||||
return properties.getProperty("db.server.host", DEFAULT_DB_HOST);
|
||||
}
|
||||
|
||||
String getPort() {
|
||||
return properties.getProperty("db.server.port", DEFAULT_DB_PORT);
|
||||
}
|
||||
|
||||
String getDatabase() {
|
||||
return properties.getProperty("db.server.database", DEFAULT_DB_DATABASE);
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return properties.getProperty("db.server.username", DEFAULT_DB_USERNAME);
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return properties.getProperty("db.server.password", DEFAULT_DB_PASSWORD);
|
||||
}
|
||||
|
||||
public void tryLogin() {
|
||||
// CompletableFuture<ButtonType> future = new CompletableFuture<>();
|
||||
// 检查配置文件中是否保存用户名和密码
|
||||
String userName = getUserName();
|
||||
if (StringUtils.hasText(userName)) {
|
||||
try {
|
||||
EmployeeInfo employeeInfo = tryToConnect(userName, getPassword());
|
||||
if (employeeInfo.errorCode < 0) {
|
||||
error("登录失败:错误代码=" + employeeInfo.errorCode);
|
||||
} else {
|
||||
logined(employeeInfo);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
showUserNameLoginDialog(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CompletableFuture<List<LoginWidowController.MacIP>> getMacAndIP() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
// mac ip
|
||||
List<LoginWidowController.MacIP> list = new ArrayList<>();
|
||||
try {
|
||||
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
|
||||
while (interfaces.hasMoreElements()) {
|
||||
NetworkInterface anInterface = interfaces.nextElement();
|
||||
if (anInterface.isLoopback()) {
|
||||
continue;
|
||||
}
|
||||
byte[] hardwareAddress = anInterface.getHardwareAddress();
|
||||
if (hardwareAddress == null) {
|
||||
continue;
|
||||
}
|
||||
Enumeration<InetAddress> inetAddresses = anInterface.getInetAddresses();
|
||||
if (!inetAddresses.hasMoreElements()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// -分割16进制表示法
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < hardwareAddress.length; i++) {
|
||||
sb.append(String.format("%02X%s", hardwareAddress[i], i < hardwareAddress.length - 1 ? "-" : ""));
|
||||
}
|
||||
|
||||
while (inetAddresses.hasMoreElements()) {
|
||||
InetAddress inetAddress = inetAddresses.nextElement();
|
||||
if (inetAddress instanceof Inet4Address) {
|
||||
list.add(new LoginWidowController.MacIP(sb.toString(), inetAddress.getHostAddress()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
private EmployeeInfo tryToConnect(String userName, String password) throws SQLException {
|
||||
String host = getHost();
|
||||
String port = getPort();
|
||||
String database = getDatabase();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("try to connect db server host:{},port:{},database:{},user:{},pwd:{}", host, port, database, userName, "*");
|
||||
}
|
||||
|
||||
try (HikariDataSource source = DataSourceBuilder.create()
|
||||
.type(HikariDataSource.class)
|
||||
.url("jdbc:mysql://" + host + ":" + port + "/" + database)
|
||||
.username(userName)
|
||||
.password(password)
|
||||
.driverClassName("com.mysql.cj.jdbc.Driver")
|
||||
.build()) {
|
||||
|
||||
CompletableFuture<List<MacIP>> macAndIP = getMacAndIP();
|
||||
macAndIP.thenAccept(map -> {
|
||||
if (map.isEmpty()) {
|
||||
error("查询本地地址信息失败,请联系管理员或重启应用!");
|
||||
logger.error("查询本地地址信息失败");
|
||||
}
|
||||
});
|
||||
|
||||
try (Connection connection = source.getConnection()) {
|
||||
info("连接到数据库 " + host + ", 请稍后,正在查询账户与本绑定的登录信息...");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("connection.getClientInfo() = {}", connection.getClientInfo());
|
||||
}
|
||||
|
||||
// 必须要阻塞,否则 connection 会断开
|
||||
EmployeeInfo employeeInfo = tryLoginWithEmployeeBind(connection, macAndIP).get();
|
||||
createSession(connection, employeeInfo);
|
||||
return employeeInfo;
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void createSession(Connection connection, EmployeeInfo employeeInfo) {
|
||||
employeeInfo.sessionId = addHistory(connection, employeeInfo.employeeId, employeeInfo.binds.getFirst());
|
||||
}
|
||||
|
||||
private int addHistory(Connection connection, int employeeId, MacIP macIP) {
|
||||
try {
|
||||
String sql = "INSERT INTO EMPLOYEE_LOGIN_HISTORY (IP, MAC, DT, EMPLOYEE_ID) VALUES (?, ?, ?, ?)";
|
||||
try (PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||
ps.setString(1, macIP.ip);
|
||||
ps.setString(2, macIP.mac);
|
||||
ps.setObject(3, LocalDateTime.now()); // 根据数据库字段类型调整
|
||||
ps.setInt(4, employeeId);
|
||||
ps.executeUpdate();
|
||||
// 返回 新的主键值
|
||||
ResultSet generatedKeys = ps.getGeneratedKeys();
|
||||
if (generatedKeys.next()) {
|
||||
return generatedKeys.getInt(1);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
holder.error("申请新会话编号失败");
|
||||
logger.error("unable insert EMPLOYEE_LOGIN_HISTORY, ", e);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static class MacIP {
|
||||
String ip;
|
||||
String mac;
|
||||
|
||||
public MacIP(String mac, String ip) {
|
||||
this.mac = mac;
|
||||
this.ip = ip;
|
||||
}
|
||||
}
|
||||
|
||||
static class EmployeeInfo {
|
||||
Integer employeeId;
|
||||
List<MacIP> binds = new ArrayList<>();
|
||||
SimpleStringProperty name = new SimpleStringProperty();
|
||||
SimpleBooleanProperty active = new SimpleBooleanProperty();
|
||||
int sessionId;
|
||||
int errorCode = 0;
|
||||
|
||||
public EmployeeInfo(Integer employeeId) {
|
||||
this.employeeId = employeeId;
|
||||
}
|
||||
|
||||
public static EmployeeInfo error(int code) {
|
||||
EmployeeInfo employeeInfo = new EmployeeInfo(null);
|
||||
employeeInfo.errorCode = code;
|
||||
return employeeInfo;
|
||||
}
|
||||
|
||||
public void addBind(MacIP macIP) {
|
||||
binds.add(macIP);
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<EmployeeInfo> tryLoginWithEmployeeBind(Connection connection, CompletableFuture<List<MacIP>> macAndIP) {
|
||||
CompletableFuture<EmployeeInfo> future = new CompletableFuture<>();
|
||||
macAndIP.thenAccept(macIPS -> {
|
||||
if (macIPS.isEmpty()) {
|
||||
future.complete(EmployeeInfo.error(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
HashMap<Integer, EmployeeInfo> employeeMap = new HashMap<>();
|
||||
for (MacIP macIP : macIPS) {
|
||||
for (Integer employeeId : findAllBindEmployee(connection, macIP)) {
|
||||
employeeMap.computeIfAbsent(employeeId, k -> new EmployeeInfo(employeeId)).addBind(macIP);
|
||||
}
|
||||
}
|
||||
|
||||
if (employeeMap.isEmpty()) {
|
||||
error("本机未绑定登录信息,请联系管理员更新.");
|
||||
// 当前计算机的信息,如用户名,计算机名等
|
||||
String username = System.getProperty("user.name");
|
||||
String computerName = System.getenv("COMPUTERNAME");
|
||||
for (MacIP macIP : macIPS) {
|
||||
if (macIP.ip.equals("127.0.0.1")) {
|
||||
continue;
|
||||
}
|
||||
registerComputer(username, computerName, connection, macIP);
|
||||
}
|
||||
future.complete(EmployeeInfo.error(-2));
|
||||
return;
|
||||
}
|
||||
|
||||
if (employeeMap.size() == 1) {
|
||||
// 直接登录
|
||||
EmployeeInfo employeeInfo = employeeMap.values().stream().findFirst().get();
|
||||
// issue #1 登录成功后没有更新员工信息
|
||||
fill(connection, employeeInfo);
|
||||
future.complete(employeeInfo);
|
||||
} else {
|
||||
List<EmployeeInfo> list = employeeMap.values().stream().toList();
|
||||
// 选择登录
|
||||
Platform.runLater(() -> {
|
||||
EmployeeInfo info = showEmployeeSelectDialog(list);
|
||||
future.complete(Objects.requireNonNullElseGet(info, () -> EmployeeInfo.error(-3)));
|
||||
});
|
||||
for (EmployeeInfo info : list) {
|
||||
fill(connection, info);
|
||||
}
|
||||
}
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
private EmployeeInfo showEmployeeSelectDialog(List<EmployeeInfo> list) {
|
||||
Stage stage = new Stage();
|
||||
stage.initOwner(primaryStage);
|
||||
stage.setTitle("请选择账户登录系统");
|
||||
stage.setWidth(360);
|
||||
stage.setHeight(280);
|
||||
|
||||
Label label = new Label("您的主机关联了以下账户,请选择一个登录");
|
||||
label.setPadding(new Insets(10, 0, 10, 10));
|
||||
ListView<Label> listView = new ListView<>();
|
||||
|
||||
EventHandler<MouseEvent> eventHandler = event -> {
|
||||
if (event.getClickCount() == 2) {
|
||||
// listView.getSelectionModel().select(cb);
|
||||
stage.close();
|
||||
}
|
||||
};
|
||||
for (EmployeeInfo employeeInfo : list) {
|
||||
Label cb = new Label();
|
||||
cb.setUserData(employeeInfo);
|
||||
cb.textProperty().bind(employeeInfo.name);
|
||||
cb.setPadding(new Insets(5));
|
||||
cb.setOnMouseClicked(eventHandler);
|
||||
listView.getItems().add(cb);
|
||||
}
|
||||
|
||||
// 创建 BorderPane 并设置边距
|
||||
BorderPane borderPane = new BorderPane();
|
||||
borderPane.setPadding(new Insets(10));
|
||||
borderPane.setTop(label);
|
||||
borderPane.setCenter(listView);
|
||||
|
||||
Button bottom = new Button("确定");
|
||||
bottom.setDefaultButton(true);
|
||||
bottom.setOnAction(event -> {
|
||||
Label selectedItem = listView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
// 没选中,退出继续选择
|
||||
return;
|
||||
}
|
||||
stage.close();
|
||||
});
|
||||
BorderPane.setAlignment(bottom, javafx.geometry.Pos.CENTER);
|
||||
|
||||
borderPane.setBottom(bottom);
|
||||
stage.setScene(new Scene(borderPane));
|
||||
stage.setOnCloseRequest(event -> {
|
||||
Label selectedItem = listView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
// 关闭时,如何没有做选择,不关闭窗口
|
||||
event.consume();
|
||||
}
|
||||
});
|
||||
|
||||
stage.showAndWait();
|
||||
|
||||
Label selectedItem = listView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
throw new NoSuchElementException("请选择工号登录系统");
|
||||
}
|
||||
|
||||
return (EmployeeInfo) selectedItem.getUserData();
|
||||
}
|
||||
|
||||
private void fill(Connection connection, EmployeeInfo info) {
|
||||
try {
|
||||
ResultSet rs = connection.createStatement()
|
||||
.executeQuery("SELECT * FROM EMPLOYEE where ID = " + info.employeeId);
|
||||
if (rs.next()) {
|
||||
String name = rs.getString("NAME");
|
||||
boolean isActive = rs.getBoolean("IS_ACTIVE");
|
||||
Platform.runLater(() -> {
|
||||
info.name.set(name);
|
||||
info.active.set(isActive);
|
||||
});
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("查询{}失败", info.employeeId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerComputer(String username, String computerName, Connection connection, MacIP macIP) {
|
||||
info("正在注册本机信息(MAC:" + macIP.mac + ", IP:" + macIP.ip + ")...");
|
||||
String sql = "INSERT INTO EMPLOYEE_AUTH_BIND (IP,MAC,DESCRIPTION)VALUES(?,?,?)";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
stmt.setString(1, macIP.ip);
|
||||
stmt.setString(2, macIP.mac);
|
||||
// 当前计算机的信息,如用户名,计算机名等
|
||||
stmt.setString(3, username + "," + computerName);
|
||||
if (stmt.execute()) {
|
||||
info("注册成功");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
error(String.format("注册失败,请联系管理员或重启应用!MAC: %s, IP: %s", macIP.mac, macIP.ip));
|
||||
logger.error("注册失败 mac:{}, ip:{}", macIP.mac, macIP.ip, e);
|
||||
}
|
||||
}
|
||||
|
||||
List<Integer> findAllBindEmployee(Connection connection, MacIP macIP) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
// 优化后代码
|
||||
String sql = "SELECT * FROM EMPLOYEE_AUTH_BIND WHERE IP = ? AND MAC = ?";
|
||||
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
|
||||
stmt.setString(1, macIP.ip);
|
||||
stmt.setString(2, macIP.mac);
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
int id = rs.getInt("EMPLOYEE_ID");
|
||||
if (id > 0) {
|
||||
list.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(
|
||||
String.format("查询本机绑定信息异常,请联系管理员或重启应用!MAC: %s, IP: %s", macIP.mac, macIP.ip),
|
||||
e
|
||||
);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void showUserNameLoginDialog(Exception exception) {
|
||||
Stage stage = new Stage();
|
||||
stage.initOwner(primaryStage);
|
||||
stage.setTitle("登录");
|
||||
|
||||
// 创建 BorderPane 并设置边距
|
||||
BorderPane borderPane = new BorderPane();
|
||||
borderPane.setPadding(new Insets(10));
|
||||
|
||||
// 创建布局
|
||||
GridPane grid = new GridPane();
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(10);
|
||||
// 为整个 GridPane 设置外边距
|
||||
//GridPane.setMargin(grid, new Insets(10));
|
||||
|
||||
// 账户输入框
|
||||
Label userLabel = new Label("账户:");
|
||||
TextField userField = new TextField();
|
||||
{
|
||||
String username = getUserName();
|
||||
if (StringUtils.hasText(username)) {
|
||||
userField.setText(username);
|
||||
}
|
||||
grid.add(userLabel, 0, 0);
|
||||
grid.add(userField, 1, 0);
|
||||
}
|
||||
|
||||
// 密码输入框
|
||||
Label passwordLabel = new Label("密码:");
|
||||
PasswordField passwordField = new PasswordField();
|
||||
{
|
||||
String password = getPassword();
|
||||
if (StringUtils.hasText(password)) {
|
||||
passwordField.setText(password);
|
||||
}
|
||||
grid.add(passwordLabel, 0, 1);
|
||||
grid.add(passwordField, 1, 1);
|
||||
}
|
||||
|
||||
// 记住密码复选框
|
||||
CheckBox rememberCheckBox = new CheckBox("记住账户密码");
|
||||
{
|
||||
String property = properties.getProperty("username_password.remember", "false");
|
||||
if (Boolean.parseBoolean(property)) {
|
||||
rememberCheckBox.setSelected(true);
|
||||
}
|
||||
}
|
||||
grid.add(rememberCheckBox, 1, 2);
|
||||
|
||||
// 错误消息提示
|
||||
Label exceptionLabel = new Label();
|
||||
grid.add(exceptionLabel, 0, 3);
|
||||
exceptionLabel.setWrapText(true);
|
||||
GridPane.setColumnSpan(exceptionLabel, 2);
|
||||
if (exception == null) {
|
||||
exceptionLabel.setVisible(false);
|
||||
} else {
|
||||
exceptionLabel.setText(exception.getMessage());
|
||||
exceptionLabel.setVisible(true);
|
||||
}
|
||||
|
||||
borderPane.setCenter(grid);
|
||||
|
||||
|
||||
// 登录按钮
|
||||
Button loginButton = new Button("登录");
|
||||
loginButton.setDefaultButton(true);
|
||||
borderPane.setBottom(loginButton);
|
||||
BorderPane.setAlignment(loginButton, javafx.geometry.Pos.CENTER);
|
||||
|
||||
|
||||
// 登录按钮点击事件
|
||||
loginButton.setOnAction(event -> {
|
||||
String username = userField.getText();
|
||||
String password = passwordField.getText();
|
||||
boolean remember = rememberCheckBox.isSelected();
|
||||
|
||||
// 尝试连接数据库
|
||||
exceptionLabel.setText("");
|
||||
exceptionLabel.setVisible(false);
|
||||
try {
|
||||
EmployeeInfo employeeInfo = tryToConnect(username, password);
|
||||
if (employeeInfo.errorCode < 0) {
|
||||
exceptionLabel.setText("登录失败:错误代码=" + employeeInfo.errorCode);
|
||||
exceptionLabel.setVisible(true);
|
||||
} else {
|
||||
logined(employeeInfo);
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
//
|
||||
exceptionLabel.setText("数据库错误:" + ex.getMessage());
|
||||
exceptionLabel.setVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
properties.setProperty("db.server.username", username);
|
||||
properties.setProperty("db.server.password", password);
|
||||
properties.setProperty("username_password.remember", Boolean.toString(remember));
|
||||
|
||||
// 如果勾选了“记住密码”,则更新配置文件
|
||||
if (remember) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
storeProperties();
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭登录窗口
|
||||
stage.close();
|
||||
});
|
||||
|
||||
|
||||
// 创建场景并设置到窗口
|
||||
Scene scene = new Scene(borderPane, 400, 260);
|
||||
stage.setScene(scene);
|
||||
// stage.setAlwaysOnTop(true);
|
||||
stage.setResizable(false);
|
||||
stage.showAndWait();
|
||||
}
|
||||
|
||||
|
||||
private void logined(EmployeeInfo employeeInfo) {
|
||||
info("欢迎 " + employeeInfo.name.get());
|
||||
if (!SpringApp.isRunning()) {
|
||||
info("请稍后...");
|
||||
}
|
||||
Desktop.instance.setActiveEmployeeId(employeeInfo.employeeId);
|
||||
Desktop.instance.setSessionId(employeeInfo.sessionId);
|
||||
tryShowHomeWindow();
|
||||
}
|
||||
|
||||
void tryShowHomeWindow() {
|
||||
try {
|
||||
while (!SpringApp.isRunning()) {
|
||||
System.out.println("等待启动");
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// 必须要等待启动成功后才能关闭主场景,否则进程结束程序退出
|
||||
HomeWindowController.show().thenRun(() -> Platform.runLater(primaryStage::close));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import com.ecep.contract.controller.tab.Skin;
|
||||
|
||||
public interface ManagerSkin extends Skin {
|
||||
|
||||
void initializeTable();
|
||||
|
||||
default void dispose() {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.cloud.u8.YongYouU8Service;
|
||||
import com.ecep.contract.constant.CompanyVendorConstant;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
|
||||
import com.ecep.contract.util.StringConfig;
|
||||
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
public class SysConfWindowController extends BaseController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SysConfWindowController.class);
|
||||
|
||||
public Label companyContractPathLabel;
|
||||
|
||||
public TextField u8DataBaseServerHostField;
|
||||
public TextField u8DataBaseCatalogField;
|
||||
public TextField u8DataBaseUserNameField;
|
||||
public TextField u8DataBasePasswordField;
|
||||
|
||||
public Label vendorPathLabel;
|
||||
public Label vendorEvaluationFormTemplateLabel;
|
||||
|
||||
public Label customerPathLabel;
|
||||
public Label customerEvaluationFormTemplateLabel;
|
||||
public Label customerSaleBookPathLabel;
|
||||
|
||||
StringConfig contractPathConfig = new StringConfig(ContractService.CONTRACT_BASE_PATH);
|
||||
StringConfig vendorPathConfig = new StringConfig(CompanyVendorConstant.KEY_BASE_PATH);
|
||||
StringConfig vendorEvaluationFormTemplateConfig = new StringConfig(
|
||||
CompanyVendorConstant.KEY_EVALUATION_FORM_TEMPLATE);
|
||||
StringConfig customerPathConfig = new StringConfig(CompanyCustomerService.KEY_BASE_PATH);
|
||||
StringConfig customerEvaluationFormTemplateConfig = new StringConfig(
|
||||
CompanyCustomerFileService.KEY_EVALUATION_FORM_TEMPLATE);
|
||||
StringConfig customerSaleBookPathConfig = new StringConfig(CompanyCustomerService.KEY_SALEBOOK_PATH);
|
||||
|
||||
StringConfig u8DataBaseServerHostConfig = new StringConfig(YongYouU8Service.KEY_HOST_IP);
|
||||
StringConfig u8DataBaseCatalogConfig = new StringConfig(YongYouU8Service.KEY_DATABASE);
|
||||
StringConfig u8DataBaseUserNameConfig = new StringConfig(YongYouU8Service.KEY_USER_NAME);
|
||||
StringConfig u8DataBasePasswordConfig = new StringConfig(YongYouU8Service.KEY_PASSWORD);
|
||||
|
||||
public void initialize() {
|
||||
contractPathConfig.setControl(companyContractPathLabel);
|
||||
contractPathConfig.initialize();
|
||||
|
||||
vendorPathConfig.setControl(vendorPathLabel);
|
||||
vendorPathConfig.initialize();
|
||||
vendorEvaluationFormTemplateConfig.setControl(vendorEvaluationFormTemplateLabel);
|
||||
vendorEvaluationFormTemplateConfig.initialize();
|
||||
|
||||
customerPathConfig.setControl(customerPathLabel);
|
||||
customerPathConfig.initialize();
|
||||
customerEvaluationFormTemplateConfig.setControl(customerEvaluationFormTemplateLabel);
|
||||
customerEvaluationFormTemplateConfig.initialize();
|
||||
customerSaleBookPathConfig.setControl(customerSaleBookPathLabel);
|
||||
customerSaleBookPathConfig.initialize();
|
||||
|
||||
u8DataBaseServerHostConfig.setControl(u8DataBaseServerHostField);
|
||||
u8DataBaseServerHostConfig.initialize();
|
||||
u8DataBaseCatalogConfig.setControl(u8DataBaseCatalogField);
|
||||
u8DataBaseCatalogConfig.initialize();
|
||||
u8DataBaseUserNameConfig.setControl(u8DataBaseUserNameField);
|
||||
u8DataBaseUserNameConfig.initialize();
|
||||
u8DataBasePasswordConfig.setControl(u8DataBasePasswordField);
|
||||
u8DataBasePasswordConfig.initialize();
|
||||
|
||||
logger.debug("#initialize()");
|
||||
}
|
||||
|
||||
private void directoryChoose(StringConfig config, String title, String key, ActionEvent event) {
|
||||
DirectoryChooser chooser = new DirectoryChooser();
|
||||
chooser.setTitle(title);
|
||||
File value = new File(config.getProperty().getValue());
|
||||
chooser.setInitialDirectory(value);
|
||||
|
||||
Node node = (Node) event.getSource();
|
||||
File selected = chooser.showDialog(node.getScene().getWindow());
|
||||
if (selected != null) {
|
||||
config.getProperty().setValue(selected.getAbsolutePath());
|
||||
config.save();
|
||||
}
|
||||
}
|
||||
|
||||
public void changeCompanyContractPath(ActionEvent actionEvent) {
|
||||
directoryChoose(contractPathConfig, "请选择合同目录", ContractService.CONTRACT_BASE_PATH, actionEvent);
|
||||
}
|
||||
|
||||
public void changeVendorPath(ActionEvent actionEvent) {
|
||||
directoryChoose(vendorPathConfig, "请选择供应商目录", CompanyVendorConstant.KEY_BASE_PATH, actionEvent);
|
||||
}
|
||||
|
||||
public void changeCustomerPath(ActionEvent actionEvent) {
|
||||
directoryChoose(customerPathConfig, "请选择客户目录", CompanyCustomerService.KEY_BASE_PATH, actionEvent);
|
||||
}
|
||||
|
||||
public void changeCustomerSaleBookPath(ActionEvent actionEvent) {
|
||||
directoryChoose(customerSaleBookPathConfig, "请选择销售台账目录", "customer.salebook.path", actionEvent);
|
||||
}
|
||||
|
||||
// 模拟销毁方法
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
|
||||
private void fileChoose(StringConfig config, String title, String key, ActionEvent event) {
|
||||
FileChooser chooser = new FileChooser();
|
||||
chooser.setTitle(title);
|
||||
File value = new File(config.getProperty().getValue());
|
||||
chooser.setInitialDirectory(value.getParentFile());
|
||||
chooser.setInitialFileName(value.getName());
|
||||
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(" 模板文件(*.xlsx)", "*.xlsx"));
|
||||
Node node = (Node) event.getSource();
|
||||
File selected = chooser.showOpenDialog(node.getScene().getWindow());
|
||||
if (selected != null) {
|
||||
config.getProperty().setValue(selected.getAbsolutePath());
|
||||
config.save();
|
||||
}
|
||||
}
|
||||
|
||||
public void changeCustomerEvaluationFormTemplate(ActionEvent actionEvent) {
|
||||
fileChoose(customerEvaluationFormTemplateConfig, "请选择客户资信评估表模板",
|
||||
CompanyCustomerFileService.KEY_EVALUATION_FORM_TEMPLATE, actionEvent);
|
||||
}
|
||||
|
||||
public void changeVendorEvaluationFormTemplate(ActionEvent actionEvent) {
|
||||
fileChoose(vendorEvaluationFormTemplateConfig, "请选择供方调查评价表模板",
|
||||
CompanyVendorConstant.KEY_EVALUATION_FORM_TEMPLATE,
|
||||
actionEvent);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.Message;
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.task.MonitoredTask;
|
||||
import com.ecep.contract.task.TaskHistory;
|
||||
import com.ecep.contract.task.TaskMonitorCenter;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableRow;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
/**
|
||||
* 任务监控界面控制器
|
||||
*/
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath(value = "/ui/task/TaskMonitorView.fxml")
|
||||
public class TaskMonitorViewController extends BaseController {
|
||||
@FXML
|
||||
private TableView<MonitoredTask<?>> activeTasksTable;
|
||||
@FXML
|
||||
private TableColumn<MonitoredTask<?>, String> activeTaskIdColumn;
|
||||
@FXML
|
||||
private TableColumn<MonitoredTask<?>, String> activeTaskTitleColumn;
|
||||
@FXML
|
||||
private TableColumn<MonitoredTask<?>, Number> activeTaskProgressColumn;
|
||||
@FXML
|
||||
private TableColumn<MonitoredTask<?>, String> activeTaskStatusColumn;
|
||||
|
||||
@FXML
|
||||
private TableView<TaskHistory> historyTasksTable;
|
||||
@FXML
|
||||
private TableColumn<TaskHistory, String> historyTaskIdColumn;
|
||||
@FXML
|
||||
private TableColumn<TaskHistory, String> historyTaskTitleColumn;
|
||||
@FXML
|
||||
private TableColumn<TaskHistory, String> historyTaskStatusColumn;
|
||||
@FXML
|
||||
private TableColumn<TaskHistory, String> historyTaskStartTimeColumn;
|
||||
@FXML
|
||||
private TableColumn<TaskHistory, String> historyTaskExecutionTimeColumn;
|
||||
|
||||
@FXML
|
||||
private Button cancelTaskButton;
|
||||
@FXML
|
||||
private Button clearHistoryButton;
|
||||
@FXML
|
||||
private Button refreshExecutorInfoButton;
|
||||
@FXML
|
||||
private TableView<ExecutorInfo> executorInfoTable;
|
||||
@FXML
|
||||
private TableColumn<ExecutorInfo, String> executorFieldColumn;
|
||||
@FXML
|
||||
private TableColumn<ExecutorInfo, String> executorValueColumn;
|
||||
@FXML
|
||||
private TableColumn<ExecutorInfo, String> executorDescriptionColumn;
|
||||
|
||||
public TaskMonitorViewController() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于存储ExecutorService信息的内部类
|
||||
*/
|
||||
public static class ExecutorInfo {
|
||||
private final String field;
|
||||
private final String value;
|
||||
private final String description;
|
||||
|
||||
public ExecutorInfo(String field, String value, String description) {
|
||||
this.field = field;
|
||||
this.value = value;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().set("任务监控中心");
|
||||
|
||||
// 初始化活动任务表格
|
||||
activeTaskIdColumn.setCellValueFactory(new PropertyValueFactory<>("taskId"));
|
||||
activeTaskTitleColumn.setCellValueFactory(new PropertyValueFactory<>("title"));
|
||||
|
||||
// 进度条列
|
||||
activeTaskProgressColumn.setCellValueFactory(
|
||||
param -> param.getValue().progressProperty().divide(param.getValue().totalWorkProperty()));
|
||||
activeTaskProgressColumn.setCellFactory(column -> new TableCell<>() {
|
||||
private final ProgressBar progressBar = new ProgressBar();
|
||||
{
|
||||
// 设置进度条最大宽度和水平扩展属性
|
||||
progressBar.setMaxWidth(Double.MAX_VALUE);
|
||||
HBox.setHgrow(progressBar, Priority.ALWAYS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(Number item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
setGraphic(null);
|
||||
return;
|
||||
}
|
||||
setGraphic(progressBar);
|
||||
progressBar.setProgress(item.doubleValue());
|
||||
}
|
||||
});
|
||||
|
||||
// 状态列
|
||||
activeTaskStatusColumn.setCellValueFactory(cellData -> {
|
||||
MonitoredTask<?> task = cellData.getValue();
|
||||
String description = "";
|
||||
if (task.stateProperty().get() != null) {
|
||||
description = task.stateProperty().get().getDescription();
|
||||
}
|
||||
return new SimpleStringProperty(description);
|
||||
});
|
||||
|
||||
// 初始化历史任务表格
|
||||
historyTaskIdColumn.setCellValueFactory(new PropertyValueFactory<>("taskId"));
|
||||
historyTaskTitleColumn.setCellValueFactory(new PropertyValueFactory<>("title"));
|
||||
historyTaskStatusColumn.setCellValueFactory(
|
||||
cellData -> new SimpleStringProperty(cellData.getValue().getStatus().getDescription()));
|
||||
historyTaskStartTimeColumn.setCellValueFactory(
|
||||
cellData -> new SimpleStringProperty(MyDateTimeUtils.format(cellData.getValue().getStartTime())));
|
||||
historyTaskExecutionTimeColumn.setCellValueFactory(
|
||||
cellData -> new SimpleStringProperty(cellData.getValue().getFormattedExecutionTime()));
|
||||
|
||||
// 绑定数据
|
||||
TaskMonitorCenter taskMonitorCenter = Desktop.instance.getTaskMonitorCenter();
|
||||
activeTasksTable.setItems(taskMonitorCenter.getActiveTasks());
|
||||
historyTasksTable.setItems(taskMonitorCenter.getTaskHistory());
|
||||
|
||||
// 添加任务双击事件(显示详情)
|
||||
historyTasksTable.setRowFactory(tv -> {
|
||||
TableRow<TaskHistory> row = new TableRow<>();
|
||||
row.setOnMouseClicked(event -> {
|
||||
if (event.getClickCount() == 2 && !row.isEmpty()) {
|
||||
TaskHistory history = row.getItem();
|
||||
showTaskDetails(history);
|
||||
}
|
||||
});
|
||||
return row;
|
||||
});
|
||||
|
||||
cancelTaskButton.disableProperty().bind(activeTasksTable.getSelectionModel().selectedItemProperty().isNull());
|
||||
// 初始化Executor信息表格
|
||||
initializeExecutorInfoTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Executor信息表格
|
||||
*/
|
||||
private void initializeExecutorInfoTable() {
|
||||
executorFieldColumn.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().getField()));
|
||||
executorValueColumn.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().getValue()));
|
||||
executorDescriptionColumn
|
||||
.setCellValueFactory(param -> new SimpleStringProperty(param.getValue().getDescription()));
|
||||
|
||||
// 初始加载Executor信息
|
||||
refreshExecutorInfo();
|
||||
// 绑定刷新按钮事件
|
||||
refreshExecutorInfoButton.setOnAction(event -> refreshExecutorInfo());
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新Executor信息
|
||||
*/
|
||||
@FXML
|
||||
private void refreshExecutorInfo() {
|
||||
executorInfoTable.getItems().clear();
|
||||
|
||||
try {
|
||||
ExecutorService executorService = Desktop.instance.getExecutorService();
|
||||
if (executorService instanceof ThreadPoolExecutor threadPoolExecutor) {
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"PoolSize",
|
||||
String.valueOf(threadPoolExecutor.getPoolSize()),
|
||||
"PoolSize"));
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"活动线程数",
|
||||
String.valueOf(threadPoolExecutor.getActiveCount()),
|
||||
"当前正在执行任务的线程数"));
|
||||
// 添加线程池信息
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"核心线程数",
|
||||
String.valueOf(threadPoolExecutor.getCorePoolSize()),
|
||||
"线程池维护的最小线程数"));
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"最大线程数",
|
||||
String.valueOf(threadPoolExecutor.getMaximumPoolSize()),
|
||||
"线程池允许的最大线程数"));
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"KeepAliveTime",
|
||||
String.valueOf(threadPoolExecutor.getKeepAliveTime(TimeUnit.SECONDS)),
|
||||
"the thread keep-alive time, which is the amount of time that threads may remain idle before being terminated. Threads that wait this amount of time without processing a task will be terminated if there are more than the core number of threads currently in the pool, or if this pool allows core thread timeout."));
|
||||
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"任务队列大小",
|
||||
String.valueOf(threadPoolExecutor.getQueue().size()),
|
||||
"等待执行的任务数量"));
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"已完成任务数",
|
||||
String.valueOf(threadPoolExecutor.getCompletedTaskCount()),
|
||||
"已完成执行的任务总数"));
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"LargestPoolSize",
|
||||
String.valueOf(threadPoolExecutor.getLargestPoolSize()),
|
||||
"线程池当前状态"));
|
||||
|
||||
// 如果是ScheduledExecutorService,添加额外信息
|
||||
if (executorService instanceof ScheduledExecutorService) {
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"线程池类型",
|
||||
"ScheduledExecutorService",
|
||||
"可调度的线程池"));
|
||||
} else {
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"线程池类型",
|
||||
"ThreadPoolExecutor",
|
||||
"普通线程池"));
|
||||
}
|
||||
} else {
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"错误",
|
||||
"未知的ExecutorService类型",
|
||||
"无法获取线程池详细信息"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
executorInfoTable.getItems().add(new ExecutorInfo(
|
||||
"异常",
|
||||
e.getMessage(),
|
||||
"获取ExecutorService信息时发生错误"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消选中的任务
|
||||
*/
|
||||
@FXML
|
||||
private void onCancelTask() {
|
||||
MonitoredTask<?> selectedTask = activeTasksTable.getSelectionModel().getSelectedItem();
|
||||
if (selectedTask != null) {
|
||||
Desktop.instance.getTaskMonitorCenter().cancelTask(selectedTask.getTaskId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空历史记录
|
||||
*/
|
||||
@FXML
|
||||
private void onClearHistory() {
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setTitle("确认操作");
|
||||
alert.setHeaderText("清空任务历史");
|
||||
alert.setContentText("确定要清空所有任务历史记录吗?此操作不可恢复。");
|
||||
|
||||
alert.showAndWait().ifPresent(response -> {
|
||||
if (response == ButtonType.OK) {
|
||||
Desktop.instance.getTaskMonitorCenter().getTaskHistory().clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示任务详情
|
||||
*/
|
||||
private void showTaskDetails(TaskHistory history) {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setTitle("任务详情");
|
||||
alert.setHeaderText(history.getTitle());
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane();
|
||||
scrollPane.setPrefHeight(300);
|
||||
VBox vBox = new VBox();
|
||||
|
||||
Label taskIdLabel = new Label("任务ID: " + history.getTaskId());
|
||||
Label statusLabel = new Label("状态: " + history.getStatus().getDescription());
|
||||
Label startTimeLabel = new Label("开始时间: " + MyDateTimeUtils.format(history.getStartTime()));
|
||||
Label endTimeLabel = new Label("结束时间: " + MyDateTimeUtils.format(history.getEndTime()));
|
||||
Label executionTimeLabel = new Label("执行耗时: " + history.getFormattedExecutionTime());
|
||||
|
||||
vBox.getChildren().addAll(taskIdLabel, statusLabel, startTimeLabel, endTimeLabel, executionTimeLabel);
|
||||
|
||||
Label messageLabel = new Label("消息:");
|
||||
vBox.getChildren().add(messageLabel);
|
||||
|
||||
for (Message msg : history.getMessages()) {
|
||||
Text text = new Text(msg.getMessage());
|
||||
if (msg.getLevel() == Level.INFO) {
|
||||
text.setFill(Color.BLUE);
|
||||
} else if (msg.getLevel() == Level.WARNING) {
|
||||
text.setFill(Color.ORANGE);
|
||||
} else if (msg.getLevel() == Level.SEVERE) {
|
||||
text.setFill(Color.RED);
|
||||
} else if (msg.getLevel() == Level.CONFIG) {
|
||||
text.setFill(Color.GRAY);
|
||||
}
|
||||
vBox.getChildren().add(text);
|
||||
}
|
||||
|
||||
if (history.getErrorMessage() != null) {
|
||||
alert.getDialogPane().setExpandableContent(new TextArea(history.getErrorMessage()));
|
||||
}
|
||||
scrollPane.setContent(vBox);
|
||||
alert.getDialogPane().setContent(scrollPane);
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行任务监控演示
|
||||
*/
|
||||
public void onRunTaskMonitorDemo(ActionEvent event) {
|
||||
com.ecep.contract.task.DemoTask.runDemo();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import org.controlsfx.control.ToggleSwitch;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.cloud.u8.ctx.CompanyCtx;
|
||||
import com.ecep.contract.cloud.u8.ctx.ContractCtx;
|
||||
import com.ecep.contract.ds.other.BooleanConfig;
|
||||
import com.ecep.contract.ds.other.LocalDateConfig;
|
||||
import com.ecep.contract.ds.other.LocalDateTimeConfig;
|
||||
import com.ecep.contract.ds.other.StringConfig;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/cloud/u8_config.fxml")
|
||||
public class YongYouU8ConfigWindowController extends BaseController {
|
||||
@FXML
|
||||
private DatePicker auto_create_company_after;
|
||||
|
||||
@FXML
|
||||
private TextField contract_latest_date;
|
||||
|
||||
@FXML
|
||||
private TextField contract_latest_id;
|
||||
|
||||
@FXML
|
||||
private TextField sync_elapse;
|
||||
@FXML
|
||||
private ToggleSwitch use_latest_id;
|
||||
|
||||
LocalDateConfig config1 = new LocalDateConfig(CompanyCtx.AUTO_CREATE_COMPANY_AFTER);
|
||||
LocalDateTimeConfig config2 = new LocalDateTimeConfig(ContractCtx.KEY_SYNC_BY_LATEST_DATE);
|
||||
StringConfig config3 = new StringConfig(ContractCtx.KEY_SYNC_BY_LATEST_ID);
|
||||
StringConfig config4 = new StringConfig(ContractCtx.KEY_SYNC_ELAPSE);
|
||||
BooleanConfig config5 = new BooleanConfig(ContractCtx.KEY_SYNC_USE_LATEST_ID);
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().set("用友U8配置");
|
||||
|
||||
auto_create_company_after.setConverter(getCurrentEmployee().getLocalDateStringConverter());
|
||||
config1.setControl(auto_create_company_after);
|
||||
config1.initialize();
|
||||
|
||||
config2.setControl(contract_latest_date);
|
||||
config2.setControlConverter(getCurrentEmployee().getLocalDateTimeStringConverter());
|
||||
config2.initialize();
|
||||
|
||||
config3.setControl(contract_latest_id);
|
||||
config3.initialize();
|
||||
|
||||
config4.setControl(sync_elapse);
|
||||
config4.initialize();
|
||||
|
||||
config5.setControl(use_latest_id);
|
||||
config5.initialize();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.cloud.u8.YongYouU8Service;
|
||||
import com.ecep.contract.controller.company.CompanyWindowController;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.model.CloudYu;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.ui.table.cell.CompanyTableCell;
|
||||
import com.ecep.contract.ui.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.vm.CloudYuInfoViewModel;
|
||||
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import lombok.Setter;
|
||||
|
||||
public class YongYouU8ManagerSkin
|
||||
extends
|
||||
AbstEntityManagerSkin<CloudYu, CloudYuInfoViewModel, YongYouU8ManagerSkin, YongYouU8ManagerWindowController>
|
||||
implements ManagerSkin {
|
||||
@Setter
|
||||
private YongYouU8Service u8Service;
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
|
||||
public YongYouU8ManagerSkin(YongYouU8ManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
YongYouU8Service getU8Service() {
|
||||
if (u8Service == null) {
|
||||
u8Service = SpringApp.getBean(YongYouU8Service.class);
|
||||
}
|
||||
return u8Service;
|
||||
}
|
||||
|
||||
CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = SpringApp.getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<CloudYuInfoViewModel> loadTableData() {
|
||||
String searchText = controller.searchKeyField.getText();
|
||||
Specification<CloudYu> spec = null;
|
||||
if (StringUtils.hasText(searchText)) {
|
||||
|
||||
Specification<CloudYu> companySpec = (root, query, builder) -> {
|
||||
Path<Object> company = root.get("company");
|
||||
return builder.or(
|
||||
builder.like(company.get("name"), "%" + searchText + "%"),
|
||||
builder.like(company.get("shortName"), "%" + searchText + "%"));
|
||||
};
|
||||
|
||||
Specification<CloudYu> cloudIdSpec = (root, query, builder) -> {
|
||||
return builder.like(root.get("cloudId"), "%" + searchText + "%");
|
||||
};
|
||||
|
||||
Specification<CloudYu> exceptionSpec = (root, query, builder) -> {
|
||||
return builder.like(root.get("exceptionMessage"), "%" + searchText + "%");
|
||||
};
|
||||
spec = Specification.anyOf(companySpec, cloudIdSpec, exceptionSpec);
|
||||
}
|
||||
|
||||
Page<CloudYu> page = getU8Service().findAll(spec, getPageable());
|
||||
updateFooter(page);
|
||||
return page.map(CloudYuInfoViewModel::from).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
controller.companyColumn.setCellValueFactory(param -> param.getValue().getCompany());
|
||||
controller.companyColumn.setCellFactory(param -> new CompanyTableCell<>(getCompanyService()));
|
||||
|
||||
controller.cloudIdColumn.setCellValueFactory(param -> param.getValue().getCloudId());
|
||||
|
||||
controller.latestUpdateColumn.setCellValueFactory(param -> param.getValue().getLatest());
|
||||
controller.latestUpdateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.cloudLatestColumn.setCellValueFactory(param -> param.getValue().getCloudLatest());
|
||||
controller.cloudLatestColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
controller.descriptionColumn.setCellValueFactory(param -> param.getValue().getVendorCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
MenuItem item2 = new MenuItem("刷新");
|
||||
item2.setOnAction(this::onTableRefreshAction);
|
||||
|
||||
MenuItem item3 = new MenuItem("清空备注");
|
||||
item3.setOnAction(this::onTableClearDescriptionAction);
|
||||
|
||||
contextMenu.getItems().addAll(item2, item3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请空选择行的注释
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
public void onTableClearDescriptionAction(ActionEvent event) {
|
||||
ObservableList<CloudYuInfoViewModel> selectedItems = getTableView().getSelectionModel().getSelectedItems();
|
||||
if (selectedItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (CloudYuInfoViewModel selectedItem : selectedItems) {
|
||||
CloudYu cloudYu = getU8Service().findById(selectedItem.getId().get());
|
||||
selectedItem.getCustomerCode().set("");
|
||||
if (selectedItem.copyTo(cloudYu)) {
|
||||
CloudYu saved = getU8Service().save(cloudYu);
|
||||
selectedItem.update(saved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CloudYuInfoViewModel item) {
|
||||
Company company = item.getCompany().get();
|
||||
if (!Hibernate.isInitialized(item)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
}
|
||||
CompanyWindowController.show(company, getTableView().getScene().getWindow());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.ecep.contract.controller;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.model.CloudYu;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.vm.CloudYuInfoViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/cloud/u8_manager.fxml")
|
||||
public class YongYouU8ManagerWindowController
|
||||
extends AbstManagerWindowController<CloudYu, CloudYuInfoViewModel, YongYouU8ManagerSkin> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(YongYouU8ManagerWindowController.class);
|
||||
|
||||
public static void show() {
|
||||
show(YongYouU8ManagerWindowController.class, null);
|
||||
}
|
||||
|
||||
public TableColumn<CloudYuInfoViewModel, Number> idColumn;
|
||||
public TableColumn<CloudYuInfoViewModel, LocalDateTime> latestUpdateColumn;
|
||||
public TableColumn<CloudYuInfoViewModel, Company> companyColumn;
|
||||
public TableColumn<CloudYuInfoViewModel, String> cloudIdColumn;
|
||||
public TableColumn<CloudYuInfoViewModel, LocalDateTime> cloudLatestColumn;
|
||||
public TableColumn<CloudYuInfoViewModel, String> descriptionColumn;
|
||||
|
||||
@Override
|
||||
public YongYouU8Service getViewModelService() {
|
||||
return getSkin().getU8Service();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected YongYouU8ManagerSkin createDefaultSkin() {
|
||||
return new YongYouU8ManagerSkin(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("用友U8");
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开配置窗口
|
||||
*/
|
||||
public void onConfigAction(ActionEvent event) {
|
||||
BaseController.show(YongYouU8ConfigWindowController.class, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据迁移,从 CloudInfo 迁移到 CloudRk
|
||||
*/
|
||||
public void onDateTransferAction(ActionEvent event) {
|
||||
DateTransferTask task = new DateTransferTask();
|
||||
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
|
||||
}
|
||||
|
||||
public void onPersonSyncAction(ActionEvent event) {
|
||||
EmployeesSyncTask task = new EmployeesSyncTask();
|
||||
UITools.showTaskDialogAndWait("员工数据同步", task, null);
|
||||
}
|
||||
|
||||
public void onContractSyncAction(ActionEvent event) {
|
||||
ContractSyncTask task = new ContractSyncTask();
|
||||
UITools.showTaskDialogAndWait("合同数据增量同步", task, null);
|
||||
}
|
||||
|
||||
public void onContractAllSyncAction(ActionEvent event) {
|
||||
ContractSyncAllTask task = new ContractSyncAllTask();
|
||||
UITools.showTaskDialogAndWait("合同数据全量同步", task, null);
|
||||
}
|
||||
|
||||
public void onVendorSyncAction(ActionEvent event) {
|
||||
VendorSyncTask task = new VendorSyncTask();
|
||||
UITools.showTaskDialogAndWait("供应商数据同步", task, null);
|
||||
}
|
||||
|
||||
public void onCustomerSyncAction(ActionEvent event) {
|
||||
CustomerSyncTask task = new CustomerSyncTask();
|
||||
UITools.showTaskDialogAndWait("客户数据同步", task, null);
|
||||
}
|
||||
|
||||
public void onContractGroupSyncAction(ActionEvent event) {
|
||||
ContractGroupSyncTask task = new ContractGroupSyncTask();
|
||||
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
|
||||
}
|
||||
|
||||
public void onContractTypeSyncAction(ActionEvent event) {
|
||||
ContractTypeSyncTask task = new ContractTypeSyncTask();
|
||||
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
|
||||
}
|
||||
|
||||
public void onContractKindSyncAction(ActionEvent event) {
|
||||
ContractKindSyncTask task = new ContractKindSyncTask();
|
||||
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
|
||||
}
|
||||
|
||||
public void onVendorClassSyncAction(ActionEvent event) {
|
||||
VendorClassSyncTask task = new VendorClassSyncTask();
|
||||
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
|
||||
}
|
||||
|
||||
public void onCustomerClassSyncAction(ActionEvent event) {
|
||||
CustomerClassSyncTask task = new CustomerClassSyncTask();
|
||||
Desktop.instance.getTaskMonitorCenter().registerAndStartTask(task);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.ecep.contract.controller.bank;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.controller.ManagerSkin;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.model.Bank;
|
||||
import com.ecep.contract.vm.BankViewModel;
|
||||
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
|
||||
|
||||
public class BankManagerSkin
|
||||
extends AbstEntityManagerSkin<Bank, BankViewModel, BankManagerSkin, BankManagerWindowController>
|
||||
implements ManagerSkin, EditableEntityTableTabSkin<Bank, BankViewModel> {
|
||||
|
||||
public BankManagerSkin(BankManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
getTableView().setEditable(true);
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
controller.codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
controller.codeColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.codeColumn.setOnEditCommit(this::onCodeColumnEditCommit);
|
||||
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
controller.nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.nameColumn.setOnEditCommit(this::onNameColumnEditCommit);
|
||||
|
||||
}
|
||||
|
||||
private void onCodeColumnEditCommit(TableColumn.CellEditEvent<BankViewModel, String> event) {
|
||||
acceptCellEditEvent(event, BankViewModel::getCode);
|
||||
}
|
||||
|
||||
private void onNameColumnEditCommit(TableColumn.CellEditEvent<BankViewModel, String> event) {
|
||||
acceptCellEditEvent(event, BankViewModel::getName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.ecep.contract.controller.bank;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.BankService;
|
||||
import com.ecep.contract.model.Bank;
|
||||
import com.ecep.contract.vm.BankViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/bank-manager.fxml")
|
||||
public class BankManagerWindowController
|
||||
extends AbstManagerWindowController<Bank, BankViewModel, BankManagerSkin> {
|
||||
|
||||
@Autowired
|
||||
private BankService bankService;
|
||||
|
||||
public TableColumn<BankViewModel, Number> idColumn;
|
||||
public TableColumn<BankViewModel, String> nameColumn;
|
||||
public TableColumn<BankViewModel, String> codeColumn;
|
||||
|
||||
@Override
|
||||
protected BankManagerSkin createDefaultSkin() {
|
||||
return new BankManagerSkin(this);
|
||||
}
|
||||
|
||||
public void onCreateNewAction(ActionEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void onReBuildFilesAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BankService getViewModelService() {
|
||||
return bankService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.ecep.contract.controller.bank.account;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.controller.company.CompanyWindowController;
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.converter.BankStringConverter;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.CompanyBankAccount;
|
||||
import com.ecep.contract.service.BankService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.service.CompanyStringConverter;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CompanyBankAccountViewModel;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import lombok.Setter;
|
||||
|
||||
public class BankAccountBaseTabSkin
|
||||
extends AbstEntityBasedTabSkin<BankAccountWindowController, CompanyBankAccount, CompanyBankAccountViewModel>
|
||||
implements TabSkin {
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
@Setter
|
||||
private BankService bankService;
|
||||
|
||||
public BankAccountBaseTabSkin(BankAccountWindowController controller) {
|
||||
super(controller);
|
||||
viewModel = controller.getViewModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
initializeBaseTabCompanyFieldAutoCompletion(controller.companyField);
|
||||
initializeBaseTabBankFieldAutoCompletion(controller.bankField);
|
||||
|
||||
controller.openingBankField.textProperty().bindBidirectional(viewModel.getOpeningBank());
|
||||
controller.bankAccountField.textProperty().bindBidirectional(viewModel.getAccount());
|
||||
|
||||
// controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());
|
||||
controller.createdField.textProperty().bind(viewModel.getCreated().asString());
|
||||
controller.versionLabel.textProperty().bind(viewModel.getVersion().asString());
|
||||
|
||||
controller.relativeCompanyBtn.disableProperty().bind(viewModel.getCompany().isNull());
|
||||
controller.relativeCompanyBtn.setOnAction(event -> {
|
||||
Company company = viewModel.getCompany().get();
|
||||
if (company != null) {
|
||||
CompanyWindowController.show(company, controller.root.getScene().getWindow());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeBaseTabCompanyFieldAutoCompletion(TextField textField) {
|
||||
CompanyStringConverter converter = SpringApp.getBean(CompanyStringConverter.class);
|
||||
UITools.autoCompletion(textField, viewModel.getCompany(), converter::suggest, converter);
|
||||
}
|
||||
|
||||
private void initializeBaseTabBankFieldAutoCompletion(TextField textField) {
|
||||
BankStringConverter converter = SpringApp.getBean(BankStringConverter.class);
|
||||
UITools.autoCompletion(textField, viewModel.getBank(), converter::suggest, converter);
|
||||
}
|
||||
|
||||
public BankService getBankService() {
|
||||
if (bankService == null) {
|
||||
bankService = getBean(BankService.class);
|
||||
}
|
||||
return bankService;
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.ecep.contract.controller.bank.account;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.company.service.CompanyBankAccountService;
|
||||
import com.ecep.contract.model.CompanyBankAccount;
|
||||
import com.ecep.contract.vm.CompanyBankAccountViewModel;
|
||||
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/company/bank-account.fxml")
|
||||
public class BankAccountWindowController extends AbstEntityController<CompanyBankAccount, CompanyBankAccountViewModel> {
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
|
||||
public Tab baseInfoTab;
|
||||
public TextField companyField;
|
||||
public Button relativeCompanyBtn;
|
||||
public TextField bankField;
|
||||
public TextField openingBankField;
|
||||
public TextField bankAccountField;
|
||||
public TextField createdField;
|
||||
public TextArea descriptionField;
|
||||
public Label versionLabel;
|
||||
|
||||
public Tab entityTab;
|
||||
|
||||
|
||||
public static void show(CompanyBankAccountViewModel viewModel, Window window) {
|
||||
show(BankAccountWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CompanyBankAccountService bankAccountService;
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent event) {
|
||||
super.onShown(event);
|
||||
getTitle().set("[" + viewModel.getId().get() + "] 银行账户详情");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab -> new BankAccountBaseTabSkin(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompanyBankAccountService getViewModelService() {
|
||||
return bankAccountService;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.ecep.contract.controller.company;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.vm.CompanyViewModel;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
|
||||
public abstract class AbstCompanyBasedTabSkin
|
||||
extends AbstEntityBasedTabSkin<CompanyWindowController, Company, CompanyViewModel>
|
||||
implements TabSkin {
|
||||
|
||||
public AbstCompanyBasedTabSkin(CompanyWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
protected CompanyService getCompanyService() {
|
||||
Task<CompanyService> task = new Task<>() {
|
||||
@Override
|
||||
protected CompanyService call() throws Exception {
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
};
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.ecep.contract.controller.company;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.controller.table.TableOfTabSkin;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.vm.CompanyBasedViewModel;
|
||||
import com.ecep.contract.vm.CompanyViewModel;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
import lombok.Setter;
|
||||
|
||||
public abstract class AbstCompanyTableTabSkin<T extends IdentityEntity, TV extends IdentityViewModel<T>>
|
||||
extends AbstEntityTableTabSkin<CompanyWindowController, Company, CompanyViewModel, T, TV>
|
||||
implements TabSkin, TableOfTabSkin<Company, T, TV> {
|
||||
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
|
||||
public AbstCompanyTableTabSkin(CompanyWindowController controller) {
|
||||
super(controller);
|
||||
viewModel = controller.getViewModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TV createNewViewModel() {
|
||||
TV model = super.createNewViewModel();
|
||||
if (model instanceof CompanyBasedViewModel m) {
|
||||
m.getCompany().set(getEntity());
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
protected CompanyService getCompanyService() {
|
||||
return getParentService();
|
||||
}
|
||||
|
||||
protected CompanyService getParentService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getSpecification(Company parent) {
|
||||
Map<String, Object> params = getSpecification();
|
||||
params.put("company", parent.getId());
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package com.ecep.contract.controller.company;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.util.FxmlUtils;
|
||||
import com.ecep.contract.ds.company.repository.CompanyContactRepository;
|
||||
import com.ecep.contract.model.CompanyContact;
|
||||
import com.ecep.contract.vm.CompanyContactViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
public class CompanyContactWindowController extends BaseController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyContactWindowController.class);
|
||||
/**
|
||||
* 显示界面
|
||||
*/
|
||||
public static void show(CompanyContactViewModel viewModel, Window window) {
|
||||
String key = toKey(viewModel);
|
||||
// 一个合同一个界面
|
||||
if (toFront(key)) {
|
||||
return;
|
||||
}
|
||||
FxmlUtils.newLoaderAsyncWithRunLater("/ui/contact.fxml", null, loader -> {
|
||||
CompanyContactWindowController controller = loader.getController();
|
||||
controller.setViewModel(viewModel);
|
||||
controller.show(loader, window, Modality.NONE, key);
|
||||
});
|
||||
}
|
||||
|
||||
private static String toKey(CompanyContactViewModel viewModel) {
|
||||
return viewModel.getClass().getName() + "-" + viewModel.getId().get();
|
||||
}
|
||||
|
||||
public Tab baseInfoTab;
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private CompanyContactViewModel viewModel;
|
||||
@Autowired
|
||||
private CompanyContactRepository companyContactRepository;
|
||||
|
||||
public TextField nameField;
|
||||
public TextField positionField;
|
||||
public TextField phoneField;
|
||||
public DatePicker createdField;
|
||||
public TextField u8CodeField;
|
||||
public TextField emailField;
|
||||
public TextField addressField;
|
||||
public TextArea descriptionField;
|
||||
public Label versionLabel;
|
||||
public Button saveBtn;
|
||||
|
||||
private CompletableFuture<CompanyContact> companyContactLoadedFuture;
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().bind(viewModel.getName().map(v -> "[" + viewModel.getId().get() + "] " + viewModel.getName().getValue() + " 曾用名详情"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("onShown");
|
||||
}
|
||||
|
||||
initializeBaseTab();
|
||||
|
||||
companyContactLoadedFuture = CompletableFuture.supplyAsync(() -> {
|
||||
Optional<CompanyContact> optional = companyContactRepository.findById(viewModel.getId().get());
|
||||
if (optional.isPresent()) {
|
||||
CompanyContact oldName = optional.get();
|
||||
Platform.runLater(() -> {
|
||||
viewModel.update(oldName);
|
||||
viewModel.bindListener();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("bind ViewModel({}) Listener", viewModel.getName().get());
|
||||
}
|
||||
tabPane.getSelectionModel().getSelectedItem().getOnSelectionChanged().handle(null);
|
||||
});
|
||||
return oldName;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void initializeBaseTab() {
|
||||
baseInfoTab.setOnSelectionChanged(event -> {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("baseInfoTab OnSelectionChanged");
|
||||
}
|
||||
if (baseInfoTab.isSelected()) {
|
||||
onBaseTabShown();
|
||||
}
|
||||
});
|
||||
saveBtn.disableProperty().bind(viewModel.getChanged().not());
|
||||
saveBtn.setOnAction(event -> {
|
||||
try {
|
||||
CompanyContact contact = companyContactLoadedFuture.join();
|
||||
viewModel.copyTo(contact);
|
||||
CompanyContact saved = companyContactRepository.save(contact);
|
||||
viewModel.update(saved);
|
||||
companyContactLoadedFuture = CompletableFuture.completedFuture(saved);
|
||||
} catch (Exception e) {
|
||||
UITools.showExceptionAndWait("保存失败,请检查", e);
|
||||
}
|
||||
});
|
||||
|
||||
nameField.textProperty().bindBidirectional(viewModel.getName());
|
||||
positionField.textProperty().bindBidirectional(viewModel.getPosition());
|
||||
phoneField.textProperty().bindBidirectional(viewModel.getPhone());
|
||||
emailField.textProperty().bindBidirectional(viewModel.getEmail());
|
||||
addressField.textProperty().bindBidirectional(viewModel.getAddress());
|
||||
LocalDateStringConverter converter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
createdField.setConverter(converter);
|
||||
createdField.valueProperty().bindBidirectional(viewModel.getCreated());
|
||||
u8CodeField.textProperty().bind(viewModel.getU8Code());
|
||||
descriptionField.textProperty().bindBidirectional(viewModel.getMemo());
|
||||
versionLabel.textProperty().bind(viewModel.getVersion().asString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础页显示时回调函数
|
||||
*/
|
||||
private void onBaseTabShown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("onBaseTabShown");
|
||||
}
|
||||
companyContactLoadedFuture.thenAcceptAsync(contact -> {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("onBaseTabShown company contact {}", contact.getName());
|
||||
}
|
||||
// viewModel.update(contact);
|
||||
}).exceptionally(ex -> {
|
||||
UITools.showExceptionAndWait(ex.getMessage(), ex);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public void onHidden(WindowEvent windowEvent) {
|
||||
if (viewModel != null) {
|
||||
try {
|
||||
viewModel.unBindListener();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("unbind ViewModel({}) Listener", viewModel.getName().get());
|
||||
}
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
super.onHidden(windowEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.ecep.contract.controller.company;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.ecep.contract.ds.company.controller.CompanyWindowController;
|
||||
import com.ecep.contract.ds.company.service.CompanyOldNameService;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.ui.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.vm.CompanyViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.TextInputDialog;
|
||||
import lombok.Setter;
|
||||
|
||||
public class CompanyManagerSkin
|
||||
extends AbstEntityManagerSkin<Company, CompanyViewModel, CompanyManagerSkin, CompanyManagerWindowController> {
|
||||
|
||||
@Setter
|
||||
private CompanyOldNameService companyOldNameService;
|
||||
|
||||
public CompanyManagerSkin(CompanyManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
|
||||
public CompanyOldNameService getCompanyOldNameService() {
|
||||
if (companyOldNameService == null) {
|
||||
companyOldNameService = getBean(CompanyOldNameService.class);
|
||||
}
|
||||
return companyOldNameService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
controller.uniscidColumn.setCellValueFactory(param -> param.getValue().getUid());
|
||||
controller.entStatusColumn.setCellValueFactory(param -> param.getValue().getEntStatus());
|
||||
controller.createdColumn.setCellValueFactory(param -> param.getValue().getCreated());
|
||||
controller.memoColumn.setCellValueFactory(param -> param.getValue().getMemo());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
getTableView().getSortOrder().add(controller.createdColumn);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CompanyViewModel item) {
|
||||
showInOwner(CompanyWindowController.class, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableCreateNewAction(ActionEvent event) {
|
||||
Platform.runLater(() -> {
|
||||
TextInputDialog dialog = new TextInputDialog();
|
||||
dialog.setTitle("新建公司");
|
||||
dialog.setHeaderText("请输入新建的公司名称,请输入公司名字全称");
|
||||
Optional<String> optional = dialog.showAndWait();
|
||||
if (optional.isPresent()) {
|
||||
CompanyService companyService = getCompanyService();
|
||||
String newCompanyName = optional.get();
|
||||
List<Company> list = companyService.findAllByName(newCompanyName);
|
||||
if (list == null || list.isEmpty()) {
|
||||
// 未登记过
|
||||
Company company = companyService.createNewCompany(newCompanyName);
|
||||
Company saved = companyService.save(company);
|
||||
CompanyWindowController.show(saved, getTableView().getScene().getWindow());
|
||||
} else {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setTitle("新建公司");
|
||||
alert.setHeaderText("公司名称 " + newCompanyName + " 已经存在,是否打开公司页面");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.ecep.contract.controller.company;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.company.controller.CompanyManagerSkin;
|
||||
import com.ecep.contract.ds.company.controller.CompanyVerifyWindowController;
|
||||
import com.ecep.contract.ds.company.tasker.CompanyFilesRebuildTasker;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.ui.AbstManagerWindowController;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CompanyViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/company/company-manager.fxml")
|
||||
public class CompanyManagerWindowController
|
||||
extends AbstManagerWindowController<Company, CompanyViewModel, CompanyManagerSkin> {
|
||||
|
||||
// columns
|
||||
@FXML
|
||||
public TableColumn<CompanyViewModel, Number> idColumn;
|
||||
@FXML
|
||||
public TableColumn<CompanyViewModel, String> nameColumn;
|
||||
@FXML
|
||||
public TableColumn<CompanyViewModel, String> uniscidColumn;
|
||||
@FXML
|
||||
public TableColumn<CompanyViewModel, String> entStatusColumn;
|
||||
@FXML
|
||||
public TableColumn<CompanyViewModel, LocalDate> createdColumn;
|
||||
@FXML
|
||||
public TableColumn<CompanyViewModel, String> memoColumn;
|
||||
|
||||
@Autowired
|
||||
private CompanyService companyService;
|
||||
|
||||
@Override
|
||||
public CompanyService getViewModelService() {
|
||||
return companyService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("公司管理");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompanyManagerSkin createDefaultSkin() {
|
||||
return new CompanyManagerSkin(this);
|
||||
}
|
||||
|
||||
public void onCompanyCreateNewAction(ActionEvent event) {
|
||||
getSkin().onTableCreateNewAction(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对所有公司的文件进行重置
|
||||
* <p>
|
||||
* 弹出对话框模式,对话框中有进度条和重置的消息
|
||||
*
|
||||
* @param event 事件
|
||||
*/
|
||||
public void onReBuildFilesAction(ActionEvent event) {
|
||||
CompanyFilesRebuildTasker task = new CompanyFilesRebuildTasker();
|
||||
UITools.showTaskDialogAndWait("公司文件重置", task, null);
|
||||
}
|
||||
|
||||
public void onVerifyAction(ActionEvent event) {
|
||||
show(CompanyVerifyWindowController.class, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.ecep.contract.controller.company;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/company/company-verify.fxml")
|
||||
public class CompanyVerifyWindowController extends BaseController {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
package com.ecep.contract.controller.company;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.DesktopUtils;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.customer.CompanyCustomerWindowController;
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinBankAccount;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinBase;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinBlackReason;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinContact;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinContract;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinFile;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinInvoice;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinOldName;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinOther;
|
||||
import com.ecep.contract.controller.tab.CompanyTabSkinPurchaseBillVoucher;
|
||||
import com.ecep.contract.controller.vendor.CompanyVendorWindowController;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.model.CompanyVendor;
|
||||
import com.ecep.contract.service.CompanyCustomerService;
|
||||
import com.ecep.contract.service.CompanyFileService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.service.CompanyVendorService;
|
||||
import com.ecep.contract.service.ContractService;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CompanyViewModel;
|
||||
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/company/company.fxml")
|
||||
public class CompanyWindowController
|
||||
extends AbstEntityController<Company, CompanyViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyWindowController.class);
|
||||
|
||||
public static void show(Company company, Window window) {
|
||||
CompanyViewModel viewModel = new CompanyViewModel();
|
||||
if (!Hibernate.isInitialized(company)) {
|
||||
company = SpringApp.getBean(CompanyService.class).findById(company.getId());
|
||||
}
|
||||
viewModel.update(company);
|
||||
show(viewModel, window);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示界面
|
||||
*/
|
||||
public static void show(CompanyViewModel viewModel, Window window) {
|
||||
show(CompanyWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private CompanyService companyService;
|
||||
@Autowired
|
||||
private CompanyFileService companyFileService;
|
||||
@Autowired
|
||||
private ContractService contractService;
|
||||
@Autowired
|
||||
private CompanyCustomerService companyCustomerService;
|
||||
@Autowired
|
||||
private CompanyVendorService companyVendorService;
|
||||
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
public Tab baseInfoTab;
|
||||
public Tab oldNameTab;
|
||||
public Tab contactTab;
|
||||
public Tab blackReasonTab;
|
||||
public Tab customerTab;
|
||||
public Tab vendorTab;
|
||||
public Tab bankAccountTab;
|
||||
public Tab contractTab;
|
||||
public Tab fileTab;
|
||||
public Tab invoiceTab;
|
||||
public Tab purchaseBillVoucherTab;
|
||||
public Tab otherTab;
|
||||
/*
|
||||
|
||||
*/
|
||||
public TextField nameField;
|
||||
public TextField shortNameField;
|
||||
public TextField uidField;
|
||||
public TextField entStatusField;
|
||||
public DatePicker setupDateField;
|
||||
public TextField entTypeField;
|
||||
public TextField industryField;
|
||||
public TextField districtField;
|
||||
public CheckBox pathExistField;
|
||||
public TextField pathField;
|
||||
public DatePicker createdDateField;
|
||||
public TextField telephoneField;
|
||||
public TextField regAddressField;
|
||||
public TextField addressField;
|
||||
public TextField registeredCapitalField;
|
||||
public TextField registeredCapitalCurrencyField;
|
||||
public TextField legalRepresentativeField;
|
||||
public DatePicker operationPeriodBeginField;
|
||||
public DatePicker operationPeriodEndField;
|
||||
public TextArea memoField;
|
||||
public Label versionLabel;
|
||||
public Button companyRenameBtn;
|
||||
public Button companyPathCreateBtn;
|
||||
public Button companyPathChangeBtn;
|
||||
public Button companyPathSameAsNameBtn;
|
||||
|
||||
// private final CompanyCustomerViewModel companyCustomerViewModel = new
|
||||
// CompanyCustomerViewModel();
|
||||
// private final CompanyVendorViewModel companyVendorViewModel = new
|
||||
// CompanyVendorViewModel();
|
||||
|
||||
private final SimpleObjectProperty<CompanyCustomer> companyCustomerProperty = new SimpleObjectProperty<>();
|
||||
private final SimpleObjectProperty<CompanyVendor> companyVendorProperty = new SimpleObjectProperty<>();
|
||||
|
||||
public Pane customerTab_pane1;
|
||||
public Button customerTab_openBtn;
|
||||
public Pane customerTab_pane2;
|
||||
public Button customerTab_createBtn;
|
||||
|
||||
public Pane vendorTab_pane1;
|
||||
public Button vendorTab_openBtn;
|
||||
public Pane vendorTab_pane2;
|
||||
public Button vendorTab_createBtn;
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
stage.minWidthProperty().set(600);
|
||||
stage.minHeightProperty().set(450);
|
||||
getTitle().set("[" + viewModel.getId().get() + "] " + viewModel.getName().getValue() + " 公司详情");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Company loadEntity() {
|
||||
return companyService.findById(viewModel.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Company saveEntity(Company entity) {
|
||||
return companyService.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab1 -> new CompanyTabSkinBase(this));
|
||||
registerTabSkin(oldNameTab, tab1 -> new CompanyTabSkinOldName(this));
|
||||
registerTabSkin(contactTab, tab1 -> new CompanyTabSkinContact(this));
|
||||
registerTabSkin(blackReasonTab, tab1 -> new CompanyTabSkinBlackReason(this));
|
||||
registerTabSkin(bankAccountTab, tab1 -> new CompanyTabSkinBankAccount(this));
|
||||
registerTabSkin(contractTab, tab -> new CompanyTabSkinContract(this));
|
||||
registerTabSkin(fileTab, tab -> new CompanyTabSkinFile(this));
|
||||
registerTabSkin(invoiceTab, tab -> new CompanyTabSkinInvoice(this));
|
||||
registerTabSkin(purchaseBillVoucherTab, tab -> new CompanyTabSkinPurchaseBillVoucher(this));
|
||||
registerTabSkin(otherTab, tab -> new CompanyTabSkinOther(this));
|
||||
|
||||
initializeVendorTab();
|
||||
initializeCustomerTab();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <K extends AbstEntityBasedTabSkin<?, ?, ?>> K registerTabSkin(Tab tab, Function<Tab, K> func) {
|
||||
K skin = super.registerTabSkin(tab, func);
|
||||
if (skin instanceof AbstCompanyBasedTabSkin b) {
|
||||
b.setViewModel(viewModel);
|
||||
}
|
||||
return skin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompanyService getViewModelService() {
|
||||
return companyService;
|
||||
}
|
||||
|
||||
private void initializeCustomerTab() {
|
||||
customerTab.setOnSelectionChanged(event -> {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("customerTab OnSelectionChanged");
|
||||
}
|
||||
if (customerTab.isSelected()) {
|
||||
onCustomerTabShown();
|
||||
}
|
||||
});
|
||||
|
||||
customerTab_pane1.visibleProperty().bind(customerTab_pane2.visibleProperty().not());
|
||||
customerTab_pane2.visibleProperty().bind(companyCustomerProperty.isNull());
|
||||
customerTab_createBtn.setOnAction(event -> {
|
||||
// TODO 创建
|
||||
});
|
||||
|
||||
customerTab_openBtn.setOnAction(event -> {
|
||||
CompanyCustomerWindowController.show(companyCustomerProperty.get(), root.getScene().getWindow());
|
||||
});
|
||||
}
|
||||
|
||||
private void onCustomerTabShown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("onCustomerTabShown");
|
||||
}
|
||||
getLoadedFuture().thenAcceptAsync(company -> {
|
||||
companyCustomerProperty.set(companyCustomerService.findByCompany(company));
|
||||
}).exceptionally(ex -> {
|
||||
UITools.showExceptionAndWait(ex.getMessage(), ex);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeVendorTab() {
|
||||
vendorTab.setOnSelectionChanged(event -> {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("vendorTab OnSelectionChanged");
|
||||
}
|
||||
if (vendorTab.isSelected()) {
|
||||
onVendorTabShown();
|
||||
}
|
||||
});
|
||||
|
||||
vendorTab_pane1.visibleProperty().bind(vendorTab_pane2.visibleProperty().not());
|
||||
vendorTab_pane2.visibleProperty().bind(companyVendorProperty.isNull());
|
||||
vendorTab_createBtn.setOnAction(event -> {
|
||||
// TODO 创建
|
||||
});
|
||||
|
||||
vendorTab_openBtn.setOnAction(event -> {
|
||||
CompanyVendorWindowController.show(companyVendorProperty.get(), root.getScene().getWindow());
|
||||
});
|
||||
}
|
||||
|
||||
private void onVendorTabShown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("onVendorTabShown");
|
||||
}
|
||||
getLoadedFuture().thenAcceptAsync(company -> {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("onVendorTabShown company {}", company.getName());
|
||||
}
|
||||
companyVendorProperty.set(companyVendorService.findByCompany(company));
|
||||
}).exceptionally(ex -> {
|
||||
UITools.showExceptionAndWait(ex.getMessage(), ex);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并更新企业信息
|
||||
*/
|
||||
public void onCompanyCompositeUpdateAction(ActionEvent event) {
|
||||
CompanyCompositeUpdateTasker task = new CompanyCompositeUpdateTasker();
|
||||
task.setCompany(getEntity());
|
||||
UITools.showTaskDialogAndWait("更新企业信息", task, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业合规检查
|
||||
*/
|
||||
public void onCompanyVerifyAction(ActionEvent event) {
|
||||
Company company = getEntity();
|
||||
CompanyVerifyTasker task = new CompanyVerifyTasker();
|
||||
task.setCompanyService(companyService);
|
||||
task.setCompany(company);
|
||||
UITools.showTaskDialogAndWait("企业合规性验证", task, null);
|
||||
}
|
||||
|
||||
public void onCompanyOpenInExplorerAction(ActionEvent event) {
|
||||
Company company = getEntity();
|
||||
String path = company.getPath();
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
if (!StringUtils.hasText(path)) {
|
||||
ButtonType buttonType = UITools.showConfirmation("目录未设置", "是否创建目录").join();
|
||||
if (buttonType == ButtonType.OK) {
|
||||
if (companyService.makePathAbsent(company)) {
|
||||
save(company);
|
||||
}
|
||||
} else {
|
||||
setStatus("未设置目录");
|
||||
return;
|
||||
}
|
||||
}
|
||||
DesktopUtils.checkAndShowInExplorer(company.getPath(), this::setStatus);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.ecep.contract.controller.company_old_name;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.model.CompanyOldName;
|
||||
import com.ecep.contract.service.CompanyOldNameService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.vm.CompanyOldNameViewModel;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
|
||||
public class CompanyOldNameTabSkinBase
|
||||
extends AbstEntityBasedTabSkin<CompanyOldNameWindowController, CompanyOldName, CompanyOldNameViewModel>
|
||||
implements TabSkin {
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
@Setter
|
||||
private CompanyOldNameService companyOldNameService;
|
||||
|
||||
public CompanyOldNameTabSkinBase(CompanyOldNameWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
|
||||
controller.nameField.textProperty().bind(viewModel.getName());
|
||||
controller.ambiguityField.selectedProperty().bindBidirectional(viewModel.getAmbiguity());
|
||||
LocalDateStringConverter converter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
controller.startDateField.setConverter(converter);
|
||||
controller.startDateField.valueProperty().bindBidirectional(viewModel.getBeginDate());
|
||||
controller.endDateField.setConverter(converter);
|
||||
controller.endDateField.valueProperty().bindBidirectional(viewModel.getEndDate());
|
||||
|
||||
controller.pathField.textProperty().bind(viewModel.getPath());
|
||||
controller.descriptionField.textProperty().bindBidirectional(viewModel.getMemo());
|
||||
controller.versionLabel.textProperty().bind(viewModel.getVersion().asString());
|
||||
|
||||
controller.saveBtn.disableProperty().bind(viewModel.getChanged().not());
|
||||
controller.saveBtn.setOnAction(this::onSaveAction);
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
public CompanyOldNameService getCompanyOldNameService() {
|
||||
if (companyOldNameService == null) {
|
||||
companyOldNameService = getBean(CompanyOldNameService.class);
|
||||
}
|
||||
return companyOldNameService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
package com.ecep.contract.controller.company_old_name;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.CompanyFileType;
|
||||
import com.ecep.contract.DesktopUtils;
|
||||
import com.ecep.contract.MyProperties;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.company.service.CompanyFileService;
|
||||
import com.ecep.contract.model.CompanyFile;
|
||||
import com.ecep.contract.model.CompanyOldName;
|
||||
import com.ecep.contract.service.CompanyOldNameService;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CompanyFileViewModel;
|
||||
import com.ecep.contract.vm.CompanyOldNameViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.Event;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableView;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class CompanyOldNameTabSkinFile
|
||||
extends
|
||||
AbstEntityTableTabSkin<CompanyOldNameWindowController, CompanyOldName, CompanyOldNameViewModel, CompanyFile, CompanyFileViewModel>
|
||||
implements TabSkin {
|
||||
@Setter
|
||||
private CompanyOldNameService companyOldNameService;
|
||||
@Setter
|
||||
private CompanyFileService companyFileService;
|
||||
@Setter
|
||||
private MyProperties myProperties;
|
||||
|
||||
public CompanyOldNameTabSkinFile(CompanyOldNameWindowController controller) {
|
||||
super(controller);
|
||||
setDragAndDrop(true);
|
||||
setDragAndDropFileHandler(this::moveFileToCompany);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.fileTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableView<CompanyFileViewModel> getTableView() {
|
||||
return controller.fileTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompanyFileService getViewModelService() {
|
||||
return companyFileService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<CompanyFile> getSpecification(CompanyOldName parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, builder) -> {
|
||||
return builder.equal(root.get("company").get("id"), parent.getCompanyId());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
// controller.fileTable_file_move_btn.setOnAction(this::onTableMoveFileAction);
|
||||
// controller.fileTable_file_retrieve_from_download_dir_btn.setOnAction(this::onTableRetrieveFromDownloadDirAction);
|
||||
// controller.fileTable_file_reset_btn.setOnAction(this::onTableResetAction);
|
||||
//
|
||||
//
|
||||
// controller.fileTable_idColumn.setCellValueFactory(param ->
|
||||
// param.getValue().getId());
|
||||
// ObservableMap<CompanyFileType, CompanyFileTypeLocal> observableMapByLocal =
|
||||
// getBean(CompanyFileTypeLocalRepository.class).getObservableMapByLocal();
|
||||
// controller.fileTable_typeColumn.setCellValueFactory(param ->
|
||||
// Bindings.valueAt(observableMapByLocal,
|
||||
// param.getValue().getType()).map(CompanyFileTypeLocal::getValue));
|
||||
// controller.fileTable_filePathColumn.setCellValueFactory(param ->
|
||||
// param.getValue().getFilePath());
|
||||
// controller.fileTable_filePathColumn.setCellFactory(param -> new
|
||||
// FileTableFilePathTableCell());
|
||||
// controller.fileTable_applyDateColumn.setCellValueFactory(param ->
|
||||
// param.getValue().getApplyDate());
|
||||
// controller.fileTable_expiringDateColumn.setCellValueFactory(param ->
|
||||
// param.getValue().getExpiringDate());
|
||||
//
|
||||
//
|
||||
// controller.fileTable_menu_refresh.setOnAction(this::onTableRefreshAction);
|
||||
// controller.fileTable_menu_del.setOnAction(this::onTableDeleteAction);
|
||||
// controller.fileTable_menu_copy_as_matched_by_contract.setOnAction(this::onTableCopyAsMatchedByContractAction);
|
||||
// controller.fileTable_menu_copy_as_matched_by_contract.setOnMenuValidation(this::onTableCopyAsMatchedMenuValidation);
|
||||
|
||||
super.initializeTab();
|
||||
}
|
||||
|
||||
private void onTableResetAction(ActionEvent event) {
|
||||
CompanyOldName oldName = getParent();
|
||||
// CompletableFuture.runAsync(() -> {
|
||||
// if (getCompanyFileService().reBuildingFiles(oldName, this::setStatus)) {
|
||||
// loadTableDataSet();
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 下载目录 中查找相关的资质文件
|
||||
*/
|
||||
private void onTableRetrieveFromDownloadDirAction(ActionEvent event) {
|
||||
// CompanyOldName oldName = getParent();
|
||||
// MyProperties myProperties = getMyProperties();
|
||||
// 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 (getCompanyOldNameService().retrieveFromDownloadFiles(oldName, files,
|
||||
// this::setStatus)) {
|
||||
// // fixed if update
|
||||
// viewModel.update(oldName);
|
||||
// loadTableDataSet();
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 把文件从 老系统中移到 \\10.84.209.8\项目信息\相关方信息 目录中
|
||||
*/
|
||||
private void onTableMoveFileAction(ActionEvent event) {
|
||||
// CompanyFileService companyFileService = getCompanyFileService();
|
||||
// CompanyOldName oldName = getParent();
|
||||
// List<CompanyFile> list = companyFileService.findByCompany(oldName);
|
||||
// if (list.isEmpty()) {
|
||||
// return;
|
||||
// }
|
||||
// if (getCompanyService().makePathAbsent(oldName)) {
|
||||
// save(oldName);
|
||||
// }
|
||||
//
|
||||
// String path = oldName.getPath();
|
||||
// if (!StringUtils.hasText(path)) {
|
||||
// setStatus("异常, 企业目录未设置");
|
||||
// return;
|
||||
// }
|
||||
// File companyPath = new File(path);
|
||||
// for (CompanyFile 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());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private void onTableCopyAsMatchedByContractAction(ActionEvent event) {
|
||||
UITools.showDialogAndWait("复制资信评估报告", "按当前评估报告复制一个合同中最匹配的", list -> {
|
||||
onTableCopyAsMatchedAction_(msg -> {
|
||||
Platform.runLater(() -> {
|
||||
list.add(msg);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void onTableCopyAsMatchedAction_(Consumer<String> state) {
|
||||
// CompanyOldName oldName = getParent();
|
||||
//
|
||||
// CompanyFileViewModel selectedItem =
|
||||
// table.getSelectionModel().getSelectedItem();
|
||||
// if (selectedItem == null) {
|
||||
// state.accept("未选择行");
|
||||
// return;
|
||||
// }
|
||||
// if (selectedItem.getApplyDate().get() == null) {
|
||||
// state.accept("有效日期不能未空");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// LocalDate nextCreditReportDate = null;
|
||||
// try {
|
||||
// nextCreditReportDate = companyFileService.getNextCreditReportDate(oldName,
|
||||
// state);
|
||||
// if (nextCreditReportDate == null) {
|
||||
// state.accept("没有找到下一个咨询评估日期");
|
||||
// return;
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// state.accept("获取下一个咨询评估日期失败:" + e.getMessage());
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// state.accept("下一个咨询评估日期:" + nextCreditReportDate);
|
||||
//
|
||||
// if (!nextCreditReportDate.isBefore(selectedItem.getApplyDate().get())) {
|
||||
// state.accept("咨询评估日期晚于下一个咨询评估日期");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// File src = new File(selectedItem.getFilePath().get());
|
||||
// if (!src.exists()) {
|
||||
// state.accept("当前选择行的文件不存在");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// String srcDate = MyDateTimeUtils.format(selectedItem.getApplyDate().get());
|
||||
// String destDate = MyDateTimeUtils.format(nextCreditReportDate);
|
||||
// String srcFileName = src.getName();
|
||||
// String destFileName;
|
||||
//
|
||||
// // 天眼查的报告
|
||||
// if (CloudTycService.isTycReport(srcFileName)) {
|
||||
// state.accept("天眼查的报告按标准格式命名");
|
||||
// String name = oldName.getName() + "_" + CloudTycService.NAME;
|
||||
// if (srcFileName.contains(CloudTycService.TYC_ENTERPRISE_BASIC_REPORT)) {
|
||||
// name = name + "_" + CloudTycService.TYC_ENTERPRISE_BASIC_REPORT;
|
||||
// } else if (srcFileName.contains(CloudTycService.TYC_ENTERPRISE_MAJOR_REPORT))
|
||||
// {
|
||||
// name = name + "_" + CloudTycService.TYC_ENTERPRISE_MAJOR_REPORT;
|
||||
// } else if
|
||||
// (srcFileName.contains(CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT)) {
|
||||
// name = name + "_" + CloudTycService.TYC_ENTERPRISE_ANALYSIS_REPORT;
|
||||
// }
|
||||
// destFileName = name + "_" + destDate + "_cp." +
|
||||
// StringUtils.getFilenameExtension(srcFileName);
|
||||
// } else {
|
||||
// if (srcFileName.contains(srcDate)) {
|
||||
// // 如果文件名中包含日期,则替换为新日期
|
||||
// destFileName = srcFileName.replace(srcDate, destDate + "_cp");
|
||||
// } else {
|
||||
// // 如果文件名中不包含日期,则添加日期
|
||||
// destFileName = oldName.getName() + "_" + destDate + "_cp." +
|
||||
// StringUtils.getFilenameExtension(srcFileName);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// state.accept("新文件名:" + destFileName);
|
||||
//
|
||||
// File dest = new File(src.getParent(), destFileName);
|
||||
// try {
|
||||
// FileSystemUtils.copyRecursively(src, dest);
|
||||
// state.accept("新文件复制成功");
|
||||
// } catch (IOException e) {
|
||||
// state.accept("新文件复制失败:" + e.getMessage());
|
||||
// }
|
||||
//
|
||||
// CompanyFile companyFile = new CompanyFile();
|
||||
// companyFile.setFilePath(dest.getAbsolutePath());
|
||||
// companyFile.setApplyDate(nextCreditReportDate);
|
||||
// companyFile.setExpiringDate(nextCreditReportDate.plusYears(1));
|
||||
// companyFile.setType(CompanyFileType.CreditReport);
|
||||
// companyFile.setCompany(oldName);
|
||||
// companyFileService.save(companyFile);
|
||||
//
|
||||
// state.accept("新文件已记录");
|
||||
//
|
||||
// loadTableDataSet();
|
||||
// state.accept("文件表已刷新");
|
||||
}
|
||||
|
||||
/**
|
||||
* 当fileTable选中的行是咨询评估时,可用
|
||||
*
|
||||
* @param event event
|
||||
*/
|
||||
public void onTableCopyAsMatchedMenuValidation(Event event) {
|
||||
// 当fileTable选中的行是咨询评估时,可用
|
||||
CompanyFileViewModel selectedItem = getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
event.consume();
|
||||
return;
|
||||
}
|
||||
CompanyFileType type = selectedItem.getType().get();
|
||||
if (type != CompanyFileType.CreditReport) {
|
||||
event.consume();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void moveFileToCompany(List<File> files) {
|
||||
String path = viewModel.getPath().get();
|
||||
if (!StringUtils.hasText(path)) {
|
||||
setStatus("未设置目录");
|
||||
return;
|
||||
}
|
||||
File dir = new File(path);
|
||||
if (!dir.exists()) {
|
||||
setStatus("目录错误,不存在");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CompanyFileViewModel item) {
|
||||
String path = item.getFilePath().get();
|
||||
if (StringUtils.hasText(path)) {
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
setStatus("文件不存在 " + file.getName());
|
||||
return;
|
||||
}
|
||||
DesktopUtils.showInExplorer(file);
|
||||
}
|
||||
}
|
||||
|
||||
class FileTableFilePathTableCell extends TableCell<CompanyFileViewModel, String> {
|
||||
@Override
|
||||
protected void updateItem(String item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
return;
|
||||
}
|
||||
String path = viewModel.getPath().get();
|
||||
if (StringUtils.hasText(path)) {
|
||||
if (item.startsWith(path)) {
|
||||
item = "~" + item.substring(path.length());
|
||||
}
|
||||
}
|
||||
setText(item);
|
||||
}
|
||||
}
|
||||
|
||||
public MyProperties getMyProperties() {
|
||||
if (myProperties == null) {
|
||||
myProperties = getBean(MyProperties.class);
|
||||
}
|
||||
return myProperties;
|
||||
}
|
||||
|
||||
private CompanyFileService getCompanyFileService() {
|
||||
if (companyFileService == null) {
|
||||
companyFileService = getBean(CompanyFileService.class);
|
||||
}
|
||||
return companyFileService;
|
||||
}
|
||||
|
||||
public CompanyOldNameService getCompanyOldNameService() {
|
||||
if (companyOldNameService == null) {
|
||||
companyOldNameService = getBean(CompanyOldNameService.class);
|
||||
}
|
||||
return companyOldNameService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package com.ecep.contract.controller.company_old_name;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.DesktopUtils;
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.model.CompanyOldName;
|
||||
import com.ecep.contract.service.CompanyOldNameService;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CompanyFileViewModel;
|
||||
import com.ecep.contract.vm.CompanyOldNameViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/company/company_old_name.fxml")
|
||||
public class CompanyOldNameWindowController extends AbstEntityController<CompanyOldName, CompanyOldNameViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyOldNameWindowController.class);
|
||||
|
||||
/**
|
||||
* 显示界面
|
||||
*/
|
||||
public static void show(CompanyOldNameViewModel viewModel, Window window) {
|
||||
show(CompanyOldNameWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
public Tab baseInfoTab;
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
public Tab fileTab;
|
||||
|
||||
public TextField nameField;
|
||||
public CheckBox ambiguityField;
|
||||
public DatePicker startDateField;
|
||||
public DatePicker endDateField;
|
||||
public TextField pathField;
|
||||
public TextArea descriptionField;
|
||||
|
||||
public Label versionLabel;
|
||||
public Button saveBtn;
|
||||
public Button saveBtn2;
|
||||
|
||||
public TableView<CompanyFileViewModel> fileTable;
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().set("[" + viewModel.getId().get() + "] " + viewModel.getName().getValue() + " 曾用名详情");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompanyOldName loadEntity() {
|
||||
return getViewModelService().findById(viewModel.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompanyOldName saveEntity(CompanyOldName entity) {
|
||||
return getViewModelService().save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, this::createBaseTabSkin);
|
||||
registerTabSkin(fileTab, this::createFileTabSkin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompanyOldNameService getViewModelService() {
|
||||
return getCachedBean(CompanyOldNameService.class);
|
||||
}
|
||||
|
||||
private CompanyOldNameTabSkinBase createBaseTabSkin(Tab tab) {
|
||||
CompanyOldNameTabSkinBase skin = new CompanyOldNameTabSkinBase(this);
|
||||
skin.setCompanyOldNameService(companyOldNameService);
|
||||
return skin;
|
||||
}
|
||||
|
||||
private CompanyOldNameTabSkinFile createFileTabSkin(Tab tab) {
|
||||
CompanyOldNameTabSkinFile skin = new CompanyOldNameTabSkinFile(this);
|
||||
skin.setCompanyOldNameService(companyOldNameService);
|
||||
// skin.setCompanyFileService(companyFileService);
|
||||
return skin;
|
||||
}
|
||||
|
||||
public void onOldCompanyOpenInExplorerAction(ActionEvent event) {
|
||||
CompanyOldName companyOldName = getEntity();
|
||||
String path = companyOldName.getPath();
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
if (!StringUtils.hasText(path)) {
|
||||
ButtonType buttonType = UITools.showConfirmation("目录未设置", "是否创建目录").join();
|
||||
if (buttonType == ButtonType.OK) {
|
||||
if (companyOldNameService.makePathAbsent(companyOldName)) {
|
||||
save(companyOldName);
|
||||
}
|
||||
} else {
|
||||
setStatus("未设置目录");
|
||||
return;
|
||||
}
|
||||
}
|
||||
File file = new File(companyOldName.getPath());
|
||||
DesktopUtils.showInExplorer(file);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ecep.contract.controller.contract;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.service.ContractService;
|
||||
import com.ecep.contract.vm.ContractViewModel;
|
||||
|
||||
public abstract class AbstContractBasedTabSkin
|
||||
extends AbstEntityBasedTabSkin<ContractWindowController, Contract, ContractViewModel>
|
||||
implements TabSkin {
|
||||
|
||||
public AbstContractBasedTabSkin(ContractWindowController controller) {
|
||||
super(controller);
|
||||
viewModel = controller.getViewModel();
|
||||
}
|
||||
|
||||
public ContractService getContractService() {
|
||||
return controller.contractService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ecep.contract.controller.contract;
|
||||
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.controller.table.TableOfTabSkin;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.contract.vo.ContractViewModel;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
public abstract class AbstContractTableTabSkin<T extends IdentityEntity, TV extends IdentityViewModel<T>>
|
||||
extends AbstEntityTableTabSkin<ContractWindowController, Contract, ContractViewModel, T, TV>
|
||||
implements TabSkin, TableOfTabSkin<Contract, T, TV> {
|
||||
|
||||
public AbstContractTableTabSkin(ContractWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
public ContractService getContractService() {
|
||||
return controller.contractService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<T> getSpecification(Contract parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, builder) -> {
|
||||
return builder.equal(root.get("contract"), parent);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.ecep.contract.controller.contract;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.tab.ContractManagerSkin;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.contract.tasker.ContractFilesRebuildAllTasker;
|
||||
import com.ecep.contract.ds.contract.tasker.ContractRepairAllTasker;
|
||||
import com.ecep.contract.ds.contract.vo.ContractViewModel;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.ContractGroup;
|
||||
import com.ecep.contract.model.ContractKind;
|
||||
import com.ecep.contract.model.ContractType;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.ui.AbstManagerWindowController;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/contract/contract-manager.fxml")
|
||||
public class ContractManagerWindowController
|
||||
extends AbstManagerWindowController<Contract, ContractViewModel, ContractManagerSkin> {
|
||||
|
||||
public ComboBox<ContractGroup> groupSelector;
|
||||
public CheckBox composeViewBtn;
|
||||
|
||||
// columns
|
||||
public TableColumn<ContractViewModel, Number> idColumn;
|
||||
public TableColumn<ContractViewModel, String> nameColumn;
|
||||
public TableColumn<ContractViewModel, String> codeColumn;
|
||||
public TableColumn<ContractViewModel, ContractGroup> groupColumn;
|
||||
public TableColumn<ContractViewModel, ContractType> typeColumn;
|
||||
public TableColumn<ContractViewModel, ContractKind> kindColumn;
|
||||
|
||||
public TableColumn<ContractViewModel, String> parentCodeColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> setupDateColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> orderDateColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> startDateColumn;
|
||||
public TableColumn<ContractViewModel, Employee> employeeColumn;
|
||||
public TableColumn<ContractViewModel, LocalDateTime> createdColumn;
|
||||
public TableColumn<ContractViewModel, Number> amountColumn;
|
||||
public TableColumn<ContractViewModel, Company> companyColumn;
|
||||
|
||||
@Autowired
|
||||
private ContractService contractService;
|
||||
|
||||
@Override
|
||||
public ContractService getViewModelService() {
|
||||
return contractService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractManagerSkin createDefaultSkin() {
|
||||
ContractManagerSkin skin = new ContractManagerSkin(this);
|
||||
return skin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("合同管理");
|
||||
}
|
||||
|
||||
public void onVerifyAction(ActionEvent event) {
|
||||
show(ContractVerifyWindowController.class, null);
|
||||
}
|
||||
|
||||
public void onCreateNewContractAction(ActionEvent event) {
|
||||
// getSkin().onTableCreateNewAction(event);
|
||||
}
|
||||
|
||||
public void onContractFilesRebuildAction(ActionEvent event) {
|
||||
ContractFilesRebuildAllTasker task = new ContractFilesRebuildAllTasker();
|
||||
task.setContractService(contractService);
|
||||
task.setGroup(groupSelector.getValue());
|
||||
UITools.showTaskDialogAndWait("合同文件重置", task, null);
|
||||
}
|
||||
|
||||
public void onContractRepairAllAction(ActionEvent event) {
|
||||
ContractRepairAllTasker task = new ContractRepairAllTasker();
|
||||
UITools.showTaskDialogAndWait("合同同步修复", task, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.ecep.contract.controller.contract;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.contract.service.ExtendVendorInfoService;
|
||||
import com.ecep.contract.ds.contract.vo.ExtendVendorInfoViewModel;
|
||||
import com.ecep.contract.ds.vendor.service.VendorGroupService;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.ExtendVendorInfo;
|
||||
import com.ecep.contract.model.VendorGroup;
|
||||
import com.ecep.contract.ui.ComboBoxUtils;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/contract/contract-tab-ext-vendor-info.fxml")
|
||||
public class ContractTabSkinExtendVendorInfo
|
||||
extends AbstContractBasedTabSkin {
|
||||
|
||||
@Setter
|
||||
private ExtendVendorInfoService extendVendorInfoService;
|
||||
@Setter
|
||||
private VendorGroupService vendorGroupService;
|
||||
|
||||
@FXML
|
||||
public ComboBox<VendorGroup> vendorGroupField;
|
||||
@FXML
|
||||
public Label vendorGroupLabel;
|
||||
@FXML
|
||||
public TextField sequenceNumberField;
|
||||
@FXML
|
||||
public CheckBox assignedProviderField;
|
||||
@FXML
|
||||
public CheckBox prePurchaseField;
|
||||
|
||||
CompletableFuture<ExtendVendorInfo> loadedFuture;
|
||||
private ExtendVendorInfoViewModel viewModel = new ExtendVendorInfoViewModel();
|
||||
|
||||
public ContractTabSkinExtendVendorInfo(ContractWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.extendVendorInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeUIComponents() {
|
||||
super.initializeUIComponents();
|
||||
listenTabSelectionChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanProperty changeProperty() {
|
||||
return viewModel.getChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabShown() {
|
||||
if (loadedFuture == null) {
|
||||
loadedFuture = CompletableFuture.supplyAsync(() -> {
|
||||
initializeTab();
|
||||
Contract contract = getEntity();
|
||||
return loadExtendVendorInfo(contract);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void updateViewModel(ExtendVendorInfo info) {
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
viewModel.update(info);
|
||||
} else {
|
||||
Platform.runLater(() -> viewModel.update(info));
|
||||
}
|
||||
}
|
||||
|
||||
private ExtendVendorInfo loadExtendVendorInfo(Contract contract) {
|
||||
ExtendVendorInfoService service = getExtendVendorInfoService();
|
||||
try {
|
||||
ExtendVendorInfo info = service.findByContract(contract);
|
||||
if (info == null) {
|
||||
info = service.newInstanceByContract(contract);
|
||||
info = service.save(info);
|
||||
}
|
||||
updateViewModel(info);
|
||||
viewModel.bindListener();
|
||||
return info;
|
||||
} catch (Exception e) {
|
||||
UITools.showExceptionAndWait("加载成本时发生错误", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
List<VendorGroup> groups = getVendorGroupService().findAll();
|
||||
ComboBoxUtils.initialComboBox(vendorGroupField, groups, true);
|
||||
vendorGroupField.valueProperty().bindBidirectional(viewModel.getGroup());
|
||||
vendorGroupLabel.textProperty().bind(vendorGroupField.valueProperty().map(v -> {
|
||||
if (v == null) {
|
||||
return "-";
|
||||
}
|
||||
if (!Hibernate.isInitialized(v)) {
|
||||
v = getVendorGroupService().findById(v.getId());
|
||||
viewModel.getGroup().set(v);
|
||||
}
|
||||
return v.getDescription();
|
||||
}));
|
||||
|
||||
sequenceNumberField.textProperty().bindBidirectional(viewModel.getCodeSequenceNumber(),
|
||||
new NumberStringConverter());
|
||||
assignedProviderField.selectedProperty().bindBidirectional(viewModel.getAssignedProvider());
|
||||
assignedProviderField.disableProperty().bind(Bindings.createBooleanBinding(() -> {
|
||||
VendorGroup group = viewModel.getGroup().get();
|
||||
if (group == null) {
|
||||
return false;
|
||||
}
|
||||
return !group.isPriceComparison();
|
||||
}, viewModel.getGroup()));
|
||||
|
||||
prePurchaseField.selectedProperty().bindBidirectional(viewModel.getPrePurchase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
if (loadedFuture != null) {
|
||||
ExtendVendorInfo vendorInfo = loadedFuture.join();
|
||||
if (viewModel.copyTo(vendorInfo)) {
|
||||
ExtendVendorInfo saved = getExtendVendorInfoService().save(vendorInfo);
|
||||
updateViewModel(saved);
|
||||
loadedFuture = CompletableFuture.completedFuture(saved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ExtendVendorInfoService getExtendVendorInfoService() {
|
||||
if (extendVendorInfoService == null) {
|
||||
extendVendorInfoService = SpringApp.getBean(ExtendVendorInfoService.class);
|
||||
}
|
||||
return extendVendorInfoService;
|
||||
}
|
||||
|
||||
public VendorGroupService getVendorGroupService() {
|
||||
if (vendorGroupService == null) {
|
||||
vendorGroupService = SpringApp.getBean(VendorGroupService.class);
|
||||
}
|
||||
return vendorGroupService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,399 @@
|
||||
package com.ecep.contract.controller.contract;
|
||||
|
||||
import static com.ecep.contract.util.TableViewUtils.bindDoubleClicked;
|
||||
import static com.ecep.contract.util.TableViewUtils.bindEnterPressed;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.ContractPayWay;
|
||||
import com.ecep.contract.Message;
|
||||
import com.ecep.contract.MessageHolder;
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.contract.tasker.ContractVerifyComm;
|
||||
import com.ecep.contract.ds.contract.tasker.ContractVerifyResultExportAsExcelFile;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.ds.project.service.SaleTypeService;
|
||||
import com.ecep.contract.ds.vendor.service.VendorGroupService;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.ui.table.cell.EmployeeTableCell;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckMenuItem;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/contract/contract-verify.fxml")
|
||||
public class ContractVerifyWindowController extends BaseController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ContractVerifyWindowController.class);
|
||||
|
||||
@Override
|
||||
public Stage show(FXMLLoader loader, Window owner, Modality modality) {
|
||||
return super.show(loader, owner, modality);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class MessageExt extends Message {
|
||||
private String prefix = null;
|
||||
|
||||
public MessageExt(Level level, String message) {
|
||||
super(level, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Model implements MessageHolder {
|
||||
private SimpleStringProperty code = new SimpleStringProperty();
|
||||
private SimpleStringProperty name = new SimpleStringProperty();
|
||||
private SimpleObjectProperty<Employee> employee = new SimpleObjectProperty<>();
|
||||
private SimpleObjectProperty<LocalDate> setupDate = new SimpleObjectProperty<>();
|
||||
private SimpleListProperty<MessageExt> messages = new SimpleListProperty<>(FXCollections.observableArrayList());
|
||||
|
||||
@Override
|
||||
public void addMessage(Level level, String message) {
|
||||
MessageExt msg = new MessageExt(level, message);
|
||||
messages.add(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageHolder sub(String prefix) {
|
||||
return (level, message) -> {
|
||||
MessageExt msg = new MessageExt(level, message);
|
||||
msg.setPrefix(prefix);
|
||||
msg.setMessage(message);
|
||||
messages.add(msg);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static class StateTableCell extends TableCell<Model, ObservableList<MessageExt>> {
|
||||
Label message2Label(MessageExt message) {
|
||||
Label label = new Label(message.getMessage());
|
||||
label.getStyleClass().add("msg-text");
|
||||
label.getStyleClass().add(message.getLevel().getName().toLowerCase());
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(ObservableList<MessageExt> item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText(null);
|
||||
setGraphic(null);
|
||||
return;
|
||||
}
|
||||
if (item.isEmpty()) {
|
||||
setText("");
|
||||
setGraphic(null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
HBox box = new HBox();
|
||||
box.getStyleClass().add("message-column-ctx");
|
||||
|
||||
// 使用绑定方式监听列表变化,避免重复创建节点
|
||||
List<Label> labels = item.stream().map(this::message2Label).toList();
|
||||
Platform.runLater(() -> box.getChildren().setAll(labels));
|
||||
|
||||
// 监听消息列表变化,动态更新 UI
|
||||
item.addListener((ListChangeListener<? super MessageExt>) change -> {
|
||||
List<MessageExt> messages = new ArrayList<>(change.getList());
|
||||
List<Label> list = messages.stream().map(this::message2Label).toList();
|
||||
Platform.runLater(() -> box.getChildren().setAll(list));
|
||||
});
|
||||
setGraphic(box);
|
||||
} catch (Exception e) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("{} @ {}", e.getMessage(), getTableRow().getItem().getCode(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContractVerifyComm comm = new ContractVerifyComm();
|
||||
|
||||
@Autowired
|
||||
private ProjectSaleTypeService saleTypeService;
|
||||
@Autowired
|
||||
private VendorGroupService vendorGroupService;
|
||||
@Autowired
|
||||
private ContractService contractService;
|
||||
@Autowired
|
||||
private EmployeeService employeeService;
|
||||
|
||||
@FXML
|
||||
public DatePicker setupDateBeginSelector;
|
||||
@FXML
|
||||
public DatePicker setupDateEndSelector;
|
||||
// 企业验证开关
|
||||
@FXML
|
||||
public CheckMenuItem verifyCompanyStatusChecker;
|
||||
@FXML
|
||||
public CheckMenuItem verifyCompanyPathChecker;
|
||||
@FXML
|
||||
public CheckMenuItem verifyCompanyCreditChecker;
|
||||
// 供应商验证开关
|
||||
@FXML
|
||||
public CheckMenuItem verifyVendorChecker;
|
||||
@FXML
|
||||
public CheckMenuItem verifyVendorFileChecker;
|
||||
// 客户验证开关
|
||||
@FXML
|
||||
public CheckMenuItem verifyCustomerChecker;
|
||||
@FXML
|
||||
public CheckMenuItem verifyCustomerFileChecker;
|
||||
@FXML
|
||||
public CheckMenuItem verifyCustomerSubContractDateChecker;
|
||||
|
||||
@FXML
|
||||
public CheckMenuItem onlyShowVerifiedChecker;
|
||||
|
||||
@FXML
|
||||
public TableView<Model> viewTable;
|
||||
private final ObservableList<Model> viewTableDataSet = FXCollections.observableArrayList();
|
||||
@FXML
|
||||
public TableColumn<Model, String> viewTable_codeColumn;
|
||||
@FXML
|
||||
public TableColumn<Model, String> viewTable_nameColumn;
|
||||
@FXML
|
||||
public TableColumn<Model, Employee> viewTable_employeeColumn;
|
||||
@FXML
|
||||
public TableColumn<Model, LocalDate> viewTable_setupDateColumn;
|
||||
@FXML
|
||||
public TableColumn<Model, ObservableList<MessageExt>> viewTable_stateColumn;
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("合同合规验证");
|
||||
}
|
||||
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
comm.setContractService(contractService);
|
||||
viewTable.getScene().getStylesheets().add("/ui/contract/contract-verify.css");
|
||||
|
||||
LocalDate now = LocalDate.now();
|
||||
setupDateBeginSelector.setValue(LocalDate.of(2024, 1, 1));
|
||||
setupDateEndSelector.setValue(now);
|
||||
|
||||
viewTable_codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
viewTable_nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
viewTable_employeeColumn.setCellValueFactory(param -> param.getValue().getEmployee());
|
||||
viewTable_employeeColumn.setCellFactory(param -> new EmployeeTableCell<>(getEmployeeService()));
|
||||
viewTable_setupDateColumn.setCellValueFactory(param -> param.getValue().getSetupDate());
|
||||
// viewTable_stateColumn.setCellValueFactory(param ->
|
||||
// param.getValue().getMessages().map(messages -> {
|
||||
// return
|
||||
// messages.stream().map(Message::getMessage).collect(Collectors.joining(", "));
|
||||
// }));
|
||||
viewTable_stateColumn.setCellValueFactory(param -> param.getValue().getMessages());
|
||||
viewTable_stateColumn.setCellFactory(param -> new StateTableCell());
|
||||
|
||||
viewTable.setItems(viewTableDataSet);
|
||||
|
||||
comm.getVerifyCompanyPath().bind(verifyCompanyPathChecker.selectedProperty());
|
||||
comm.getVerifyCompanyStatus().bind(verifyCompanyStatusChecker.selectedProperty());
|
||||
comm.getVerifyCompanyCredit().bind(verifyCompanyCreditChecker.selectedProperty());
|
||||
comm.getVerifyVendor().bind(verifyVendorChecker.selectedProperty());
|
||||
comm.getVerifyVendorFiles().bind(verifyVendorFileChecker.selectedProperty());
|
||||
comm.getVerifyCustomer().bind(verifyCustomerChecker.selectedProperty());
|
||||
comm.getVerifyCustomerFiles().bind(verifyCustomerFileChecker.selectedProperty());
|
||||
comm.getVerifyCustomerSubContractDate().bind(verifyCustomerSubContractDateChecker.selectedProperty());
|
||||
|
||||
bindDoubleClicked(viewTable, this::showContract);
|
||||
bindEnterPressed(viewTable, this::reVerifyContract);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同验证
|
||||
*/
|
||||
public void onVerifyAction(ActionEvent event) {
|
||||
Button btn = (Button) event.getSource();
|
||||
CompletableFuture<Void> future = runAsync(() -> {
|
||||
viewTableDataSet.clear();
|
||||
Pageable pageRequest = PageRequest.ofSize(200);
|
||||
AtomicInteger counter = new AtomicInteger(0);
|
||||
Specification<Contract> spec = (root, query, builder) -> {
|
||||
return builder.and(
|
||||
builder.or(
|
||||
builder.equal(root.get("payWay"), ContractPayWay.RECEIVE),
|
||||
builder.and(
|
||||
builder.equal(root.get("payWay"), ContractPayWay.PAY),
|
||||
builder.or(
|
||||
builder.isNull(root.get("parentCode")),
|
||||
builder.equal(root.get("parentCode"), "")))),
|
||||
builder.between(root.get("setupDate"), setupDateBeginSelector.getValue(),
|
||||
setupDateEndSelector.getValue()));
|
||||
};
|
||||
long total = contractService.count(spec);
|
||||
setStatus("合同:" + total + " 条");
|
||||
|
||||
while (true) {
|
||||
if (isCloseRequested()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Page<Contract> page = contractService.findAll(spec, pageRequest);
|
||||
for (Contract contract : page) {
|
||||
if (isCloseRequested()) {
|
||||
break;
|
||||
}
|
||||
counter.incrementAndGet();
|
||||
Model model = new Model();
|
||||
viewTableDataSet.add(model);
|
||||
Employee handler = contract.getHandler();
|
||||
if (handler == null) {
|
||||
model.getEmployee().set(contract.getEmployee());
|
||||
} else {
|
||||
model.getEmployee().set(handler);
|
||||
}
|
||||
|
||||
model.getCode().set(contract.getCode());
|
||||
model.getName().set(contract.getName());
|
||||
model.getSetupDate().set(contract.getSetupDate());
|
||||
comm.verify(contract, model);
|
||||
setStatus("合同验证进度:" + counter.get() + " / " + total);
|
||||
// 移除中间消息
|
||||
if (!model.getMessages().isEmpty()) {
|
||||
model.getMessages().removeIf(msg -> msg.getLevel().intValue() <= Level.INFO.intValue());
|
||||
}
|
||||
if (model.getMessages().isEmpty()) {
|
||||
if (onlyShowVerifiedChecker.isSelected()) {
|
||||
viewTableDataSet.remove(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!page.hasNext()) {
|
||||
break;
|
||||
}
|
||||
pageRequest = page.nextPageable();
|
||||
}
|
||||
setStatus("合同验证完成");
|
||||
}).exceptionally(e -> {
|
||||
setStatus(e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public void onContractReVerifyAction(ActionEvent event) {
|
||||
Model selectedItem = viewTable.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
return;
|
||||
}
|
||||
reVerifyContract(selectedItem);
|
||||
}
|
||||
|
||||
private void reVerifyContract(Model model) {
|
||||
String contractCode = model.getCode().get();
|
||||
if (!StringUtils.hasText(contractCode)) {
|
||||
return;
|
||||
}
|
||||
runAsync(() -> {
|
||||
Contract contract = contractService.findByCode(contractCode);
|
||||
if (contract == null) {
|
||||
return;
|
||||
}
|
||||
model.getMessages().clear();
|
||||
try {
|
||||
comm.verify(contract, model);
|
||||
// 移除中间消息
|
||||
if (!model.getMessages().isEmpty()) {
|
||||
model.getMessages().removeIf(msg -> msg.getLevel().intValue() <= Level.INFO.intValue());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error(model.getCode().get(), e);
|
||||
model.error(e.getMessage());
|
||||
}
|
||||
|
||||
if (model.getMessages().isEmpty()) {
|
||||
Platform.runLater(() -> {
|
||||
viewTableDataSet.remove(model);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onShowContractDetailAction(ActionEvent event) {
|
||||
Model selectedItem = viewTable.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
return;
|
||||
}
|
||||
showContract(selectedItem);
|
||||
}
|
||||
|
||||
private void showContract(Model model) {
|
||||
String contractCode = model.getCode().get();
|
||||
if (!StringUtils.hasText(contractCode)) {
|
||||
return;
|
||||
}
|
||||
Contract contract = contractService.findByCode(contractCode);
|
||||
if (contract == null) {
|
||||
return;
|
||||
}
|
||||
ContractWindowController.show(contract, viewTable.getScene().getWindow());
|
||||
}
|
||||
|
||||
public void onExportVerifyResultAsFileAction(ActionEvent e) {
|
||||
FileChooser chooser = new FileChooser();
|
||||
chooser.setTitle("导出核验结果");
|
||||
chooser.setInitialFileName("核验结果.xlsx");
|
||||
File selected = chooser.showSaveDialog(viewTable.getScene().getWindow());
|
||||
if (selected != null) {
|
||||
ContractVerifyResultExportAsExcelFileTasker task = new ContractVerifyResultExportAsExcelFileTasker();
|
||||
task.setDestFile(selected);
|
||||
task.setModels(new ArrayList<>(viewTableDataSet));
|
||||
UITools.showTaskDialogAndWait("导出中...", task, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
package com.ecep.contract.controller.contract;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.DesktopUtils;
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.company.CompanyWindowController;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinBase;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinFiles;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinItems;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinItemsV2;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinPayPlan;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinPurchaseOrders;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinSaleOrders;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinSubContract;
|
||||
import com.ecep.contract.controller.tab.ContractTabSkinVendorBid;
|
||||
import com.ecep.contract.ds.contract.tasker.ContractVerifyTasker;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.service.ContractService;
|
||||
import com.ecep.contract.service.ProjectService;
|
||||
import com.ecep.contract.task.ContractRepairTask;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.ContractViewModel;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/contract/contract.fxml")
|
||||
public class ContractWindowController
|
||||
extends AbstEntityController<Contract, ContractViewModel> {
|
||||
|
||||
public static void show(Contract contract, Window owner) {
|
||||
ContractViewModel model = new ContractViewModel();
|
||||
model.update(contract);
|
||||
show(model, owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示界面
|
||||
*/
|
||||
public static void show(ContractViewModel viewModel, Window window) {
|
||||
show(ContractWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
public BorderPane root;
|
||||
public Tab baseInfoTab;
|
||||
public Tab extendVendorInfo;
|
||||
public Tab contractTab;
|
||||
public Tab bidVendorTab;
|
||||
public Tab payPlanTab;
|
||||
public Tab itemTab;
|
||||
public Tab fileTab;
|
||||
|
||||
public Button verifyBtn;
|
||||
public Button openRelativeCompanyCustomerBtn;
|
||||
public Button openRelativeCompanyVendorBtn;
|
||||
|
||||
@Autowired
|
||||
CompanyService companyService;
|
||||
@Autowired
|
||||
ContractService contractService;
|
||||
@Autowired
|
||||
ProjectService projectService;
|
||||
|
||||
public TextField nameField;
|
||||
public TextField guidField;
|
||||
public TextField codeField;
|
||||
public TextField parentCodeField;
|
||||
public TextField companyField;
|
||||
public TextField stateField;
|
||||
public TextField groupField;
|
||||
public TextField typeField;
|
||||
public TextField kindField;
|
||||
public TextField pathField;
|
||||
public DatePicker orderDateField;
|
||||
public DatePicker startDateField;
|
||||
public DatePicker endDateField;
|
||||
public TextField setupPersonField;
|
||||
public DatePicker setupDateField;
|
||||
public TextField inurePersonField;
|
||||
public DatePicker inureDateField;
|
||||
public TextField varyPersonField;
|
||||
public DatePicker varyDateField;
|
||||
public TextField projectField;
|
||||
public TextField employeeField;
|
||||
public TextField handlerField;
|
||||
public TextField createdField;
|
||||
public TextArea descriptionField;
|
||||
public TextField amountField;
|
||||
public TextField totalQuantityField;
|
||||
public TextField totalAmountField;
|
||||
public TextField totalUnTaxAmountField;
|
||||
public TextField execQuantityField;
|
||||
public TextField execAmountField;
|
||||
public TextField execUnTaxAmountField;
|
||||
public TextField payWayField;
|
||||
public Button linkContractProjectBtn;
|
||||
|
||||
public Button contractRenameBtn;
|
||||
public Button contractPathCreateBtn;
|
||||
public Button contractPathChangeBtn;
|
||||
public Button contractPathAsNameBtn;
|
||||
public Button contractPathAsCodeBtn;
|
||||
/**
|
||||
* 打开主合同
|
||||
*/
|
||||
public Button openMainContractBtn;
|
||||
/**
|
||||
* 计算主合同编号按钮
|
||||
*/
|
||||
public Button calcMainContractNoBtn;
|
||||
public Label versionLabel;
|
||||
|
||||
@Override
|
||||
public ContractService getViewModelService() {
|
||||
return contractService;
|
||||
}
|
||||
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().bind(viewModel.getName()
|
||||
.map(name -> "[" + viewModel.getId().get() + "] " + viewModel.getCode().get() + " " + name + " 合同详情"));
|
||||
root.getScene().getStylesheets().add("/ui/contract/contract.css");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
TabPane tabPane = baseInfoTab.getTabPane();
|
||||
ObservableList<Tab> tabs = tabPane.getTabs();
|
||||
|
||||
registerTabSkin(baseInfoTab, tab -> new ContractTabSkinBase(this));
|
||||
switch (viewModel.getPayWay().get()) {
|
||||
case RECEIVE -> {
|
||||
tabs.remove(extendVendorInfo);
|
||||
registerTabSkin(contractTab, t -> new ContractTabSkinSubContract(this));
|
||||
tabs.remove(bidVendorTab);
|
||||
Tab saleOrderTab = new Tab("销售订单");
|
||||
tabs.add(saleOrderTab);
|
||||
registerTabSkin(saleOrderTab, tab -> new ContractTabSkinSaleOrders(this, tab));
|
||||
tabs.add(new Tab("票据"));
|
||||
break;
|
||||
}
|
||||
case PAY -> {
|
||||
registerTabSkin(extendVendorInfo, t -> new ContractTabSkinExtendVendorInfo(this));
|
||||
tabs.remove(contractTab);
|
||||
registerTabSkin(bidVendorTab, t -> new ContractTabSkinVendorBid(this));
|
||||
|
||||
Tab purchaseOrderTab = new Tab("采购订单");
|
||||
tabs.add(purchaseOrderTab);
|
||||
registerTabSkin(purchaseOrderTab, tab -> new ContractTabSkinPurchaseOrders(this, tab));
|
||||
|
||||
tabs.add(new Tab("发货单"));
|
||||
tabs.add(new Tab("签收单"));
|
||||
tabs.add(new Tab("付款单"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
registerTabSkin(itemTab, tab -> new ContractTabSkinItemsV2(this));
|
||||
registerTabSkin(payPlanTab, tab -> new ContractTabSkinPayPlan(this));
|
||||
registerTabSkin(fileTab, tab -> new ContractTabSkinFiles(this));
|
||||
}
|
||||
|
||||
public void onContractOpenInExplorerAction(ActionEvent event) {
|
||||
Contract contract = getEntity();
|
||||
String path = contract.getPath();
|
||||
if (!StringUtils.hasText(path)) {
|
||||
setStatus("未设置目录");
|
||||
return;
|
||||
}
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
setStatus("目录错误,不存在");
|
||||
return;
|
||||
}
|
||||
DesktopUtils.showInExplorer(file);
|
||||
}
|
||||
|
||||
public void onContractOpenRelativeCompanyAction(ActionEvent event) {
|
||||
Contract contract = getEntity();
|
||||
if (contract.getCompany() == null) {
|
||||
UITools.showAlertAndWait("没有关联的公司,你可以尝试同步修复异常。");
|
||||
return;
|
||||
}
|
||||
Integer companyId = contract.getCompany().getId();
|
||||
Company company = companyService.findById(companyId);
|
||||
if (company != null) {
|
||||
CompanyWindowController.show(company, root.getScene().getWindow());
|
||||
}
|
||||
}
|
||||
|
||||
public void onSyncContractAction(ActionEvent event) {
|
||||
ContractRepairTask task = new ContractRepairTask();
|
||||
task.setContractService(contractService);
|
||||
task.setContract(getEntity());
|
||||
UITools.showTaskDialogAndWait("同步合同", task, null);
|
||||
if (task.isRepaired()) {
|
||||
setEntity(task.getContract());
|
||||
}
|
||||
if (task.isFilesUpdated()) {
|
||||
ContractTabSkinFiles tabSkin = getTabSkin(ContractTabSkinFiles.class);
|
||||
if (tabSkin != null) {
|
||||
tabSkin.loadTableDataSet();
|
||||
}
|
||||
}
|
||||
if (task.isPlayPlanUpdated()) {
|
||||
ContractTabSkinPayPlan tabSkin = getTabSkin(ContractTabSkinPayPlan.class);
|
||||
if (tabSkin != null) {
|
||||
tabSkin.loadTableDataSet();
|
||||
}
|
||||
}
|
||||
if (task.isItemsUpdated()) {
|
||||
ContractTabSkinItems tabSkin = getTabSkin(ContractTabSkinItems.class);
|
||||
if (tabSkin != null) {
|
||||
tabSkin.loadTableDataSet();
|
||||
}
|
||||
}
|
||||
if (task.isSaleOrderUpdated()) {
|
||||
ContractTabSkinSaleOrders tabSkin = getTabSkin(ContractTabSkinSaleOrders.class);
|
||||
if (tabSkin != null) {
|
||||
tabSkin.loadTableDataSet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证合同合规性
|
||||
*/
|
||||
public void onContractVerifyAction(ActionEvent event) {
|
||||
Contract contract = getEntity();
|
||||
ContractVerifyTasker task = new ContractVerifyTasker();
|
||||
task.setContractService(contractService);
|
||||
task.setContract(contract);
|
||||
UITools.showTaskDialogAndWait("同步合规性验证", task, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.service.CompanyCustomerService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.vm.CompanyCustomerViewModel;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
public abstract class AbstCompanyCustomerTableTabSkin<T extends IdentityEntity, TV extends IdentityViewModel<T>>
|
||||
extends
|
||||
AbstEntityTableTabSkin<CompanyCustomerWindowController, CompanyCustomer, CompanyCustomerViewModel, T, TV>
|
||||
implements TabSkin {
|
||||
|
||||
public AbstCompanyCustomerTableTabSkin(CompanyCustomerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
return controller.getCompanyService();
|
||||
}
|
||||
|
||||
protected CompanyCustomerService getCompanyCustomerService() {
|
||||
return getCachedBean(CompanyCustomerService.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.util.FxmlUtils;
|
||||
import com.ecep.contract.ds.company.CompanyFileUtils;
|
||||
import com.ecep.contract.ds.customer.repository.CompanyCustomerEvaluationFormFileRepository;
|
||||
import com.ecep.contract.ds.customer.repository.CompanyCustomerFileRepository;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
|
||||
import com.ecep.contract.model.CompanyCustomerFile;
|
||||
import com.ecep.contract.vm.CompanyCustomerFileViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Bounds;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.SplitPane;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Toggle;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.image.PixelWriter;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
public class CompanyCustomerEvaluationFormFileWindowController extends BaseController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerEvaluationFormFileWindowController.class);
|
||||
|
||||
public static void show(CompanyCustomerFile saved, Window window) {
|
||||
CompanyCustomerFileViewModel model = new CompanyCustomerFileViewModel();
|
||||
model.update(saved);
|
||||
show(model, window);
|
||||
}
|
||||
|
||||
public static void show(CompanyCustomerFileViewModel viewModel, Window window) {
|
||||
String key = viewModel.getClass().getName() + "-" + viewModel.getId().get();
|
||||
if (toFront(key)) {
|
||||
return;
|
||||
}
|
||||
FxmlUtils.newLoaderAsyncWithRunLater("/ui/company/customer/customer_evaluation_form.fxml", null, loader -> {
|
||||
CompanyCustomerEvaluationFormFileWindowController controller = loader.getController();
|
||||
controller.viewModel = viewModel;
|
||||
controller.show(loader, window, Modality.NONE, key);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public Label idField;
|
||||
public TextField filePathField;
|
||||
public CheckBox validField;
|
||||
public TextField editFilePathField;
|
||||
public DatePicker signDateField;
|
||||
public ToggleGroup catalog;
|
||||
public ToggleGroup level;
|
||||
public ToggleGroup score1;
|
||||
public ToggleGroup score2;
|
||||
public ToggleGroup score3;
|
||||
public ToggleGroup score4;
|
||||
public ToggleGroup score5;
|
||||
public ToggleGroup creditLevel;
|
||||
public ImageView imageView;
|
||||
public SplitPane splitPane;
|
||||
public ScrollPane leftPane;
|
||||
public Label totalCreditScoreLabel;
|
||||
|
||||
private CompanyCustomerFileViewModel viewModel;
|
||||
|
||||
private final SimpleStringProperty catalogProperty = new SimpleStringProperty("");
|
||||
private final SimpleStringProperty levelProperty = new SimpleStringProperty("");
|
||||
private final SimpleIntegerProperty score1Property = new SimpleIntegerProperty(-1);
|
||||
private final SimpleIntegerProperty score2Property = new SimpleIntegerProperty(-1);
|
||||
private final SimpleIntegerProperty score3Property = new SimpleIntegerProperty(-1);
|
||||
private final SimpleIntegerProperty score4Property = new SimpleIntegerProperty(-1);
|
||||
private final SimpleIntegerProperty score5Property = new SimpleIntegerProperty(-1);
|
||||
private final SimpleIntegerProperty creditLevelProperty = new SimpleIntegerProperty(-1);
|
||||
private final SimpleIntegerProperty totalCreditScoreProperty = new SimpleIntegerProperty(-1);
|
||||
|
||||
private SimpleObjectProperty<Image> imageProperty = new SimpleObjectProperty<>();
|
||||
|
||||
private CompletableFuture<CompanyCustomerEvaluationFormFile> loadedFuture;
|
||||
@Autowired
|
||||
private CompanyCustomerFileRepository companyCustomerFileRepository;
|
||||
@Autowired
|
||||
private CompanyCustomerEvaluationFormFileRepository companyCustomerEvaluationFormFileRepository;
|
||||
@Lazy
|
||||
@Autowired
|
||||
private CompanyCustomerFileService companyCustomerFileService;
|
||||
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
stage.setFullScreen(false);
|
||||
// Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
|
||||
//
|
||||
// stage.setX(screenBounds.getMinX());
|
||||
// stage.setY(screenBounds.getMinY());
|
||||
// stage.setWidth(screenBounds.getWidth());
|
||||
// stage.setHeight(screenBounds.getHeight());
|
||||
//
|
||||
// stage.isMaximized();
|
||||
stage.setMaximized(true);
|
||||
getTitle().set("客户评估表单");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("onShown");
|
||||
}
|
||||
|
||||
initializePane();
|
||||
|
||||
loadedFuture = CompletableFuture.supplyAsync(() -> {
|
||||
int id = viewModel.getId().get();
|
||||
CompanyCustomerFile customerFile = companyCustomerFileService.findById(id);
|
||||
CompanyCustomerEvaluationFormFile formFile = companyCustomerFileService.findCustomerEvaluationFormFileByCustomerFile(customerFile);
|
||||
Platform.runLater(() -> update(formFile));
|
||||
return formFile;
|
||||
});
|
||||
}
|
||||
|
||||
BiConsumer<ToggleGroup, String> stringRadioGroupUpdater = (group, newValue) -> {
|
||||
if (newValue != null) {
|
||||
for (Toggle toggle : group.getToggles()) {
|
||||
String data = (String) toggle.getUserData();
|
||||
if (data == null) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("toggle unset userData: {}", toggle);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (newValue.equals(data)) {
|
||||
toggle.setSelected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
group.selectToggle(null);
|
||||
// Toggle first = group.getToggles().getFirst();
|
||||
// first.setSelected(true);
|
||||
// first.setSelected(false);
|
||||
// RadioButton btn = (RadioButton) first;
|
||||
// btn.setText(newValue);
|
||||
});
|
||||
};
|
||||
|
||||
BiConsumer<SimpleStringProperty, Toggle> stringPropertyUpdater = (property, toggle) -> {
|
||||
if (toggle == null) {
|
||||
property.set("");
|
||||
return;
|
||||
}
|
||||
String data = (String) toggle.getUserData();
|
||||
property.set(data);
|
||||
};
|
||||
|
||||
BiConsumer<ToggleGroup, Number> numberRadioGroupUpdater = (group, newValue) -> {
|
||||
String value = String.valueOf(newValue);
|
||||
for (Toggle toggle : group.getToggles()) {
|
||||
String data = (String) toggle.getUserData();
|
||||
if (value.equals(data)) {
|
||||
toggle.setSelected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
group.selectToggle(null);
|
||||
// Toggle first = group.getToggles().getFirst();
|
||||
// first.setSelected(true);
|
||||
// first.setSelected(false);
|
||||
// RadioButton btn = (RadioButton) first;
|
||||
// btn.setText(String.valueOf(newValue));
|
||||
});
|
||||
};
|
||||
|
||||
BiConsumer<SimpleIntegerProperty, Toggle> numberPropertyUpdater = (property, toggle) -> {
|
||||
if (toggle == null) {
|
||||
property.set(0);
|
||||
return;
|
||||
}
|
||||
String data = (String) toggle.getUserData();
|
||||
property.set(Integer.parseInt(data));
|
||||
};
|
||||
|
||||
|
||||
int totalScoreToLevel(int score) {
|
||||
if (score >= 200) {
|
||||
return 4;
|
||||
} else if (score >= 150) {
|
||||
return 3;
|
||||
} else if (score >= 100) {
|
||||
return 2;
|
||||
} else if (score >= 60) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean calcValid() {
|
||||
if (creditLevelProperty.get() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (!StringUtils.hasText(catalogProperty.get())) {
|
||||
return false;
|
||||
}
|
||||
if (!StringUtils.hasText(levelProperty.get())) {
|
||||
return false;
|
||||
}
|
||||
if (score1Property.get() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (score2Property.get() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (score3Property.get() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (score4Property.get() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (score5Property.get() <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (creditLevelProperty.get() <= 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initializePane() {
|
||||
idField.textProperty().bind(viewModel.getId().asString());
|
||||
filePathField.textProperty().bind(viewModel.getFilePath());
|
||||
editFilePathField.textProperty().bind(viewModel.getEditFilePath());
|
||||
signDateField.valueProperty().bindBidirectional(viewModel.getSignDate());
|
||||
validField.selectedProperty().bindBidirectional(viewModel.getValid());
|
||||
|
||||
initializeRadioGroup(catalog, catalogProperty);
|
||||
initializeRadioGroup(level, levelProperty);
|
||||
|
||||
initializeRadioGroup(score1, score1Property);
|
||||
initializeRadioGroup(score2, score2Property);
|
||||
initializeRadioGroup(score3, score3Property);
|
||||
initializeRadioGroup(score4, score4Property);
|
||||
initializeRadioGroup(score5, score5Property);
|
||||
|
||||
creditLevelProperty.addListener((observable, oldValue, newValue) -> {
|
||||
numberRadioGroupUpdater.accept(creditLevel, newValue);
|
||||
});
|
||||
|
||||
SimpleIntegerProperty[] scores = new SimpleIntegerProperty[]{score1Property, score2Property, score3Property, score4Property, score5Property};
|
||||
totalCreditScoreProperty.bind(Bindings.createIntegerBinding(() -> {
|
||||
int total = 0;
|
||||
for (SimpleIntegerProperty score : scores) {
|
||||
total += score.get();
|
||||
}
|
||||
creditLevelProperty.set(totalScoreToLevel(total));
|
||||
return total;
|
||||
}, scores));
|
||||
|
||||
totalCreditScoreLabel.textProperty().bind(totalCreditScoreProperty.map(score -> {
|
||||
return "合计总分:" + score;
|
||||
}));
|
||||
|
||||
Bindings.createBooleanBinding(() -> {
|
||||
boolean valid = calcValid();
|
||||
viewModel.getValid().set(valid);
|
||||
return valid;
|
||||
}, catalogProperty, levelProperty, score1Property, score2Property, score3Property, score4Property, score5Property, creditLevelProperty).addListener(((observable, oldValue, newValue) -> {
|
||||
logger.info("valid:{}", newValue);
|
||||
}));
|
||||
|
||||
|
||||
imageView.imageProperty().bind(viewModel.getFilePath().map(path -> {
|
||||
if (CompanyFileUtils.withExtensions(path, CompanyFileUtils.PDF)) {
|
||||
File pdfFile = new File(path);
|
||||
try (PDDocument pdDocument = Loader.loadPDF(pdfFile)) {
|
||||
PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
|
||||
BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);
|
||||
|
||||
// 获取 BufferedImage 的宽度和高度
|
||||
int width = bufferedImage.getWidth();
|
||||
int height = bufferedImage.getHeight();
|
||||
WritableImage writableImage = new WritableImage(width, height);
|
||||
PixelWriter pixelWriter = writableImage.getPixelWriter();
|
||||
// 将 BufferedImage 的像素数据复制到 WritableImage
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int argb = bufferedImage.getRGB(x, y);
|
||||
pixelWriter.setArgb(x, y, argb);
|
||||
}
|
||||
}
|
||||
return writableImage;
|
||||
} catch (Exception e) {
|
||||
setStatus(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
File file = new File(path);
|
||||
Image image = new Image(file.toURI().toString());
|
||||
return image;
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
leftPane.widthProperty().addListener((observable, oldValue, newValue) -> {
|
||||
Platform.runLater(() -> {
|
||||
imageView.setFitWidth(leftPane.getWidth());
|
||||
imageView.setFitHeight(leftPane.getHeight());
|
||||
});
|
||||
});
|
||||
|
||||
imageView.setFitWidth(leftPane.getWidth());
|
||||
imageView.setFitHeight(leftPane.getHeight());
|
||||
|
||||
imageView.setOnScroll(event -> {
|
||||
System.out.println("event = " + event);
|
||||
System.out.println("event.getDeltaY() = " + event.getDeltaY());
|
||||
Bounds bounds = imageView.getBoundsInLocal();
|
||||
// Bounds latestBounds = (Bounds) imageView.getProperties().get("latestBounds");
|
||||
// if (latestBounds != null) {
|
||||
// double latestBoundsWidth = latestBounds.getWidth();
|
||||
// }
|
||||
// if (bounds.getWidth() < leftPane.getWidth()) {
|
||||
imageView.setFitWidth(bounds.getWidth() + event.getDeltaY());
|
||||
// } else {
|
||||
imageView.setFitHeight(bounds.getHeight() + event.getDeltaY());
|
||||
// }
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeRadioGroup(ToggleGroup toggleGroup, SimpleStringProperty property) {
|
||||
property.addListener((observable, oldValue, newValue) -> {
|
||||
stringRadioGroupUpdater.accept(toggleGroup, newValue);
|
||||
});
|
||||
toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
|
||||
stringPropertyUpdater.accept(property, newValue);
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeRadioGroup(ToggleGroup toggleGroup, SimpleIntegerProperty property) {
|
||||
property.addListener((observable, oldValue, newValue) -> {
|
||||
numberRadioGroupUpdater.accept(toggleGroup, newValue);
|
||||
});
|
||||
|
||||
toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
|
||||
numberPropertyUpdater.accept(property, newValue);
|
||||
});
|
||||
}
|
||||
|
||||
private void update(CompanyCustomerEvaluationFormFile formFile) {
|
||||
|
||||
|
||||
viewModel.update(formFile.getCustomerFile());
|
||||
|
||||
// formFile.getScoreTemplateVersion();
|
||||
|
||||
catalogProperty.set(formFile.getCatalog());
|
||||
levelProperty.set(formFile.getLevel());
|
||||
score1Property.set(formFile.getScore1());
|
||||
score2Property.set(formFile.getScore2());
|
||||
score3Property.set(formFile.getScore3());
|
||||
score4Property.set(formFile.getScore4());
|
||||
score5Property.set(formFile.getScore5());
|
||||
creditLevelProperty.set(formFile.getCreditLevel());
|
||||
}
|
||||
|
||||
public void onSaveAction(ActionEvent event) {
|
||||
boolean modified = false;
|
||||
|
||||
int id = viewModel.getId().get();
|
||||
CompanyCustomerEvaluationFormFile formFile = companyCustomerFileService.findCustomerEvaluationFormFileById(id);
|
||||
CompanyCustomerFile customerFile = formFile.getCustomerFile();
|
||||
|
||||
if (!Objects.equals(catalogProperty.get(), formFile.getCatalog())) {
|
||||
formFile.setCatalog(catalogProperty.get());
|
||||
modified = true;
|
||||
}
|
||||
if (!Objects.equals(levelProperty.get(), formFile.getLevel())) {
|
||||
formFile.setLevel(levelProperty.get());
|
||||
modified = true;
|
||||
}
|
||||
if (!Objects.equals(score1Property.get(), formFile.getScore1())) {
|
||||
formFile.setScore1(score1Property.get());
|
||||
modified = true;
|
||||
}
|
||||
if (!Objects.equals(score2Property.get(), formFile.getScore2())) {
|
||||
formFile.setScore2(score2Property.get());
|
||||
modified = true;
|
||||
}
|
||||
if (!Objects.equals(score3Property.get(), formFile.getScore3())) {
|
||||
formFile.setScore3(score3Property.get());
|
||||
modified = true;
|
||||
}
|
||||
if (!Objects.equals(score4Property.get(), formFile.getScore4())) {
|
||||
formFile.setScore4(score4Property.get());
|
||||
modified = true;
|
||||
}
|
||||
if (!Objects.equals(score5Property.get(), formFile.getScore5())) {
|
||||
formFile.setScore5(score5Property.get());
|
||||
modified = true;
|
||||
}
|
||||
if (!Objects.equals(creditLevelProperty.get(), formFile.getCreditLevel())) {
|
||||
formFile.setCreditLevel(creditLevelProperty.get());
|
||||
modified = true;
|
||||
}
|
||||
|
||||
|
||||
if (viewModel.copyTo(customerFile)) {
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) {
|
||||
companyCustomerFileService.save(formFile);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import static com.ecep.contract.util.ExcelUtils.setCellValue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.ecep.contract.service.*;
|
||||
import com.ecep.contract.util.CompanyUtils;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.CompanyCustomerFileType;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.model.CloudTyc;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
|
||||
import com.ecep.contract.model.CompanyCustomerFile;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import lombok.Setter;
|
||||
|
||||
public class CompanyCustomerEvaluationFormUpdateTask extends Task<Object> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerEvaluationFormUpdateTask.class);
|
||||
|
||||
@Setter
|
||||
private CompanyCustomer customer;
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
private CompanyContactService companyContactService;
|
||||
|
||||
private CompanyCustomerService companyCustomerService;
|
||||
@Setter
|
||||
private CompanyCustomerFileService companyCustomerFileService;
|
||||
|
||||
private CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = SpringApp.getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
private CompanyCustomerService getCompanyCustomerService() {
|
||||
if (companyCustomerService == null) {
|
||||
companyCustomerService = SpringApp.getBean(CompanyCustomerService.class);
|
||||
}
|
||||
return companyCustomerService;
|
||||
}
|
||||
|
||||
private CompanyContactService getCompanyContactService() {
|
||||
if (companyContactService == null) {
|
||||
companyContactService = SpringApp.getBean(CompanyContactService.class);
|
||||
}
|
||||
return companyContactService;
|
||||
}
|
||||
|
||||
private CompanyCustomerFileService getCompanyCustomerFileService() {
|
||||
if (companyCustomerFileService == null) {
|
||||
companyCustomerFileService = SpringApp.getBean(CompanyCustomerFileService.class);
|
||||
}
|
||||
return companyCustomerFileService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object call() throws Exception {
|
||||
try {
|
||||
updateEvaluationForm();
|
||||
} catch (Exception ex) {
|
||||
updateMessage(ex.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private File getEvaluationFormTemplate() {
|
||||
return getCompanyCustomerFileService().getEvaluationFormTemplate();
|
||||
}
|
||||
|
||||
public void updateEvaluationForm() {
|
||||
if (!StringUtils.hasText(customer.getPath())) {
|
||||
updateMessage("供应商目录未设置,请先设置供应商目录");
|
||||
return;
|
||||
}
|
||||
File template = getEvaluationFormTemplate();
|
||||
if (template == null) {
|
||||
updateMessage("评价表模板文件未设置,请先设置评价表模板文件");
|
||||
return;
|
||||
}
|
||||
if (!template.exists()) {
|
||||
updateMessage("评价表模板文件 " + template.getAbsolutePath() + " 不存在,请检查");
|
||||
return;
|
||||
}
|
||||
|
||||
File dir = new File(customer.getPath());
|
||||
String template_file_name = template.getName();
|
||||
File destFile = new File(dir, template_file_name);
|
||||
|
||||
if (destFile.exists()) {
|
||||
updateMessage("表单文件已经存在," + destFile.getName());
|
||||
try (
|
||||
InputStream inp = new FileInputStream(destFile);
|
||||
Workbook wb = WorkbookFactory.create(inp)) {
|
||||
updateEvaluationForm(wb, destFile);
|
||||
updateMessage("评价表已更新");
|
||||
} catch (Exception e) {
|
||||
updateMessage(e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
updateMessage("根据模板 " + template_file_name + " 创建表单 " + destFile.getName());
|
||||
try (
|
||||
InputStream inp = new FileInputStream(template);
|
||||
Workbook wb = WorkbookFactory.create(inp)) {
|
||||
updateEvaluationForm(wb, destFile);
|
||||
updateMessage("评价表已创建");
|
||||
CompanyCustomerFile customerFile = new CompanyCustomerFile();
|
||||
customerFile.setCustomer(customer);
|
||||
customerFile.setFilePath(destFile.getAbsolutePath());
|
||||
customerFile.setType(CompanyCustomerFileType.General);
|
||||
save(customerFile);
|
||||
} catch (Exception e) {
|
||||
updateMessage(e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
updateProgress(1, 1);
|
||||
}
|
||||
|
||||
private void save(CompanyCustomerFile customerFile) {
|
||||
getCompanyCustomerFileService().save(customerFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新客户评估表,依据模板创建,如果已经存在生成的文件,则更新评估表
|
||||
*
|
||||
* @param wb work book
|
||||
* @param destFile 目标文件
|
||||
*/
|
||||
public void updateEvaluationForm(
|
||||
Workbook wb, File destFile) throws IOException {
|
||||
Company company = customer.getCompany();
|
||||
if (!Hibernate.isInitialized(company)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
customer.setCompany(company);
|
||||
}
|
||||
|
||||
Sheet sheet = wb.getSheetAt(0);
|
||||
updateSheet(company, sheet);
|
||||
// 输出到文件
|
||||
try (OutputStream fileOut = new FileOutputStream(destFile)) {
|
||||
wb.write(fileOut);
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
updateMessage("写评估表时发生文件错误,请检查评估表是否被打开中");
|
||||
updateMessage(e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSheet(Company company, Sheet sheet) {
|
||||
setCellValue(sheet, "B3", "客户编号:" + CompanyUtils.formatCompanyVendorId(customer.getId()));
|
||||
setCellValue(sheet, "B4", "客户名称:" + company.getName());
|
||||
|
||||
LocalDate suggestDate = getCompanyCustomerFileService().getNextSignDate(customer, (level, msg) -> {
|
||||
updateMessage(" - " + msg);
|
||||
});
|
||||
if (suggestDate == null) {
|
||||
suggestDate = LocalDate.now();
|
||||
}
|
||||
setCellValue(sheet, "H3", "评定时间:" + suggestDate);
|
||||
setCellValue(sheet, "H4", "统一社会信用代码:");
|
||||
setCellValue(sheet, "H5", company.getUniscid());
|
||||
// 注册所属地
|
||||
setCellValue(sheet, "B5", "注册所属地:" + company.getDistrict());
|
||||
// 经营状态
|
||||
setCellValue(sheet, "D6", "经营状态:" + company.getEntStatus());
|
||||
// 成立日期
|
||||
setCellValue(sheet, "H6", "成立日期:" + company.getSetupDate());
|
||||
// 所属行业
|
||||
setCellValue(sheet, "D7", "所属行业:" + company.getIndustry());
|
||||
setCellValue(sheet, "D8",
|
||||
"注册资金:" + company.getRegisteredCapital() + " " + company.getRegisteredCapitalCurrency());
|
||||
// 企业类型
|
||||
setCellValue(sheet, "H10", "企业类型:" + company.getEntType());
|
||||
// 天眼评分
|
||||
CloudTycService cloudTycService = SpringApp.getBean(CloudTycService.class);
|
||||
CloudTyc cloudTyc = cloudTycService.getOrCreateCloudTyc(company);
|
||||
setCellValue(sheet, "D10", "天眼评分:" + (cloudTyc.getScore() > 0 ? cloudTyc.getScore() : ""));
|
||||
|
||||
// 检索评估表
|
||||
List<CompanyCustomerEvaluationFormFile> evaluationFormFiles = getCompanyCustomerFileService()
|
||||
.findAllCustomerEvaluationFormFiles(customer);
|
||||
List<CompanyCustomerEvaluationFormFile> filteredList = evaluationFormFiles.stream()
|
||||
.filter(v -> {
|
||||
CompanyCustomerFile file = v.getCustomerFile();
|
||||
return file.getSignDate() != null && file.isValid();
|
||||
})
|
||||
.sorted(Comparator.comparing(v -> v.getCustomerFile().getSignDate()))
|
||||
.toList();
|
||||
|
||||
if (filteredList.isEmpty()) {
|
||||
setCellValue(sheet, "C40", "首次评价");
|
||||
try {
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("C40:K40"));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
} else {
|
||||
setCellValue(sheet, "C40", "评价日期");
|
||||
try {
|
||||
sheet.addMergedRegion(CellRangeAddress.valueOf("C40:D40"));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
setCellValue(sheet, "E40", "经济指标");
|
||||
setCellValue(sheet, "F40", "综合指标");
|
||||
setCellValue(sheet, "G40", "资信等级");
|
||||
String[] CreditLevelTitles = new String[]{"-", "差★", " 一般★★", " 较好★★★", " 好★★★★", " "};
|
||||
int baseRow = 40;
|
||||
for (CompanyCustomerEvaluationFormFile form : filteredList) {
|
||||
CompanyCustomerFile customerFile = form.getCustomerFile();
|
||||
setCellValue(sheet, baseRow, 2, String.valueOf(customerFile.getSignDate()));
|
||||
setCellValue(sheet, baseRow, 4, form.getCatalog());
|
||||
setCellValue(sheet, baseRow, 5, form.getLevel());
|
||||
if (form.getCreditLevel() == null) {
|
||||
setCellValue(sheet, baseRow, 6, "-");
|
||||
} else {
|
||||
setCellValue(sheet, baseRow, 6, CreditLevelTitles[form.getCreditLevel()]);
|
||||
}
|
||||
try {
|
||||
sheet.addMergedRegion(new CellRangeAddress(baseRow, baseRow, 2, 3));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
baseRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import com.ecep.contract.MessageHolder;
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.model.*;
|
||||
import com.ecep.contract.service.CompanyCustomerEntityService;
|
||||
import com.ecep.contract.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.service.CompanyCustomerService;
|
||||
import com.ecep.contract.task.Tasker;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import lombok.Setter;
|
||||
import org.apache.poi.ss.SpreadsheetVersion;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.AreaReference;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFTable;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import static com.ecep.contract.util.ExcelUtils.*;
|
||||
|
||||
public class CompanyCustomerExportExcelTasker extends Tasker<Object> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerExportExcelTasker.class);
|
||||
|
||||
|
||||
@Setter
|
||||
File destFile;
|
||||
|
||||
CompanyCustomerService customerService;
|
||||
CompanyCustomerEntityService customerEntityService;
|
||||
CompanyCustomerFileService customerFileService;
|
||||
|
||||
CompanyCustomerService getCustomerService() {
|
||||
if (customerService == null)
|
||||
customerService = getBean(CompanyCustomerService.class);
|
||||
return customerService;
|
||||
}
|
||||
|
||||
CompanyCustomerFileService getCustomerFileService() {
|
||||
if (customerFileService == null)
|
||||
customerFileService = getBean(CompanyCustomerFileService.class);
|
||||
return customerFileService;
|
||||
}
|
||||
CompanyCustomerEntityService getCustomerEntityService() {
|
||||
if (customerEntityService == null)
|
||||
customerEntityService = getBean(CompanyCustomerEntityService.class);
|
||||
return customerEntityService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object execute(MessageHolder holder) throws Exception {
|
||||
if (destFile.exists()) {
|
||||
holder.warn("文件已存在, 输出将覆盖文件...");
|
||||
}
|
||||
String path = getConfService().getString("customer.evaluation.book.template");
|
||||
if (!StringUtils.hasText(path)) {
|
||||
holder.error("模板文件未设置,模板文件");
|
||||
return null;
|
||||
}
|
||||
File template = new File(path);
|
||||
if (!template.exists()) {
|
||||
holder.warn("模板文件 " + template.getAbsolutePath() + " 不存在,请检查");
|
||||
return null;
|
||||
}
|
||||
try (
|
||||
InputStream inp = new FileInputStream(template);
|
||||
Workbook wb = WorkbookFactory.create(inp);
|
||||
) {
|
||||
String sheetName = "客户资信台账";
|
||||
Sheet sheet = null;
|
||||
for (int i = 0; i < wb.getNumberOfSheets(); i++) {
|
||||
Sheet s = wb.getSheetAt(i);
|
||||
if (s.getSheetName().contains(sheetName)) {
|
||||
sheet = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sheet == null) {
|
||||
holder.error("找不到" + sheetName + "Sheet");
|
||||
return null;
|
||||
}
|
||||
|
||||
setCellValue(sheet, "H2", "年度:" + LocalDate.now().getYear());
|
||||
|
||||
setCellValue(sheet, "A19", "Build by CMS @ " + MyDateTimeUtils.format(LocalDateTime.now()));
|
||||
|
||||
int rowIndex = 0;
|
||||
for (CompanyCustomer customer : getCustomerService().findAll(null, Pageable.unpaged())) {
|
||||
Company company = customer.getCompany();
|
||||
if (company == null) {
|
||||
holder.warn("客户 #" + customer.getId() + " 不存在对应公司");
|
||||
continue;
|
||||
}
|
||||
if (!Hibernate.isInitialized(company)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
}
|
||||
|
||||
LocalDate devDate = null;
|
||||
List<CompanyCustomerEntity> entities = getCustomerEntityService() .findAllByCustomer(customer);
|
||||
for (CompanyCustomerEntity entity : entities) {
|
||||
if (devDate == null || devDate.isAfter(entity.getDevelopDate())) {
|
||||
devDate = entity.getDevelopDate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CompanyCustomerEvaluationFormFile evaluationFormFile = getCustomerFileService().findAllCustomerEvaluationFormFiles(customer).stream().filter(v -> {
|
||||
CompanyCustomerFile customerFile = v.getCustomerFile();
|
||||
if (customerFile == null) {
|
||||
return false;
|
||||
}
|
||||
return customerFile.isValid();
|
||||
}).max(Comparator.comparing(v -> v.getCustomerFile().getSignDate())).orElse(null);
|
||||
|
||||
if (evaluationFormFile == null) {
|
||||
holder.warn(company.getName() + " 未匹配的客户评估");
|
||||
continue;
|
||||
}
|
||||
|
||||
CompanyCustomerFile customerFile = evaluationFormFile.getCustomerFile();
|
||||
if (devDate != null && devDate.isAfter(customerFile.getSignDate())) {
|
||||
holder.debug(company.getName() + " 最新评估日期早于客户开发日期,评估日期:" + customerFile.getSignDate() + ", 开发日期:" + devDate);
|
||||
}
|
||||
|
||||
|
||||
rowIndex++;
|
||||
|
||||
if (rowIndex > 11) {
|
||||
// 插入行,并复制行的格式
|
||||
sheet.shiftRows(rowIndex + 3, sheet.getLastRowNum(), 1);
|
||||
Row templateRow = getRow(sheet, rowIndex + 2, true);
|
||||
Row newRow = getRow(sheet, rowIndex + 3, true);
|
||||
if (templateRow != null && newRow != null) {
|
||||
for (int i = 0; i < templateRow.getLastCellNum(); i++) {
|
||||
Cell templateCell = templateRow.getCell(i);
|
||||
Cell newCell = getCell(newRow, i, true);
|
||||
if (templateCell != null && newCell != null) {
|
||||
newCell.setCellStyle(templateCell.getCellStyle());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Row row = getRow(sheet, rowIndex + 3, true);
|
||||
|
||||
setCellValue(row, 0, rowIndex);
|
||||
setCellValue(row, 1, company.getName());
|
||||
// 客户类型
|
||||
setCellValue(row, 2, evaluationFormFile.getCatalog());
|
||||
setCellValue(row, 3, devDate);
|
||||
setCellValue(row, 4, "无");
|
||||
setCellValue(row, 5, "无");
|
||||
setCellValue(row, 6, evaluationFormFile.getCreditLevel());
|
||||
|
||||
setCellValue(row, 7, "更新 " + customerFile.getSignDate());
|
||||
}
|
||||
|
||||
for (XSSFTable table : ((XSSFSheet) sheet).getTables()) {
|
||||
if ("表2".equals(table.getName())) {
|
||||
holder.info("找到表=" + table.getName() + ", style=" + table.getStyleName());
|
||||
table.setCellReferences(new AreaReference("$A$4:$H$" + (rowIndex + 4), SpreadsheetVersion.EXCEL2007));
|
||||
|
||||
// table.setDataRowCount(rowIndex);
|
||||
//table.getCTTable().setRef("$A$4:$H$" + (rowIndex + 4));
|
||||
}
|
||||
}
|
||||
|
||||
wb.setPrintArea(wb.getSheetIndex(sheet), "A1:H" + (rowIndex + 7));
|
||||
PrintSetup printSetup = sheet.getPrintSetup();
|
||||
printSetup.setPaperSize(PrintSetup.A4_PAPERSIZE); // A4 纸
|
||||
printSetup.setFitHeight((short) 0);
|
||||
printSetup.setFitWidth((short) 1); // 调整为 1 页宽
|
||||
|
||||
sheet.setFitToPage(true);
|
||||
sheet.setRepeatingRows(CellRangeAddress.valueOf("$1:$4"));
|
||||
sheet.getFooter().setCenter("第 &P 页, 共 &N 页");
|
||||
sheet.getFooter().setRight("&D &T");
|
||||
|
||||
try (OutputStream fileOut = new FileOutputStream(destFile)) {
|
||||
wb.write(fileOut);
|
||||
} catch (FileNotFoundException e) {
|
||||
UITools.showExceptionAndWait("写时发生文件错误", e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
UITools.showExceptionAndWait("保存失败", e);
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.controller.table.cell.CompanyTableCell;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.service.CompanyCustomerService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.vm.CompanyCustomerViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import lombok.Setter;
|
||||
|
||||
public class CompanyCustomerManagerSkin
|
||||
extends
|
||||
AbstEntityManagerSkin<CompanyCustomer, CompanyCustomerViewModel, CompanyCustomerManagerSkin, CompanyCustomerManagerWindowController> {
|
||||
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
|
||||
public CompanyCustomerManagerSkin(CompanyCustomerManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
public CompanyCustomerService getCompanyCustomerService() {
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
controller.companyColumn.setCellValueFactory(param -> param.getValue().getCompany());
|
||||
controller.companyColumn.setCellFactory(param-> new CompanyTableCell<>(getCompanyService()));
|
||||
|
||||
controller.developDateColumn.setCellValueFactory(param -> param.getValue().getDevelopDate());
|
||||
controller.pathColumn.setCellValueFactory(param -> param.getValue().getPath());
|
||||
|
||||
controller.createdColumn
|
||||
.setCellValueFactory(param -> param.getValue().getCreated().map(MyDateTimeUtils::format));
|
||||
Platform.runLater(() -> {
|
||||
getTableView().getSortOrder().add(controller.idColumn);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CompanyCustomerViewModel item) {
|
||||
showInOwner(item);
|
||||
}
|
||||
|
||||
private void showInOwner(CompanyCustomerViewModel model) {
|
||||
showInOwner(CompanyCustomerWindowController.class, model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.service.CompanyCustomerService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CompanyCustomerViewModel;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDate;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/company/customer/customer_manager.fxml")
|
||||
public class CompanyCustomerManagerWindowController
|
||||
extends AbstManagerWindowController<CompanyCustomer, CompanyCustomerViewModel, CompanyCustomerManagerSkin> {
|
||||
|
||||
// columns
|
||||
public TableColumn<CompanyCustomerViewModel, Number> idColumn;
|
||||
public TableColumn<CompanyCustomerViewModel, Company> companyColumn;
|
||||
public TableColumn<CompanyCustomerViewModel, String> catalogColumn;
|
||||
public TableColumn<CompanyCustomerViewModel, LocalDate> developDateColumn;
|
||||
public TableColumn<CompanyCustomerViewModel, String> pathColumn;
|
||||
public TableColumn<CompanyCustomerViewModel, String> createdColumn;
|
||||
|
||||
@Autowired
|
||||
private CompanyService companyService;
|
||||
@Autowired
|
||||
private CompanyCustomerService companyCustomerService;
|
||||
|
||||
@Override
|
||||
public CompanyCustomerService getViewModelService() {
|
||||
return companyCustomerService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("客户管理");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompanyCustomerManagerSkin createDefaultSkin() {
|
||||
CompanyCustomerManagerSkin skin = new CompanyCustomerManagerSkin(this);
|
||||
skin.setCompanyService(companyService);
|
||||
return skin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对所有客户的文件进行重置
|
||||
* <p>
|
||||
* 弹出对话框模式,对话框中有进度条和重置的消息
|
||||
*
|
||||
* @param event 事件
|
||||
*/
|
||||
public void onReBuildFilesAction(ActionEvent event) {
|
||||
Dialog<String> dialog = new Dialog<>();
|
||||
dialog.setTitle("客户文件重置");
|
||||
AtomicBoolean canceled = new AtomicBoolean(false);
|
||||
VBox box = new VBox();
|
||||
Label header = new Label("遍历所有客户,对每个可以客户的文件进行“重置”操作");
|
||||
|
||||
ProgressBar progressBar = new ProgressBar();
|
||||
progressBar.setPrefWidth(300);
|
||||
progressBar.setMinHeight(18);
|
||||
VBox.setMargin(progressBar, new Insets(8, 0, 8, 0));
|
||||
|
||||
ListView<String> listView = new ListView<>();
|
||||
ObservableList<String> listViewDataSet = FXCollections.observableArrayList();
|
||||
listView.setItems(listViewDataSet);
|
||||
VBox.setVgrow(listView, Priority.ALWAYS);
|
||||
box.getChildren().setAll(header, progressBar, listView);
|
||||
|
||||
dialog.getDialogPane().setContent(box);
|
||||
|
||||
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
|
||||
dialog.setResizable(true);
|
||||
dialog.setWidth(600);
|
||||
dialog.setHeight(500);
|
||||
dialog.setOnCloseRequest(v -> canceled.set(true));
|
||||
dialog.initOwner(table.getScene().getWindow());
|
||||
dialog.show();
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
Pageable pageRequest = PageRequest.ofSize(50);
|
||||
while (!canceled.get()) {
|
||||
Page<CompanyCustomer> page = companyCustomerService.findAll(null, pageRequest);
|
||||
int index = page.getNumber() * page.getSize();
|
||||
|
||||
int i = 1;
|
||||
for (CompanyCustomer companyCustomer : page) {
|
||||
if (canceled.get()) {
|
||||
return;
|
||||
}
|
||||
Company company = companyCustomer.getCompany();
|
||||
if (!Hibernate.isInitialized(company)) {
|
||||
company = companyService.findById(company.getId());
|
||||
}
|
||||
|
||||
String prefix = (index + i) + "/" + page.getTotalElements() + ", " + company.getName() + "> ";
|
||||
companyCustomerService.reBuildingFiles(companyCustomer, (level, msg) -> {
|
||||
Platform.runLater(() -> {
|
||||
listViewDataSet.add(prefix + msg);
|
||||
listView.scrollTo(listViewDataSet.size() - 1);
|
||||
});
|
||||
});
|
||||
|
||||
double progress = (double) (index + i) / page.getTotalElements();
|
||||
Platform.runLater(() -> {
|
||||
progressBar.setProgress(progress);
|
||||
});
|
||||
i++;
|
||||
}
|
||||
if (!page.hasNext()) {
|
||||
break;
|
||||
}
|
||||
pageRequest = page.nextPageable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onCreateNewCustomerAction(ActionEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void onBaseTableRefreshAction(ActionEvent event) {
|
||||
getSkin().loadTableDataSet(true);
|
||||
}
|
||||
|
||||
public void onExportAction(ActionEvent event) {
|
||||
CompanyCustomerExportExcelTasker tasker = new CompanyCustomerExportExcelTasker();
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("导出");
|
||||
fileChooser.setInitialFileName("客户资信台账-" + MyDateTimeUtils.format(LocalDate.now()) + ".xlsx");
|
||||
fileChooser.setInitialDirectory(companyCustomerService.getBasePath());
|
||||
File destFile = fileChooser.showSaveDialog(table.getScene().getWindow());
|
||||
tasker.setDestFile(destFile);
|
||||
UITools.showTaskDialogAndWait("导出Excel", tasker, null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.company.CompanyWindowController;
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.company.service.CompanyContactService;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.CompanyContact;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.service.CompanyStringConverter;
|
||||
import com.ecep.contract.vm.CompanyCustomerViewModel;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
|
||||
public class CompanyCustomerTabSkinBase
|
||||
extends AbstEntityBasedTabSkin<CompanyCustomerWindowController, CompanyCustomer, CompanyCustomerViewModel>
|
||||
implements TabSkin {
|
||||
|
||||
public CompanyCustomerTabSkinBase(CompanyCustomerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
initializeCompanyFieldAutoCompletion(controller.companyField);
|
||||
initializeContactFieldAutoCompletion(controller.contactField);
|
||||
|
||||
LocalDateStringConverter converter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
|
||||
controller.developDateField.setConverter(converter);
|
||||
controller.developDateField.valueProperty().bindBidirectional(viewModel.getDevelopDate());
|
||||
|
||||
controller.pathField.textProperty().bind(viewModel.getPath());
|
||||
controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());
|
||||
controller.createdField.textProperty().bind(
|
||||
Bindings.createStringBinding(
|
||||
() -> localDateTimeFormatter(viewModel.getCreated()),
|
||||
viewModel.getCreated())
|
||||
);
|
||||
controller.versionLabel.textProperty().bind(viewModel.getVersion().asString());
|
||||
|
||||
controller.relativeCompanyBtn.disableProperty().bind(viewModel.getCompany().isNull());
|
||||
controller.relativeCompanyBtn.setOnAction(event -> {
|
||||
Company company = viewModel.getCompany().get();
|
||||
if (company != null) {
|
||||
CompanyWindowController.show(company, controller.root.getScene().getWindow());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
controller.createPathBtn.setOnAction(this::onCompanyCustomerCreatePathAction);
|
||||
controller.changePathBtn.setOnAction(this::onCompanyCustomerChangePathAction);
|
||||
controller.pathAsNameBtn.setOnAction(this::onCompanyCustomerPathSameAsNameAction);
|
||||
}
|
||||
|
||||
protected String localDateTimeFormatter(SimpleObjectProperty<LocalDateTime> property) {
|
||||
LocalDateTime dateTime = property.get();
|
||||
if (dateTime == null) {
|
||||
return "";
|
||||
}
|
||||
return MyDateTimeUtils.format(dateTime);
|
||||
}
|
||||
|
||||
private void initializeContactFieldAutoCompletion(TextField textField) {
|
||||
EntityStringConverter<CompanyContact> stringConverter = new EntityStringConverter<>();
|
||||
stringConverter.setInitialized(cc -> getCompanyContactService().findById(cc.getId()));
|
||||
UITools.autoCompletion(textField, viewModel.getContact(), p -> getCompanyContactService().searchByCompany(viewModel.getCompany().get(), p.getUserText()), stringConverter);
|
||||
}
|
||||
|
||||
private void initializeCompanyFieldAutoCompletion(TextField textField) {
|
||||
CompanyStringConverter converter = SpringApp.getBean(CompanyStringConverter.class);
|
||||
UITools.autoCompletion(textField, viewModel.getCompany(), converter::suggest, converter);
|
||||
}
|
||||
|
||||
public void onCompanyCustomerCreatePathAction(ActionEvent event) {
|
||||
CompanyCustomer companyCustomer = getCompanyCustomerService().findById(viewModel.getId().get());
|
||||
if (getCompanyCustomerService().makePathAbsent(companyCustomer)) {
|
||||
companyCustomer = getCompanyCustomerService().save(companyCustomer);
|
||||
viewModel.update(companyCustomer);
|
||||
} else {
|
||||
setStatus("目录存在或创建失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onCompanyCustomerChangePathAction(ActionEvent event) {
|
||||
setStatus("未实现");
|
||||
}
|
||||
|
||||
public void onCompanyCustomerPathSameAsNameAction(ActionEvent event) {
|
||||
setStatus("未实现");
|
||||
}
|
||||
|
||||
public CompanyCustomerService getCompanyCustomerService() {
|
||||
return controller.companyCustomerService;
|
||||
}
|
||||
|
||||
public CompanyContactService getCompanyContactService() {
|
||||
return controller.companyContactService;
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
return controller.companyService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.DesktopUtils;
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.service.CompanyContactService;
|
||||
import com.ecep.contract.service.CompanyCustomerService;
|
||||
import com.ecep.contract.service.CompanyService;
|
||||
import com.ecep.contract.vm.CompanyCustomerViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/company/customer/customer.fxml")
|
||||
public class CompanyCustomerWindowController extends AbstEntityController<CompanyCustomer, CompanyCustomerViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerWindowController.class);
|
||||
|
||||
/**
|
||||
* 显示界面
|
||||
*/
|
||||
public static void show(CompanyCustomer customer, Window window) {
|
||||
CompanyCustomerViewModel viewModel = new CompanyCustomerViewModel();
|
||||
viewModel.update(customer);
|
||||
show(CompanyCustomerWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
public Tab baseInfoTab;
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
public Tab fileTab;
|
||||
public Tab entityTab;
|
||||
public Tab satisfactionTab;
|
||||
public TextField companyField;
|
||||
public TextField contactField;
|
||||
public TextField pathField;
|
||||
public TextArea descriptionField;
|
||||
public DatePicker developDateField;
|
||||
public TextField createdField;
|
||||
public Label versionLabel;
|
||||
|
||||
public Button relativeCompanyBtn;
|
||||
public Button createPathBtn;
|
||||
public Button changePathBtn;
|
||||
public Button pathAsNameBtn;
|
||||
public Button OpenCustomerPathInExplorerBtn;
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().bind(viewModel.getCompany().map(company -> {
|
||||
if (company == null) {
|
||||
return "-";
|
||||
}
|
||||
if (!Hibernate.isInitialized(company)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
viewModel.getCompany().set(company);
|
||||
}
|
||||
return getMessage("ui.customer.title", String.valueOf(viewModel.getId().get()), company.getName());
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab -> new CompanyCustomerTabSkinBase(this));
|
||||
registerTabSkin(fileTab, tab -> new CustomerTabSkinFile(this));
|
||||
registerTabSkin(entityTab, tab -> new CustomerTabSkinEntity(this));
|
||||
registerTabSkin(satisfactionTab, tab -> new CustomerTabSkinSatisfactionSurvey(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompanyCustomerService getViewModelService() {
|
||||
return getCachedBean(CompanyCustomerService.class);
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
return getCachedBean(CompanyService.class);
|
||||
}
|
||||
|
||||
public CompanyContactService getCompanyContactService() {
|
||||
return getCachedBean(CompanyContactService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
OpenCustomerPathInExplorerBtn.setOnAction(this::onCompanyCustomerOpenInExplorerAction);
|
||||
}
|
||||
|
||||
public void onCompanyCustomerOpenInExplorerAction(ActionEvent event) {
|
||||
String path = viewModel.getPath().get();
|
||||
if (!StringUtils.hasText(path)) {
|
||||
setStatus("未设置目录");
|
||||
return;
|
||||
}
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
setStatus("目录错误,不存在");
|
||||
return;
|
||||
}
|
||||
DesktopUtils.showInExplorer(file);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerEntityService;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.model.CompanyCustomerEntity;
|
||||
import com.ecep.contract.model.CustomerCatalog;
|
||||
import com.ecep.contract.ui.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.CustomerEntityViewModel;
|
||||
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/company/customer/customer-tab-entity.fxml")
|
||||
public class CustomerTabSkinEntity
|
||||
extends AbstCompanyCustomerTableTabSkin<CompanyCustomerEntity, CustomerEntityViewModel> {
|
||||
|
||||
// 关联项 tab
|
||||
public TableColumn<CustomerEntityViewModel, Number> entityTable_idColumn;
|
||||
public TableColumn<CustomerEntityViewModel, String> entityTable_catalogColumn;
|
||||
public TableColumn<CustomerEntityViewModel, String> entityTable_nameColumn;
|
||||
public TableColumn<CustomerEntityViewModel, String> entityTable_abbNameColumn;
|
||||
public TableColumn<CustomerEntityViewModel, String> entityTable_codeColumn;
|
||||
public TableColumn<CustomerEntityViewModel, String> entityTable_creatorColumn;
|
||||
public TableColumn<CustomerEntityViewModel, LocalDate> entityTable_developDateColumn;
|
||||
public TableColumn<CustomerEntityViewModel, String> entityTable_modifierColumn;
|
||||
public TableColumn<CustomerEntityViewModel, LocalDate> entityTable_modifyDateColumn;
|
||||
public TableColumn<CustomerEntityViewModel, LocalDate> entityTable_updatedDateColumn;
|
||||
public TableColumn<CustomerEntityViewModel, LocalDateTime> fetchedTimeColumn;
|
||||
|
||||
public MenuItem entityTable_menu_refresh;
|
||||
public MenuItem entityTable_menu_del;
|
||||
|
||||
@Setter
|
||||
private CompanyCustomerEntityService customerEntityService;
|
||||
|
||||
public CustomerTabSkinEntity(CompanyCustomerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.entityTab;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
super.initializeTab();
|
||||
|
||||
entityTable_idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
entityTable_nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
entityTable_abbNameColumn.setCellValueFactory(param -> param.getValue().getAbbName());
|
||||
entityTable_codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
initializeEntityTabCatalogColumn(entityTable_catalogColumn);
|
||||
|
||||
EmployeeStringConverter stringConverter = SpringApp.getBean(EmployeeStringConverter.class);
|
||||
entityTable_developDateColumn.setCellValueFactory(param -> param.getValue().getDevelopDate());
|
||||
entityTable_modifyDateColumn.setCellValueFactory(param -> param.getValue().getModifyDate());
|
||||
entityTable_creatorColumn.setCellValueFactory(param -> param.getValue().getCreator().map(stringConverter::toString));
|
||||
entityTable_modifierColumn.setCellValueFactory(param -> param.getValue().getModifier().map(stringConverter::toString));
|
||||
entityTable_updatedDateColumn.setCellValueFactory(param -> param.getValue().getUpdatedDate());
|
||||
|
||||
fetchedTimeColumn.setCellValueFactory(param -> param.getValue().getFetchedTime());
|
||||
fetchedTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
entityTable_menu_refresh.setOnAction(this::onTableRefreshAction);
|
||||
entityTable_menu_del.setOnAction(this::onTableDeleteAction);
|
||||
}
|
||||
|
||||
|
||||
private void initializeEntityTabCatalogColumn(TableColumn<CustomerEntityViewModel, String> column) {
|
||||
EntityStringConverter<CustomerCatalog> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(v -> getCompanyCustomerService().findCatalogById(v.getId()));
|
||||
column.setCellValueFactory(param -> param.getValue().getCatalog().map(converter::toString));
|
||||
}
|
||||
|
||||
CompanyCustomerEntityService getCompanyCustomerEntityService() {
|
||||
if (customerEntityService == null) {
|
||||
customerEntityService = getBean(CompanyCustomerEntityService.class);
|
||||
}
|
||||
return customerEntityService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompanyCustomerEntityService getViewModelService() {
|
||||
return getCompanyCustomerEntityService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<CompanyCustomerEntity> getSpecification(CompanyCustomer parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, builder) -> {
|
||||
return builder.equal(root.get("customer"), parent);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import com.ecep.contract.*;
|
||||
import com.ecep.contract.constant.CompanyCustomerConstant;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.model.*;
|
||||
import com.ecep.contract.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.service.CompanyCustomerService;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.util.UITools;
|
||||
import com.ecep.contract.vm.CompanyCustomerFileViewModel;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.ObservableMap;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.input.Dragboard;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@FxmlPath("/ui/company/customer/customer-tab-file.fxml")
|
||||
public class CustomerTabSkinFile
|
||||
extends AbstCompanyCustomerTableTabSkin<CompanyCustomerFile, CompanyCustomerFileViewModel>
|
||||
implements EditableEntityTableTabSkin<CompanyCustomerFile, CompanyCustomerFileViewModel> {
|
||||
|
||||
@Setter
|
||||
private CompanyCustomerFileService companyCustomerFileService;
|
||||
|
||||
public TableColumn<CompanyCustomerFileViewModel, Number> fileTable_idColumn;
|
||||
public TableColumn<CompanyCustomerFileViewModel, String> fileTable_typeColumn;
|
||||
public TableColumn<CompanyCustomerFileViewModel, String> fileTable_filePathColumn;
|
||||
public TableColumn<CompanyCustomerFileViewModel, String> fileTable_editFilePathColumn;
|
||||
public TableColumn<CompanyCustomerFileViewModel, LocalDate> fileTable_signDateColumn;
|
||||
public TableColumn<CompanyCustomerFileViewModel, Boolean> fileTable_validColumn;
|
||||
public TableColumn<CompanyCustomerFileViewModel, String> fileTable_descriptionColumn;
|
||||
|
||||
public Button fileTable_reBuildBtn;
|
||||
public Button fileTable_updateEvaluationFormBuildBtn;
|
||||
public Button fileTable_calcNextSignDateBtn;
|
||||
public MenuItem fileTable_menu_refresh;
|
||||
public MenuItem fileTable_menu_add;
|
||||
public MenuItem fileTable_menu_del;
|
||||
|
||||
public CustomerTabSkinFile(CompanyCustomerWindowController controller) {
|
||||
super(controller);
|
||||
setDragAndDrop(true);
|
||||
setDragAndDropFileHandler(this::moveFileToCustomer);
|
||||
}
|
||||
|
||||
// 文件 tab
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.fileTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompanyCustomerFileService getViewModelService() {
|
||||
return getCompanyCustomerFileService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getSpecification(CompanyCustomer parent) {
|
||||
Map<String, Object> params = getSpecification();
|
||||
params.put("customer", parent.getId());
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
|
||||
TableView<CompanyCustomerFileViewModel> table = getTableView();
|
||||
|
||||
table.disableProperty().bind(viewModel.getPath().isEmpty());
|
||||
fileTable_idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
ObservableMap<CompanyCustomerFileType, CompanyCustomerFileTypeLocal> observableMapByLocal = SpringApp
|
||||
.getBean(CompanyCustomerFileTypeLocalRepository.class).getObservableMapByLocal();
|
||||
fileTable_typeColumn.setCellValueFactory(param -> Bindings.valueAt(observableMapByLocal,
|
||||
param.getValue().getType()).map(BaseEnumEntity::getValue));
|
||||
|
||||
fileTable_filePathColumn.setCellValueFactory(param -> param.getValue().getFilePath());
|
||||
fileTable_filePathColumn.setCellFactory(param -> new FileTableFilePathTableCell());
|
||||
fileTable_editFilePathColumn.setCellValueFactory(param -> param.getValue().getEditFilePath());
|
||||
fileTable_editFilePathColumn.setCellFactory(param -> new FileTableFilePathTableCell());
|
||||
fileTable_signDateColumn.setCellValueFactory(param -> param.getValue().getSignDate());
|
||||
fileTable_validColumn.setEditable(true);
|
||||
fileTable_validColumn.setCellValueFactory(param -> param.getValue().getValid());
|
||||
fileTable_validColumn.setCellFactory(param -> new CheckBoxTableCell<>());
|
||||
|
||||
table.setOnDragOver(event -> {
|
||||
Dragboard dragboard = event.getDragboard();
|
||||
if (dragboard.hasFiles()) {
|
||||
event.acceptTransferModes(TransferMode.MOVE);
|
||||
}
|
||||
event.consume();
|
||||
});
|
||||
|
||||
table.setOnDragDropped(event -> {
|
||||
Dragboard dragboard = event.getDragboard();
|
||||
boolean success = false;
|
||||
if (dragboard.hasFiles()) {
|
||||
List<File> files = dragboard.getFiles();
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
moveFileToCustomer(files);
|
||||
} catch (Exception e) {
|
||||
UITools.showExceptionAndWait("移动文件出错", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
event.setDropCompleted(success);
|
||||
event.consume();
|
||||
});
|
||||
|
||||
fileTable_reBuildBtn.setOnAction(this::onFileReBuildingAction);
|
||||
fileTable_updateEvaluationFormBuildBtn.setOnAction(this::onUpdateEvaluationFormAction);
|
||||
fileTable_calcNextSignDateBtn.setOnAction(this::onCalcNextSignDateAction);
|
||||
|
||||
fileTable_menu_refresh.setOnAction(this::onTableRefreshAction);
|
||||
fileTable_menu_add.setOnAction(this::onTableDeleteAction);
|
||||
fileTable_menu_del.setOnAction(this::onFileTableMoveToCompanyPathAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CompanyCustomerFileViewModel item) {
|
||||
CompanyCustomerFileType fileType = item.getType().get();
|
||||
if (fileType == CompanyCustomerFileType.EvaluationForm) {
|
||||
// 文件不是 Excel 文件时,打开编辑UI
|
||||
if (!CompanyFileUtils.withExtensions(item.getFilePath().get(), CompanyFileUtils.XLS,
|
||||
CompanyFileUtils.XLSX)) {
|
||||
CompanyCustomerEvaluationFormFileWindowController.show(item, controller.root.getScene().getWindow());
|
||||
return;
|
||||
}
|
||||
}
|
||||
File file = new File(item.getFilePath().get());
|
||||
if (!file.exists()) {
|
||||
setStatus("文件不存在 " + file.getName());
|
||||
return;
|
||||
}
|
||||
DesktopUtils.showInExplorer(file);
|
||||
}
|
||||
|
||||
private void moveFileToCustomer(List<File> files) {
|
||||
String path = viewModel.getPath().get();
|
||||
if (!StringUtils.hasText(path)) {
|
||||
setStatus("未设置目录");
|
||||
return;
|
||||
}
|
||||
File dir = new File(path);
|
||||
if (!dir.exists()) {
|
||||
setStatus("目录错误,不存在");
|
||||
return;
|
||||
}
|
||||
CompanyCustomer companyCustomer = getParent();
|
||||
LocalDate nextSignDate = getCompanyCustomerFileService().getNextSignDate(companyCustomer, ((level, message) -> setStatus(message)));
|
||||
if (nextSignDate != null && files.size() == 1) {
|
||||
File file = files.getFirst();
|
||||
String fileName = file.getName();
|
||||
if (fileName.startsWith("S")) {
|
||||
String destFileName = CompanyCustomerConstant.EVALUATION_FORM_NAME2 + "_"
|
||||
+ MyDateTimeUtils.format(nextSignDate)
|
||||
+ "." + StringUtils.getFilenameExtension(fileName);
|
||||
File dest = new File(dir, destFileName);
|
||||
if (file.renameTo(dest)) {
|
||||
CompanyCustomerFile ccf = new CompanyCustomerFile();
|
||||
ccf.setCustomer(companyCustomer);
|
||||
ccf.setType(CompanyCustomerFileType.EvaluationForm);
|
||||
ccf.setFilePath(dest.getAbsolutePath());
|
||||
ccf.setSignDate(nextSignDate);
|
||||
ccf.setValid(false);
|
||||
CompanyCustomerFile saved = getCompanyCustomerFileService().save(ccf);
|
||||
Platform.runLater(() -> {
|
||||
CompanyCustomerFileViewModel model = new CompanyCustomerFileViewModel();
|
||||
model.update(saved);
|
||||
dataSet.add(model);
|
||||
CompanyCustomerEvaluationFormFileWindowController.show(model,
|
||||
getTableView().getScene().getWindow());
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
List<CompanyCustomerFile> companyCustomerFiles = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
File dest = new File(dir, file.getName());
|
||||
if (file.renameTo(dest)) {
|
||||
CompanyCustomerFile ccf = new CompanyCustomerFile();
|
||||
ccf.setCustomer(companyCustomer);
|
||||
ccf.setType(CompanyCustomerFileType.General);
|
||||
ccf.setFilePath(dest.getAbsolutePath());
|
||||
ccf.setValid(false);
|
||||
companyCustomerFiles.add(ccf);
|
||||
}
|
||||
}
|
||||
|
||||
getCompanyCustomerFileService().saveAll(companyCustomerFiles);
|
||||
|
||||
loadTableDataSet();
|
||||
}
|
||||
|
||||
public void onFileReBuildingAction(ActionEvent event) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
CompanyCustomerService customerService = getCompanyCustomerService();
|
||||
try {
|
||||
CompanyCustomer companyCustomer = customerService.findById(viewModel.getId().get());
|
||||
if (customerService.reBuildingFiles(companyCustomer, (level, message) -> setStatus(message))) {
|
||||
loadTableDataSet();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompanyCustomerFile loadRowData(CompanyCustomerFileViewModel row) {
|
||||
return getCompanyCustomerFileService().findById(row.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompanyCustomerFile saveRowData(CompanyCustomerFile entity) {
|
||||
return getCompanyCustomerFileService().save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRowData(CompanyCustomerFile entity) {
|
||||
getCompanyCustomerFileService().delete(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean deleteRow(CompanyCustomerFileViewModel row) {
|
||||
String path = row.getFilePath().get();
|
||||
if (super.deleteRow(row)) {
|
||||
File file = new File(path);
|
||||
if (file.exists()) {
|
||||
UITools.showConfirmation("数据记录已经删除,请确认是否删除物理文件", path)
|
||||
.thenAccept(buttonType -> {
|
||||
if (buttonType == ButtonType.OK) {
|
||||
if (file.delete()) {
|
||||
setStatus("删除文件 " + path);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onFileTableMoveToCompanyPathAction(ActionEvent event) {
|
||||
Company company = viewModel.getCompany().get();
|
||||
if (!Hibernate.isInitialized(company)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
viewModel.getCompany().set(company);
|
||||
}
|
||||
|
||||
if (!StringUtils.hasText(company.getPath())) {
|
||||
setStatus("公司目录未设置");
|
||||
return;
|
||||
}
|
||||
|
||||
File companyPath = new File(company.getPath());
|
||||
if (!companyPath.exists()) {
|
||||
setStatus("公司目录设置设置异常,无法访问");
|
||||
return;
|
||||
}
|
||||
|
||||
CompanyCustomerFileViewModel selectedItem = getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
return;
|
||||
}
|
||||
String filePath = selectedItem.getFilePath().get();
|
||||
String editFilePath = selectedItem.getEditFilePath().get();
|
||||
|
||||
if (StringUtils.hasText(filePath)) {
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
File dest = new File(companyPath, file.getName());
|
||||
if (file.renameTo(dest)) {
|
||||
setStatus(file.getAbsolutePath() + " -> " + dest.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(editFilePath)) {
|
||||
File file = new File(editFilePath);
|
||||
if (file.exists()) {
|
||||
File dest = new File(companyPath, file.getName());
|
||||
if (file.renameTo(dest)) {
|
||||
setStatus(file.getAbsolutePath() + " -> " + dest.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteRow(selectedItem);
|
||||
|
||||
// getCompanyCustomerService().deleteFileById(selectedItem.getId().get());
|
||||
// dataSet.remove(selectedItem);
|
||||
}
|
||||
|
||||
private void initializeTask(Task<Object> task, String prefix, Consumer<String> consumer) {
|
||||
task.setOnScheduled(e -> {
|
||||
consumer.accept("正在" + prefix + ",请稍后...");
|
||||
});
|
||||
task.setOnRunning(e -> {
|
||||
consumer.accept("开始" + prefix + "...");
|
||||
});
|
||||
task.setOnSucceeded(e -> {
|
||||
consumer.accept(prefix + "同步完成...");
|
||||
});
|
||||
task.exceptionProperty().addListener((observable, oldValue, newValue) -> {
|
||||
consumer.accept(newValue.getMessage());
|
||||
});
|
||||
SpringApp.getBean(ScheduledExecutorService.class).submit(task);
|
||||
consumer.accept("任务已创建...");
|
||||
}
|
||||
|
||||
public void onUpdateEvaluationFormAction(ActionEvent event) {
|
||||
CompanyCustomerEvaluationFormUpdateTask task = new CompanyCustomerEvaluationFormUpdateTask();
|
||||
task.setCompanyService(getCompanyService());
|
||||
task.setCompanyCustomerFileService(getCompanyCustomerFileService());
|
||||
task.setCustomer(getCompanyCustomerService().findById(viewModel.getId().get()));
|
||||
UITools.showTaskDialogAndWait("更新评价表", task, consumer -> {
|
||||
initializeTask(task, "更新评价表", msg -> consumer.accept(Message.info(msg)));
|
||||
});
|
||||
loadTableDataSet();
|
||||
}
|
||||
|
||||
public void onCalcNextSignDateAction(ActionEvent event) {
|
||||
UITools.showDialogAndWait("计算客户下一个评价日期", "依据已有的客户评估表和登记采购的合同计算下一个评估日期", ds -> {
|
||||
CompanyCustomer companyCustomer = getCompanyCustomerService().findById(viewModel.getId().get());
|
||||
LocalDate nextSignDate = getCompanyCustomerFileService().getNextSignDate(companyCustomer, (level, msg) -> {
|
||||
Platform.runLater(() -> {
|
||||
ds.add(msg);
|
||||
});
|
||||
});
|
||||
if (nextSignDate != null) {
|
||||
Platform.runLater(() -> {
|
||||
ds.add("下一个评价日期:" + nextSignDate);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class FileTableFilePathTableCell extends TableCell<CompanyCustomerFileViewModel, String> {
|
||||
@Override
|
||||
protected void updateItem(String item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || !StringUtils.hasText(item)) {
|
||||
setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
String path = viewModel.getPath().get();
|
||||
if (StringUtils.hasText(path)) {
|
||||
if (item.startsWith(path)) {
|
||||
item = "~" + item.substring(path.length());
|
||||
}
|
||||
}
|
||||
setText(item);
|
||||
}
|
||||
}
|
||||
|
||||
private CompanyCustomerFileService getCompanyCustomerFileService() {
|
||||
if (companyCustomerFileService == null) {
|
||||
companyCustomerFileService = SpringApp.getBean(CompanyCustomerFileService.class);
|
||||
}
|
||||
return companyCustomerFileService;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.project.satisfaction_survey.CustomerSatisfactionSurveyWindowController;
|
||||
import com.ecep.contract.controller.table.cell.EmployeeTableCell;
|
||||
import com.ecep.contract.controller.table.cell.ProjectTableCell;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.model.CustomerCatalog;
|
||||
import com.ecep.contract.model.CustomerSatisfactionSurvey;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.service.CustomerSatisfactionSurveyService;
|
||||
import com.ecep.contract.service.ProjectService;
|
||||
import com.ecep.contract.vm.CustomerEntityViewModel;
|
||||
import com.ecep.contract.vm.CustomerSatisfactionSurveyViewModel;
|
||||
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/company/customer/customer-tab-satisfaction-survey.fxml")
|
||||
public class CustomerTabSkinSatisfactionSurvey
|
||||
extends AbstCompanyCustomerTableTabSkin<CustomerSatisfactionSurvey, CustomerSatisfactionSurveyViewModel> {
|
||||
|
||||
// 关联项 tab
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, Number> idColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, Project> projectColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, String> codeColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, Number> totalScoreColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, Employee> applicantColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, LocalDateTime> applyTimeColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, String> descriptionColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, LocalDate> dateColumn;
|
||||
|
||||
public MenuItem entityTable_menu_refresh;
|
||||
public MenuItem entityTable_menu_del;
|
||||
@Setter
|
||||
private ProjectService projectService;
|
||||
@Setter
|
||||
private CustomerSatisfactionSurveyService satisfactionSurveyService;
|
||||
|
||||
public CustomerTabSkinSatisfactionSurvey(CompanyCustomerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.satisfactionTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
super.initializeTab();
|
||||
|
||||
bindNumberColumn(idColumn, CustomerSatisfactionSurveyViewModel::getId);
|
||||
bindColumn(codeColumn, CustomerSatisfactionSurveyViewModel::getCode);
|
||||
projectColumn.setCellValueFactory(param -> param.getValue().getProject());
|
||||
projectColumn.setCellFactory(cell -> new ProjectTableCell<>(getProjectService()));
|
||||
bindLocalDateColumn(dateColumn, CustomerSatisfactionSurveyViewModel::getDate);
|
||||
bindNumberColumn(totalScoreColumn, CustomerSatisfactionSurveyViewModel::getTotalScore);
|
||||
applicantColumn.setCellValueFactory(param -> param.getValue().getApplicant());
|
||||
applicantColumn.setCellFactory(cell -> new EmployeeTableCell<>(getEmployeeService()));
|
||||
bindLocalDateTimeColumn(applyTimeColumn, CustomerSatisfactionSurveyViewModel::getApplyTime);
|
||||
bindColumn(descriptionColumn, CustomerSatisfactionSurveyViewModel::getDescription);
|
||||
|
||||
entityTable_menu_refresh.setOnAction(this::onTableRefreshAction);
|
||||
entityTable_menu_del.setOnAction(this::onTableDeleteAction);
|
||||
}
|
||||
|
||||
private void initializeEntityTabCatalogColumn(TableColumn<CustomerEntityViewModel, String> column) {
|
||||
EntityStringConverter<CustomerCatalog> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(v -> getCompanyCustomerService().findCatalogById(v.getId()));
|
||||
column.setCellValueFactory(param -> param.getValue().getCatalog().map(converter::toString));
|
||||
}
|
||||
|
||||
private CustomerSatisfactionSurveyService getCustomerSatisfactionSurveyService() {
|
||||
if (satisfactionSurveyService == null) {
|
||||
satisfactionSurveyService = getBean(CustomerSatisfactionSurveyService.class);
|
||||
}
|
||||
return satisfactionSurveyService;
|
||||
}
|
||||
|
||||
ProjectService getProjectService() {
|
||||
if (projectService == null) {
|
||||
projectService = getBean(ProjectService.class);
|
||||
}
|
||||
return projectService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CustomerSatisfactionSurveyService getViewModelService() {
|
||||
return getCustomerSatisfactionSurveyService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getSpecification(CompanyCustomer parent) {
|
||||
Map<String, Object> params = getSpecification();
|
||||
params.put("project.customer", parent.getId());
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CustomerSatisfactionSurveyViewModel item) {
|
||||
showInOwner(CustomerSatisfactionSurveyWindowController.class, item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package com.ecep.contract.controller.customer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.tab.SalesOrderTabSkinBase;
|
||||
import com.ecep.contract.controller.tab.SalesOrderTabSkinBillVoucher;
|
||||
import com.ecep.contract.controller.tab.SalesOrderTabSkinItems;
|
||||
import com.ecep.contract.model.SalesOrder;
|
||||
import com.ecep.contract.service.SaleOrdersService;
|
||||
import com.ecep.contract.vm.SalesOrderViewModel;
|
||||
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/contract/sale-orders.fxml")
|
||||
public class SalesOrderWindowController extends AbstEntityController<SalesOrder, SalesOrderViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SalesOrderWindowController.class);
|
||||
public TabPane tabPane;
|
||||
public Button saveBtn;
|
||||
|
||||
public Tab baseInfoTab;
|
||||
public Tab itemTab;
|
||||
public Tab billVoucherTab;
|
||||
|
||||
public TextField codeField;
|
||||
public TextField employeeField;
|
||||
public TextField verifierDateField;
|
||||
public TextField verifierField;
|
||||
public TextField makeDateField;
|
||||
public TextField makerField;
|
||||
public TextArea descriptionField;
|
||||
|
||||
|
||||
public static void show(SalesOrderViewModel viewModel, Window window) {
|
||||
show(SalesOrderWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("销售订单详情");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab -> new SalesOrderTabSkinBase(this));
|
||||
registerTabSkin(itemTab, tab -> new SalesOrderTabSkinItems(this));
|
||||
registerTabSkin(billVoucherTab, tab -> new SalesOrderTabSkinBillVoucher(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SaleOrdersService getViewModelService() {
|
||||
return getCachedBean(SaleOrdersService.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.ecep.contract.controller.department;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.controller.ManagerSkin;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.model.Department;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.vm.DepartmentViewModel;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.control.cell.ComboBoxTableCell;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
|
||||
public class DepartmentManagerSkin
|
||||
extends AbstEntityManagerSkin<Department, DepartmentViewModel, DepartmentManagerSkin, DepartmentManagerWindowController>
|
||||
implements ManagerSkin, EditableEntityTableTabSkin<Department, DepartmentViewModel> {
|
||||
|
||||
|
||||
public DepartmentManagerSkin(DepartmentManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
getTableView().setEditable(true);
|
||||
|
||||
Specification<Employee> spec = (root, query, cb) -> {
|
||||
return cb.equal(root.get("isActive"), true);
|
||||
};
|
||||
List<Employee> employees = controller.getEmployeeService().findAll(spec, Pageable.ofSize(30)).getContent();
|
||||
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
controller.nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.nameColumn.setOnEditCommit(this::onNameColumnEditCommit);
|
||||
|
||||
controller.codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
controller.codeColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.codeColumn.setOnEditCommit(this::onCodeColumnEditCommit);
|
||||
|
||||
controller.leaderColumn.setCellValueFactory(param -> param.getValue().getLeader());
|
||||
controller.leaderColumn.setCellFactory(ComboBoxTableCell.forTableColumn(getBean(EmployeeStringConverter.class), FXCollections.observableArrayList(employees)));
|
||||
controller.leaderColumn.setOnEditCommit(this::onLeaderColumnEditCommit);
|
||||
|
||||
controller.activeColumn.setCellValueFactory(param -> param.getValue().getIsActive());
|
||||
controller.activeColumn.setEditable(true);
|
||||
controller.activeColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.activeColumn));
|
||||
controller.activeColumn.setOnEditCommit(this::onActiveColumnEditCommit);
|
||||
}
|
||||
|
||||
|
||||
private void onCodeColumnEditCommit(TableColumn.CellEditEvent<DepartmentViewModel, String> event) {
|
||||
DepartmentViewModel row = event.getRowValue();
|
||||
row.getCode().set(event.getNewValue());
|
||||
saveRowData(row);
|
||||
}
|
||||
|
||||
private void onNameColumnEditCommit(TableColumn.CellEditEvent<DepartmentViewModel, String> event) {
|
||||
DepartmentViewModel row = event.getRowValue();
|
||||
row.getName().set(event.getNewValue());
|
||||
saveRowData(row);
|
||||
}
|
||||
|
||||
private void onLeaderColumnEditCommit(TableColumn.CellEditEvent<DepartmentViewModel, Employee> event) {
|
||||
DepartmentViewModel row = event.getRowValue();
|
||||
row.getLeader().set(event.getNewValue());
|
||||
saveRowData(row);
|
||||
}
|
||||
|
||||
private void onActiveColumnEditCommit(TableColumn.CellEditEvent<DepartmentViewModel, Boolean> event) {
|
||||
DepartmentViewModel row = event.getRowValue();
|
||||
row.getIsActive().set(event.getNewValue());
|
||||
saveRowData(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(DepartmentViewModel item) {
|
||||
//TODO 显示详情
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableCreateNewAction(ActionEvent event) {
|
||||
Department employee = new Department();
|
||||
employee = controller.getViewModelService().save(employee);
|
||||
DepartmentViewModel viewModel = DepartmentViewModel.from(employee);
|
||||
dataSet.add(viewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.ecep.contract.controller.department;
|
||||
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.DepartmentService;
|
||||
import com.ecep.contract.model.Department;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.vm.DepartmentViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath(value = "/ui/employee/department-manager.fxml")
|
||||
public class DepartmentManagerWindowController
|
||||
extends AbstManagerWindowController<Department, DepartmentViewModel, DepartmentManagerSkin> {
|
||||
|
||||
public TableColumn<DepartmentViewModel, Number> idColumn;
|
||||
public TableColumn<DepartmentViewModel, String> nameColumn;
|
||||
public TableColumn<DepartmentViewModel, String> codeColumn;
|
||||
public TableColumn<DepartmentViewModel, Employee> leaderColumn;
|
||||
public TableColumn<DepartmentViewModel, Boolean> activeColumn;
|
||||
|
||||
@Autowired
|
||||
DepartmentService departmentService;
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("部门管理");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DepartmentManagerSkin createDefaultSkin() {
|
||||
return new DepartmentManagerSkin(this);
|
||||
}
|
||||
|
||||
public void onReBuildFilesAction(ActionEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public void onBaseTableRefreshAction(ActionEvent event) {
|
||||
getSkin().loadTableDataSet(true);
|
||||
}
|
||||
|
||||
public void onCreateNewAction(ActionEvent event) {
|
||||
getSkin().onTableCreateNewAction(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DepartmentService getViewModelService() {
|
||||
return departmentService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.ds.other.service.EmployeeRoleService;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.vm.EmployeeViewModel;
|
||||
|
||||
import lombok.Setter;
|
||||
|
||||
public abstract class AbstEmployeeBasedTabSkin
|
||||
extends AbstEntityBasedTabSkin<EmployeeWindowController, Employee, EmployeeViewModel>
|
||||
implements TabSkin {
|
||||
@Setter
|
||||
private PermissionService permissionService;
|
||||
@Setter
|
||||
private EmployeeRoleService employeeRoleService;
|
||||
|
||||
public AbstEmployeeBasedTabSkin(EmployeeWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
protected EmployeeService getEmployeeService() {
|
||||
return controller.employeeService;
|
||||
}
|
||||
|
||||
protected EmployeeRoleService getEmployeeRoleService() {
|
||||
if (employeeRoleService == null) {
|
||||
employeeRoleService = getBean(EmployeeRoleService.class);
|
||||
}
|
||||
return employeeRoleService;
|
||||
}
|
||||
|
||||
protected PermissionService getPermissionService() {
|
||||
if (permissionService == null) {
|
||||
permissionService = getBean(PermissionService.class);
|
||||
}
|
||||
return permissionService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import org.apache.poi.ss.formula.functions.T;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.EmployeeBasedViewModel;
|
||||
import com.ecep.contract.vm.EmployeeViewModel;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
|
||||
public abstract class AbstEmployeeTableTabSkin<T extends IdentityEntity, TV extends IdentityViewModel<T>>
|
||||
extends AbstEntityTableTabSkin<EmployeeWindowController, Employee, EmployeeViewModel, T, TV>
|
||||
implements TabSkin {
|
||||
|
||||
public AbstEmployeeTableTabSkin(EmployeeWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
public EmployeeService getEmployeeService() {
|
||||
return controller.employeeService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TV createNewViewModel() {
|
||||
TV model = super.createNewViewModel();
|
||||
if (model instanceof EmployeeBasedViewModel m) {
|
||||
m.getEmployee().set(getEntity());
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Specification<T> getSpecification(Employee parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, builder) -> {
|
||||
return builder.equal(root.get("employee"), parent);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.controller.ManagerSkin;
|
||||
import com.ecep.contract.ds.other.service.DepartmentService;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.ui.table.cell.DepartmentTableCell;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.EmployeeViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
|
||||
public class EmployeeManagerSkin
|
||||
extends AbstEntityManagerSkin<Employee, EmployeeViewModel, EmployeeManagerSkin, EmployeeManagerWindowController>
|
||||
implements ManagerSkin {
|
||||
public EmployeeManagerSkin(EmployeeManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
DepartmentService departmentService;
|
||||
|
||||
DepartmentService getDepartmentService() {
|
||||
if (departmentService == null) {
|
||||
departmentService = getBean(DepartmentService.class);
|
||||
}
|
||||
return departmentService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<Employee> getSpecification() {
|
||||
Specification<Employee> spec = super.getSpecification();
|
||||
if (controller.activeCheckBox.isSelected()) {
|
||||
spec = SpecificationUtils.and(spec, (root, query, builder) -> {
|
||||
return builder.isTrue(root.get("isActive"));
|
||||
});
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
controller.aliasColumn.setCellValueFactory(param -> param.getValue().getAlias());
|
||||
controller.codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
controller.accountColumn.setCellValueFactory(param -> param.getValue().getAccount());
|
||||
|
||||
controller.departmentColumn.setCellValueFactory(param -> param.getValue().getDepartment());
|
||||
controller.departmentColumn.setCellFactory(param -> new DepartmentTableCell<>(getDepartmentService()));
|
||||
|
||||
|
||||
controller.emailColumn.setCellValueFactory(param -> param.getValue().getEmail());
|
||||
controller.createdColumn.setCellValueFactory(param -> param.getValue().getCreated());
|
||||
controller.entryDateColumn.setCellValueFactory(param -> param.getValue().getEntryDate());
|
||||
controller.leaveDateColumn.setCellValueFactory(param -> param.getValue().getLeaveDate());
|
||||
controller.activeColumn.setCellValueFactory(param -> param.getValue().getIsActive());
|
||||
controller.activeColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.activeColumn));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(EmployeeViewModel item) {
|
||||
show(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableCreateNewAction(ActionEvent event) {
|
||||
Employee employee = new Employee();
|
||||
employee = controller.getViewModelService().save(employee);
|
||||
EmployeeViewModel viewModel = EmployeeViewModel.from(employee);
|
||||
dataSet.add(viewModel);
|
||||
show(viewModel);
|
||||
|
||||
}
|
||||
|
||||
public void show(EmployeeViewModel viewModel) {
|
||||
showInOwner(EmployeeWindowController.class, viewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.cloud.u8.EmployeesSyncTask;
|
||||
import com.ecep.contract.constant.CloudServiceConstant;
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.model.Department;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.vm.EmployeeViewModel;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/employee/employee-manager.fxml")
|
||||
public class EmployeeManagerWindowController
|
||||
extends AbstManagerWindowController<Employee, EmployeeViewModel, EmployeeManagerSkin> {
|
||||
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, Number> idColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, String> accountColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, Department> departmentColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, String> nameColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, String> aliasColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, String> codeColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, String> emailColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, LocalDate> createdColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, LocalDate> entryDateColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, LocalDate> leaveDateColumn;
|
||||
@FXML
|
||||
public TableColumn<EmployeeViewModel, Boolean> activeColumn;
|
||||
@FXML
|
||||
public CheckBox activeCheckBox;
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("员工管理");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EmployeeManagerSkin createDefaultSkin() {
|
||||
return new EmployeeManagerSkin(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 U8系统 同步员工数据
|
||||
*/
|
||||
public void onSyncFromU8Action(ActionEvent event) {
|
||||
Task<Object> task = new EmployeesSyncTask();
|
||||
UITools.showTaskDialogAndWait("从 " + CloudServiceConstant.U8_NAME + " 同步员工数据", task, null);
|
||||
}
|
||||
|
||||
|
||||
public void onBaseTableRefreshAction(ActionEvent event) {
|
||||
getSkin().loadTableDataSet(true);
|
||||
}
|
||||
|
||||
public void onCreateNewAction(ActionEvent event) {
|
||||
getSkin().onTableCreateNewAction(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmployeeService getViewModelService() {
|
||||
return getEmployeeService();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.EmployeeAuthBindService;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.EmployeeAuthBind;
|
||||
import com.ecep.contract.ui.table.cell.EmployeeTableCell;
|
||||
import com.ecep.contract.vm.EmployeeAuthBindViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/employee/employee-auth-bind.fxml")
|
||||
public class EmployeeTabSkinAuthBind
|
||||
extends AbstEmployeeTableTabSkin<EmployeeAuthBind, EmployeeAuthBindViewModel> {
|
||||
public TableColumn<EmployeeAuthBindViewModel, Number> idColumn;
|
||||
public TableColumn<EmployeeAuthBindViewModel, String> ipColumn;
|
||||
public TableColumn<EmployeeAuthBindViewModel, String> macColumn;
|
||||
public TableColumn<EmployeeAuthBindViewModel, LocalDateTime> createTime;
|
||||
public TableColumn<EmployeeAuthBindViewModel, LocalDateTime> updateTimeColumn;
|
||||
public TableColumn<EmployeeAuthBindViewModel, Employee> updaterColumn;
|
||||
public TableColumn<EmployeeAuthBindViewModel, String> descriptionColumn;
|
||||
|
||||
@Setter
|
||||
private EmployeeAuthBindService employeeAuthBindService;
|
||||
|
||||
public EmployeeTabSkinAuthBind(EmployeeWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
EmployeeAuthBindService getEmployeeAuthBindService() {
|
||||
if (employeeAuthBindService == null) {
|
||||
employeeAuthBindService = getBean(EmployeeAuthBindService.class);
|
||||
}
|
||||
return employeeAuthBindService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EmployeeAuthBindService getViewModelService() {
|
||||
return getEmployeeAuthBindService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.authBindTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
super.initializeTab();
|
||||
getTableView().setEditable(true);
|
||||
|
||||
bindNumberColumn(idColumn, EmployeeAuthBindViewModel::getId);
|
||||
|
||||
bindColumn(ipColumn, EmployeeAuthBindViewModel::getIp);
|
||||
bindColumn(macColumn, EmployeeAuthBindViewModel::getMac);
|
||||
|
||||
bindLocalDateTimeColumn(createTime, EmployeeAuthBindViewModel::getCreateTime);
|
||||
bindLocalDateTimeColumn(updateTimeColumn, EmployeeAuthBindViewModel::getUpdateTime);
|
||||
|
||||
updaterColumn.setCellValueFactory(param -> param.getValue().getUpdater());
|
||||
updaterColumn.setCellFactory(cell -> new EmployeeTableCell<>());
|
||||
|
||||
bindColumn(descriptionColumn, EmployeeAuthBindViewModel::getDescription);
|
||||
|
||||
Platform.runLater(() -> {
|
||||
getTableView().getSortOrder().add(updateTimeColumn);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
super.createContextMenu(contextMenu);
|
||||
MenuItem menuItem = new MenuItem("导入未关联");
|
||||
menuItem.setOnAction(event -> {
|
||||
EmployeeAuthBindService service = getEmployeeAuthBindService();
|
||||
List<EmployeeAuthBind> authBinds = service.findAllByEmployee(null, Sort.unsorted());
|
||||
for (EmployeeAuthBind authBind : authBinds) {
|
||||
authBind.setEmployee(getEntity());
|
||||
authBind.setUpdateTime(LocalDateTime.now());
|
||||
authBind.setUpdater(controller.getCurrentUser());
|
||||
service.save(authBind);
|
||||
}
|
||||
});
|
||||
contextMenu.getItems().add(menuItem);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.other.service.DepartmentService;
|
||||
import com.ecep.contract.model.Department;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
|
||||
public class EmployeeTabSkinBase
|
||||
extends AbstEmployeeBasedTabSkin
|
||||
implements TabSkin {
|
||||
public EmployeeTabSkinBase(EmployeeWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
EntityStringConverter<Department> departmentEntityStringConverter = new EntityStringConverter<>();
|
||||
DepartmentService departmentService = getBean(DepartmentService.class);
|
||||
departmentEntityStringConverter.setInitialized(department -> departmentService.findById(department.getId()));
|
||||
UITools.autoCompletion(controller.departmentField, viewModel.getDepartment(),
|
||||
p -> departmentService.search(p.getUserText()), departmentEntityStringConverter);
|
||||
|
||||
controller.nameField.textProperty().bindBidirectional(viewModel.getName());
|
||||
controller.aliasField.textProperty().bindBidirectional(viewModel.getAlias());
|
||||
controller.codeField.textProperty().bind(viewModel.getCode());
|
||||
controller.accountField.textProperty().bindBidirectional(viewModel.getAccount());
|
||||
controller.emailField.textProperty().bindBidirectional(viewModel.getEmail());
|
||||
controller.phoneField.textProperty().bindBidirectional(viewModel.getPhone());
|
||||
|
||||
LocalDateStringConverter converter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
controller.leaveDateField.setConverter(converter);
|
||||
controller.leaveDateField.valueProperty().bindBidirectional(viewModel.getLeaveDate());
|
||||
controller.entryDateField.setConverter(converter);
|
||||
controller.entryDateField.valueProperty().bindBidirectional(viewModel.getEntryDate());
|
||||
|
||||
controller.createdField.setConverter(converter);
|
||||
controller.createdField.valueProperty().bindBidirectional(viewModel.getCreated());
|
||||
|
||||
controller.isActiveField.selectedProperty().bindBidirectional(viewModel.getIsActive());
|
||||
|
||||
|
||||
// Callback<ListView<EmployeeRole>, ListCell<EmployeeRole>> cellFactory = controller.rolesField.getCellFactory();
|
||||
// StringConverter<EmployeeRole> employeeRoleStringConverter = new EntityStringConverter<>();
|
||||
// controller.rolesField.setCellFactory(param -> {
|
||||
// ListCell<EmployeeRole> cell = cellFactory.call(param);
|
||||
// if (cell instanceof CheckBoxListCell<EmployeeRole> list) {
|
||||
// list.setConverter(employeeRoleStringConverter);
|
||||
// }
|
||||
// return cell;
|
||||
// });
|
||||
|
||||
|
||||
// controller.rolesField.getCheckModel().getCheckedItems().setAll();
|
||||
// Property<IndexedCheckModel<EmployeeRole>> selectedRoles = new SimpleObjectProperty<>();
|
||||
// controller.rolesField.getCheckModel().getCheckedItems().addListener((ListChangeListener<? super EmployeeRole>) changed -> {
|
||||
// System.out.println("newValue = " + changed);
|
||||
// });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.ds.other.service.EmployeeLoginHistoryService;
|
||||
import com.ecep.contract.model.EmployeeLoginHistory;
|
||||
import com.ecep.contract.ui.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.vm.EmployeeLoginHistoryViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
|
||||
@FxmlPath("/ui/employee/employee-login-history.fxml")
|
||||
public class EmployeeTabSkinLoginHistory
|
||||
extends AbstEmployeeTableTabSkin<EmployeeLoginHistory, EmployeeLoginHistoryViewModel>
|
||||
implements TabSkin {
|
||||
public TableColumn<EmployeeLoginHistoryViewModel, Number> idColumn;
|
||||
public TableColumn<EmployeeLoginHistoryViewModel, String> ipColumn;
|
||||
public TableColumn<EmployeeLoginHistoryViewModel, String> macColumn;
|
||||
public TableColumn<EmployeeLoginHistoryViewModel, LocalDateTime> loginTimeColumn;
|
||||
public TableColumn<EmployeeLoginHistoryViewModel, LocalDateTime> activeTimeColumn;
|
||||
|
||||
private EmployeeLoginHistoryService loginHistoryService;
|
||||
|
||||
public EmployeeTabSkinLoginHistory(EmployeeWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
EmployeeLoginHistoryService getLoginHistoryService() {
|
||||
if (loginHistoryService == null) {
|
||||
loginHistoryService = getBean(EmployeeLoginHistoryService.class);
|
||||
}
|
||||
return loginHistoryService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EmployeeLoginHistoryService getViewModelService() {
|
||||
return getLoginHistoryService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.loginHistoryTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
super.initializeTab();
|
||||
|
||||
idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
ipColumn.setCellValueFactory(param -> param.getValue().getIp());
|
||||
macColumn.setCellValueFactory(param -> param.getValue().getMac());
|
||||
loginTimeColumn.setCellValueFactory(param -> param.getValue().getLoginTime());
|
||||
loginTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
activeTimeColumn.setCellValueFactory(param -> param.getValue().getActiveTime());
|
||||
activeTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
getTableView().getSortOrder().add(activeTimeColumn);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.Tab;
|
||||
|
||||
public class EmployeeTabSkinRole
|
||||
extends AbstEmployeeBasedTabSkin
|
||||
implements TabSkin {
|
||||
|
||||
private final SimpleBooleanProperty changed = new SimpleBooleanProperty(false);
|
||||
|
||||
public EmployeeTabSkinRole(EmployeeWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanProperty changeProperty() {
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.rolesTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
initializeListView();
|
||||
loadSelectedRoles();
|
||||
}
|
||||
|
||||
private void loadSelectedRoles() {
|
||||
List<EmployeeRole> selectedRoles = getEmployeeService().getRolesByEmployeeId(viewModel.getId().get());
|
||||
controller.rolesField.getTargetItems().setAll(selectedRoles);
|
||||
changed.set(false);
|
||||
}
|
||||
|
||||
private void initializeListView() {
|
||||
// 非系统内置账户
|
||||
Specification<EmployeeRole> spec = null;
|
||||
if (!Desktop.instance.getActiveEmployee().isSystemAdministrator()) {
|
||||
spec = (root, query, cb) -> cb.equal(root.get("systemAdministrator"), false);
|
||||
}
|
||||
List<EmployeeRole> roles = getEmployeeRoleService().findAll(spec, Pageable.ofSize(500)).getContent();
|
||||
|
||||
controller.rolesField.getSourceItems().setAll(roles);
|
||||
controller.rolesField.setCellFactory(param -> {
|
||||
return new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(EmployeeRole item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item == null || empty) {
|
||||
setText(null);
|
||||
} else {
|
||||
setText(item.getName());
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
controller.rolesField.getTargetItems().addListener((ListChangeListener<EmployeeRole>) change -> {
|
||||
while (change.next()) {
|
||||
List<? extends EmployeeRole> added = change.getAddedSubList();
|
||||
List<? extends EmployeeRole> removed = change.getRemoved();
|
||||
if (!added.isEmpty() || !removed.isEmpty()) {
|
||||
changed.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
Employee entity = getEntity();
|
||||
entity.setRoles(controller.rolesField.getTargetItems());
|
||||
save(entity);
|
||||
loadSelectedRoles();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.ecep.contract.controller.employee;
|
||||
|
||||
import org.controlsfx.control.ListSelectionView;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
import com.ecep.contract.vm.EmployeeViewModel;
|
||||
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import lombok.Getter;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/employee/employee.fxml")
|
||||
public class EmployeeWindowController extends AbstEntityController<Employee, EmployeeViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmployeeWindowController.class);
|
||||
|
||||
/**
|
||||
* 显示界面
|
||||
*/
|
||||
public static void show(EmployeeViewModel viewModel, Window window) {
|
||||
show(EmployeeWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
public Tab baseInfoTab;
|
||||
|
||||
public TextField nameField;
|
||||
public TextField departmentField;
|
||||
public TextField aliasField;
|
||||
public TextField accountField;
|
||||
public TextField emailField;
|
||||
public TextField phoneField;
|
||||
public DatePicker createdField;
|
||||
public TextField codeField;
|
||||
public DatePicker leaveDateField;
|
||||
public DatePicker entryDateField;
|
||||
public CheckBox isActiveField;
|
||||
/*
|
||||
|
||||
*/
|
||||
public Tab rolesTab;
|
||||
public ListSelectionView<EmployeeRole> rolesField;
|
||||
|
||||
public Tab loginHistoryTab;
|
||||
public Tab authBindTab;
|
||||
/*
|
||||
|
||||
*/
|
||||
public Tab permissionsTab;
|
||||
public TableView<Tab> permissionsTable;
|
||||
|
||||
|
||||
public static void show(Employee employee, Window owner) {
|
||||
EmployeeViewModel model = EmployeeViewModel.from(employee);
|
||||
show(model, owner);
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
@Getter
|
||||
EmployeeService employeeService;
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().bind(viewModel.getName().map(name -> "[" + viewModel.getId().get() + "] " + name + " 员工详情"));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab -> new EmployeeTabSkinBase(this));
|
||||
registerTabSkin(rolesTab, tab -> new EmployeeTabSkinRole(this));
|
||||
registerTabSkin(loginHistoryTab, tab -> new EmployeeTabSkinLoginHistory(this));
|
||||
registerTabSkin(authBindTab, tab -> new EmployeeTabSkinAuthBind(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmployeeService getViewModelService() {
|
||||
return employeeService;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.ecep.contract.controller.inventory;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.controller.table.LocalDateFieldTableCell;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.other.service.InventoryCatalogService;
|
||||
import com.ecep.contract.ds.other.service.InventoryService;
|
||||
import com.ecep.contract.model.Inventory;
|
||||
import com.ecep.contract.model.InventoryCatalog;
|
||||
import com.ecep.contract.ui.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.vm.InventoryViewModel;
|
||||
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class InventoryManagerSkin extends
|
||||
AbstEntityManagerSkin<Inventory, InventoryViewModel, InventoryManagerSkin, InventoryManagerWindowController> {
|
||||
|
||||
@Setter
|
||||
private InventoryCatalogService catalogService;
|
||||
|
||||
public InventoryManagerSkin(InventoryManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
InventoryService getService() {
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
|
||||
InventoryCatalogService getInventoryCatalogService() {
|
||||
if (catalogService == null) {
|
||||
catalogService = getBean(InventoryCatalogService.class);
|
||||
}
|
||||
return catalogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
getTableView().setEditable(false);
|
||||
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
controller.nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.nameColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getName));
|
||||
|
||||
controller.codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
controller.codeColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.codeColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getCode));
|
||||
|
||||
controller.catalogColumn.setCellValueFactory(param -> param.getValue().getCatalog());
|
||||
EntityStringConverter<InventoryCatalog> catalogStringConverter = new EntityStringConverter<>();
|
||||
catalogStringConverter.setInitialized(v -> getInventoryCatalogService().findById(v.getId()));
|
||||
catalogStringConverter.setFormater(InventoryCatalog::getName);
|
||||
catalogStringConverter.setFromString(v -> getInventoryCatalogService().findByName(v));
|
||||
catalogStringConverter.setSuggestion(getInventoryCatalogService()::search);
|
||||
|
||||
controller.catalogColumn.setCellFactory(TextFieldTableCell.forTableColumn(catalogStringConverter));
|
||||
controller.catalogColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getCatalog));
|
||||
|
||||
controller.specificationColumn.setCellValueFactory(param -> param.getValue().getSpecification());
|
||||
controller.specificationColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.specificationColumn
|
||||
.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getSpecification));
|
||||
|
||||
controller.unitColumn.setCellValueFactory(param -> param.getValue().getUnit());
|
||||
controller.unitColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.unitColumn.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getUnit));
|
||||
|
||||
controller.purchaseTaxRateColumn.setCellValueFactory(param -> param.getValue().getPurchaseTaxRate());
|
||||
controller.purchaseTaxRateColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
controller.purchaseTaxRateColumn
|
||||
.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getPurchaseTaxRate));
|
||||
|
||||
controller.purchasePriceColumn.setCellValueFactory(param -> param.getValue().getPurchasePrice());
|
||||
controller.purchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter()));
|
||||
// controller.purchasePriceColumn.setOnEditCommit(event ->
|
||||
// onColumnEditCommit(event, InventoryViewModel::getPurchasePrice));
|
||||
|
||||
controller.saleTaxRateColumn.setCellValueFactory(param -> param.getValue().getSaleTaxRate());
|
||||
controller.saleTaxRateColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
controller.saleTaxRateColumn
|
||||
.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getSaleTaxRate));
|
||||
|
||||
controller.salePriceColumn.setCellValueFactory(param -> param.getValue().getSalePrice());
|
||||
controller.salePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter()));
|
||||
// controller.salePriceColumn.setOnEditCommit(event -> onColumnEditCommit(event,
|
||||
// InventoryViewModel::getSalePrice));
|
||||
|
||||
controller.createTimeColumn.setCellValueFactory(param -> param.getValue().getCreateTime());
|
||||
controller.createTimeColumn.setCellFactory(LocalDateFieldTableCell.forTableColumn());
|
||||
controller.createTimeColumn
|
||||
.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getCreateTime));
|
||||
|
||||
controller.updateDateColumn.setCellValueFactory(param -> param.getValue().getUpdateDate());
|
||||
controller.updateDateColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
controller.updateDateColumn
|
||||
.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getUpdateDate));
|
||||
|
||||
controller.descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
|
||||
controller.descriptionColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.descriptionColumn
|
||||
.setOnEditCommit(event -> onColumnEditCommit(event, InventoryViewModel::getDescription));
|
||||
}
|
||||
|
||||
private <T> void onColumnEditCommit(
|
||||
TableColumn.CellEditEvent<InventoryViewModel, T> event,
|
||||
Function<InventoryViewModel, Property<T>> supplier) {
|
||||
InventoryViewModel row = event.getRowValue();
|
||||
supplier.apply(row).setValue(event.getNewValue());
|
||||
saveRowData(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(InventoryViewModel item) {
|
||||
showInOwner(InventoryWindowController.class, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableCreateNewAction(ActionEvent event) {
|
||||
Inventory inventory = getService().save(getService().createNewInstance());
|
||||
InventoryViewModel viewModel = InventoryViewModel.from(inventory);
|
||||
dataSet.add(viewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.ecep.contract.controller.inventory;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.controller.InventorySyncTask;
|
||||
import com.ecep.contract.ds.other.service.InventoryService;
|
||||
import com.ecep.contract.model.Inventory;
|
||||
import com.ecep.contract.model.InventoryCatalog;
|
||||
import com.ecep.contract.vm.InventoryViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath(value = "/ui/inventory/inventory-manager.fxml")
|
||||
public class InventoryManagerWindowController
|
||||
extends AbstManagerWindowController<Inventory, InventoryViewModel, InventoryManagerSkin> {
|
||||
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, Number> idColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, String> nameColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, String> codeColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, InventoryCatalog> catalogColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, String> specificationColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, String> unitColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, Number> purchaseTaxRateColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, Number> purchasePriceColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, Number> saleTaxRateColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, Number> salePriceColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, LocalDate> createTimeColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, LocalDateTime> updateDateColumn;
|
||||
@FXML
|
||||
public TableColumn<InventoryViewModel, String> descriptionColumn;
|
||||
|
||||
@Autowired
|
||||
private InventoryService service;
|
||||
|
||||
@Override
|
||||
public InventoryService getViewModelService() {
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("存货管理");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InventoryManagerSkin createDefaultSkin() {
|
||||
return new InventoryManagerSkin(this);
|
||||
}
|
||||
|
||||
public void onSyncAction(ActionEvent event) {
|
||||
InventorySyncTask task = new InventorySyncTask();
|
||||
UITools.showTaskDialogAndWait("同步数据", task, null);
|
||||
}
|
||||
|
||||
public void onCreateNewAction(ActionEvent event) {
|
||||
getSkin().onTableCreateNewAction(event);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.ecep.contract.controller.inventory;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.MessageHolder;
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.cloud.u8.ctx.InventoryCtx;
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.other.service.InventoryCatalogService;
|
||||
import com.ecep.contract.ds.other.service.InventoryService;
|
||||
import com.ecep.contract.model.Inventory;
|
||||
import com.ecep.contract.model.InventoryCatalog;
|
||||
import com.ecep.contract.vm.InventoryViewModel;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import javafx.util.converter.LocalDateTimeStringConverter;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class InventoryTabSkinBase
|
||||
extends AbstEntityBasedTabSkin<InventoryWindowController, Inventory, InventoryViewModel>
|
||||
implements TabSkin, EditableEntityTableTabSkin<Inventory, InventoryViewModel> {
|
||||
@Setter
|
||||
private InventoryService service;
|
||||
@Setter
|
||||
private InventoryCatalogService catalogService;
|
||||
|
||||
public InventoryTabSkinBase(InventoryWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
InventoryService getService() {
|
||||
if (service == null) {
|
||||
service = getBean(InventoryService.class);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
InventoryCatalogService getCatalogService() {
|
||||
if (catalogService == null) {
|
||||
catalogService = getBean(InventoryCatalogService.class);
|
||||
}
|
||||
return catalogService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
controller.syncBtn.setOnAction(this::onSyncAction);
|
||||
|
||||
NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
|
||||
numberInstance.setMaximumFractionDigits(2);
|
||||
numberInstance.setMinimumFractionDigits(2);
|
||||
CurrencyStringConverter currencyStringConverter = new CurrencyStringConverter(numberInstance);
|
||||
|
||||
controller.nameField.textProperty().bindBidirectional(viewModel.getName());
|
||||
controller.nameLockField.selectedProperty().bindBidirectional(viewModel.getNameLock());
|
||||
controller.codeField.textProperty().bind(viewModel.getCode());
|
||||
controller.unitField.textProperty().bindBidirectional(viewModel.getUnit());
|
||||
controller.specificationField.textProperty().bindBidirectional(viewModel.getSpecification());
|
||||
controller.specificationLockField.selectedProperty().bindBidirectional(viewModel.getSpecificationLock());
|
||||
|
||||
EntityStringConverter<InventoryCatalog> catalogConverter = new EntityStringConverter<>();
|
||||
catalogConverter.setInitialized(v -> getCatalogService().findById(v.getId()));
|
||||
catalogConverter.setFormater(InventoryCatalog::getName);
|
||||
catalogConverter.setSuggestion(getCatalogService()::search);
|
||||
catalogConverter.setFromString(getCatalogService()::findByName);
|
||||
UITools.autoCompletion(controller.catalogField, viewModel.getCatalog(), catalogConverter);
|
||||
|
||||
controller.purchaseTaxRateField.textProperty().bindBidirectional(viewModel.getPurchaseTaxRate(),
|
||||
new NumberStringConverter());
|
||||
// 采购价
|
||||
bindPriceField(controller.purchasePriceField, viewModel.getPurchasePrice(), currencyStringConverter,
|
||||
viewModel::updatePurchasePrice);
|
||||
bindPriceField(controller.purchaseTaxPriceField, viewModel.getPurchaseTaxPrice(), currencyStringConverter,
|
||||
viewModel::updatePurchaseTaxPrice);
|
||||
|
||||
controller.saleTaxRateField.textProperty().bindBidirectional(viewModel.getSaleTaxRate(),
|
||||
new NumberStringConverter());
|
||||
// 销售价
|
||||
bindPriceField(controller.salePriceField, viewModel.getSalePrice(), currencyStringConverter,
|
||||
viewModel::updateSalePrice);
|
||||
bindPriceField(controller.saleTaxPriceField, viewModel.getSaleTaxPrice(), currencyStringConverter,
|
||||
viewModel::updateSaleTaxPrice);
|
||||
|
||||
// 采购价不能大于销售价
|
||||
Bindings.greaterThan(viewModel.getPurchasePrice(), viewModel.getSalePrice())
|
||||
.addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
controller.purchasePriceField.getStyleClass().add("error");
|
||||
controller.salePriceField.getStyleClass().add("error");
|
||||
} else {
|
||||
controller.purchasePriceField.getStyleClass().remove("error");
|
||||
controller.salePriceField.getStyleClass().remove("error");
|
||||
}
|
||||
});
|
||||
Bindings.greaterThan(viewModel.getPurchaseTaxPrice(), viewModel.getSaleTaxPrice())
|
||||
.addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
controller.purchaseTaxPriceField.getStyleClass().add("error");
|
||||
controller.saleTaxPriceField.getStyleClass().add("error");
|
||||
} else {
|
||||
controller.purchaseTaxPriceField.getStyleClass().remove("error");
|
||||
controller.saleTaxPriceField.getStyleClass().remove("error");
|
||||
}
|
||||
});
|
||||
|
||||
EmployeeStringConverter employeeStringConverter = getBean(EmployeeStringConverter.class);
|
||||
UITools.autoCompletion(controller.creatorField, viewModel.getCreator(), employeeStringConverter);
|
||||
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATE_FORMAT_PATTERN);
|
||||
controller.createTimeField.textProperty().bindBidirectional(viewModel.getCreateTime(),
|
||||
new LocalDateStringConverter(dateFormatter, null));
|
||||
|
||||
UITools.autoCompletion(controller.updaterField, viewModel.getUpdater(), employeeStringConverter);
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter
|
||||
.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN);
|
||||
controller.updateDateField.textProperty().bindBidirectional(viewModel.getUpdateDate(),
|
||||
new LocalDateTimeStringConverter(dateTimeFormatter, null));
|
||||
|
||||
controller.weightUnitField.textProperty().bindBidirectional(viewModel.getWeightUnit());
|
||||
controller.sizeUnitField.textProperty().bindBidirectional(viewModel.getSizeUnit());
|
||||
controller.volumeUnitField.textProperty().bindBidirectional(viewModel.getVolumeUnit());
|
||||
controller.weightField.textProperty().bindBidirectional(viewModel.getWeight(), new NumberStringConverter());
|
||||
controller.packagedWeightField.textProperty().bindBidirectional(viewModel.getPackagedWeight(),
|
||||
new NumberStringConverter());
|
||||
controller.sizeLengthField.textProperty().bindBidirectional(viewModel.getSizeLength(),
|
||||
new NumberStringConverter());
|
||||
controller.sizeWidthField.textProperty().bindBidirectional(viewModel.getSizeWidth(),
|
||||
new NumberStringConverter());
|
||||
controller.sizeHeightField.textProperty().bindBidirectional(viewModel.getSizeHeight(),
|
||||
new NumberStringConverter());
|
||||
controller.volumeField.textProperty().bindBidirectional(viewModel.getVolume(), new NumberStringConverter());
|
||||
controller.packagedSizeLengthField.textProperty().bindBidirectional(viewModel.getPackagedSizeLength(),
|
||||
new NumberStringConverter());
|
||||
controller.packagedSizeWidthField.textProperty().bindBidirectional(viewModel.getPackagedSizeWidth(),
|
||||
new NumberStringConverter());
|
||||
controller.packagedSizeHeightField.textProperty().bindBidirectional(viewModel.getPackagedSizeHeight(),
|
||||
new NumberStringConverter());
|
||||
controller.packagedVolumeField.textProperty().bindBidirectional(viewModel.getPackagedVolume(),
|
||||
new NumberStringConverter());
|
||||
|
||||
controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());
|
||||
}
|
||||
|
||||
private void bindPriceField(TextField textField, SimpleDoubleProperty property,
|
||||
CurrencyStringConverter stringConverter, Consumer<Double> updater) {
|
||||
textField.setText(stringConverter.toString(property.get()));
|
||||
property.addListener((observable, oldValue, newValue) -> {
|
||||
textField.setText(stringConverter.toString(newValue));
|
||||
});
|
||||
textField.setOnKeyTyped(event -> {
|
||||
Number number = stringConverter.fromString(textField.getText());
|
||||
updater.accept(number.doubleValue());
|
||||
});
|
||||
}
|
||||
|
||||
private void onSyncAction(ActionEvent event) {
|
||||
Inventory inventory = getEntity();
|
||||
setStatus("开始同步数据...");
|
||||
if (inventory == null) {
|
||||
setStatus("请选择要同步的数据.");
|
||||
return;
|
||||
}
|
||||
if (!StringUtils.hasText(inventory.getCode())) {
|
||||
setStatus("请填写商品编码.");
|
||||
return;
|
||||
}
|
||||
setStatus("正在同步数据...");
|
||||
InventoryCtx ctx = new InventoryCtx();
|
||||
MessageHolder holder = (lv, msg) -> setStatus(msg);
|
||||
ctx.initializeRepository(holder);
|
||||
if (ctx.syncInventoryDetailByCode(inventory, inventory.getCode(), holder)) {
|
||||
save(inventory);
|
||||
setStatus("同步数据完成.");
|
||||
} else {
|
||||
setStatus("没有数据更新.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRowData(Inventory entity) {
|
||||
getService().delete(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory loadRowData(InventoryViewModel row) {
|
||||
return getService().findById(row.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Inventory saveRowData(Inventory entity) {
|
||||
return getService().save(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.ecep.contract.controller.inventory;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.controller.ContractWindowController;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.contract.service.ContractItemService;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.other.service.InventoryHistoryPriceService;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.ContractItem;
|
||||
import com.ecep.contract.model.Inventory;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.ContractViewModel;
|
||||
import com.ecep.contract.vm.InventoryViewModel;
|
||||
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.criteria.Subquery;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/inventory/inventory-contract.fxml")
|
||||
public class InventoryTabSkinContracts
|
||||
extends
|
||||
AbstEntityTableTabSkin<InventoryWindowController, Inventory, InventoryViewModel, Contract, ContractViewModel>
|
||||
implements TabSkin {
|
||||
public TableColumn<ContractViewModel, Number> idColumn;
|
||||
public TableColumn<ContractViewModel, String> nameColumn;
|
||||
public TableColumn<ContractViewModel, String> codeColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> setupDateColumn;
|
||||
|
||||
@Setter
|
||||
InventoryHistoryPriceService inventoryHistoryPriceService;
|
||||
@Setter
|
||||
ContractService contractService;
|
||||
@Setter
|
||||
ContractItemService contractItemService;
|
||||
|
||||
public InventoryTabSkinContracts(InventoryWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractService getViewModelService() {
|
||||
return getContractService();
|
||||
}
|
||||
|
||||
InventoryHistoryPriceService getInventoryHistoryPriceService() {
|
||||
if (inventoryHistoryPriceService == null) {
|
||||
inventoryHistoryPriceService = getBean(InventoryHistoryPriceService.class);
|
||||
}
|
||||
return inventoryHistoryPriceService;
|
||||
}
|
||||
|
||||
ContractItemService getContractItemService() {
|
||||
if (contractItemService == null) {
|
||||
contractItemService = getBean(ContractItemService.class);
|
||||
}
|
||||
return contractItemService;
|
||||
}
|
||||
|
||||
ContractService getContractService() {
|
||||
if (contractService == null) {
|
||||
contractService = getBean(ContractService.class);
|
||||
}
|
||||
return contractService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.contractsTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
|
||||
numberInstance.setMaximumFractionDigits(2);
|
||||
numberInstance.setMinimumFractionDigits(2);
|
||||
CurrencyStringConverter currencyStringConverter = new CurrencyStringConverter(numberInstance);
|
||||
|
||||
idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
setupDateColumn.setCellValueFactory(param -> param.getValue().getSetupDate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<Contract> getSpecification(Inventory parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, builder) -> {
|
||||
// 创建ContractItem的子查询
|
||||
Subquery<Integer> subquery = query.subquery(Integer.class);
|
||||
Root<ContractItem> from = subquery.from(ContractItem.class);
|
||||
// 子查询选择与指定库存相关的合同ID
|
||||
subquery.select(from.get("contract").get("id"))
|
||||
.where(builder.equal(from.get("inventory"), parent));
|
||||
|
||||
// 主查询筛选ID在子查询结果中的合同
|
||||
return builder.in(root.get("id")).value(subquery);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
MenuItem item2 = new MenuItem("刷新");
|
||||
item2.setOnAction(this::onTableRefreshAction);
|
||||
contextMenu.getItems().add(item2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(ContractViewModel item) {
|
||||
showInOwner(ContractWindowController.class, item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
package com.ecep.contract.controller.inventory;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.time.MonthDay;
|
||||
import java.time.Year;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.ContractPayWay;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.contract.service.ContractItemService;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.other.service.InventoryHistoryPriceService;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.ContractItem;
|
||||
import com.ecep.contract.model.HistoryPrice;
|
||||
import com.ecep.contract.model.Inventory;
|
||||
import com.ecep.contract.model.InventoryHistoryPrice;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.InventoryHistoryPriceViewModel;
|
||||
import com.ecep.contract.vm.InventoryViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/inventory/inventory-history-price.fxml")
|
||||
public class InventoryTabSkinHistoryPrice
|
||||
extends
|
||||
AbstEntityTableTabSkin<InventoryWindowController, Inventory, InventoryViewModel, InventoryHistoryPrice, InventoryHistoryPriceViewModel>
|
||||
implements TabSkin {
|
||||
public Button refreshBtn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> idColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Year> yearColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> latestSaleTaxColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> latestSalePriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> latestSaleTaxPriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, MonthDay> latestSalePriceDateColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> latestPurchaseTaxColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> latestPurchasePriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> latestPurchaseTaxPriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, MonthDay> latestPurchasePriceDateColumn;
|
||||
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> maxSaleTaxColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> maxSalePriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> maxSaleTaxPriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, MonthDay> maxSalePriceDateColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> maxPurchaseTaxColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> maxPurchasePriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> maxPurchaseTaxPriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, MonthDay> maxPurchasePriceDateColumn;
|
||||
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> miniSaleTaxColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> miniSalePriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> miniSaleTaxPriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, MonthDay> miniSalePriceDateColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> miniPurchaseTaxColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> miniPurchasePriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, Number> miniPurchaseTaxPriceColumn;
|
||||
public TableColumn<InventoryHistoryPriceViewModel, MonthDay> miniPurchasePriceDateColumn;
|
||||
|
||||
@Setter
|
||||
InventoryHistoryPriceService service;
|
||||
@Setter
|
||||
ContractService contractService;
|
||||
@Setter
|
||||
ContractItemService contractItemService;
|
||||
|
||||
public InventoryTabSkinHistoryPrice(InventoryWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InventoryHistoryPriceService getViewModelService() {
|
||||
return getService();
|
||||
}
|
||||
|
||||
InventoryHistoryPriceService getService() {
|
||||
if (service == null) {
|
||||
service = getBean(InventoryHistoryPriceService.class);
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
ContractItemService getContractItemService() {
|
||||
if (contractItemService == null) {
|
||||
contractItemService = getBean(ContractItemService.class);
|
||||
}
|
||||
return contractItemService;
|
||||
}
|
||||
|
||||
ContractService getContractService() {
|
||||
if (contractService == null) {
|
||||
contractService = getBean(ContractService.class);
|
||||
}
|
||||
return contractService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.historyPriceTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
refreshBtn.setOnAction(this::onRefreshAction);
|
||||
|
||||
NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
|
||||
numberInstance.setMaximumFractionDigits(2);
|
||||
numberInstance.setMinimumFractionDigits(2);
|
||||
CurrencyStringConverter currencyStringConverter = new CurrencyStringConverter(numberInstance);
|
||||
|
||||
idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
yearColumn.setCellValueFactory(param -> param.getValue().getYear());
|
||||
|
||||
latestSaleTaxColumn.setCellValueFactory(param -> param.getValue().getLatestSaleTax());
|
||||
latestSaleTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
latestSalePriceColumn.setCellValueFactory(param -> param.getValue().getLatestSalePrice());
|
||||
latestSalePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
latestSaleTaxPriceColumn.setCellValueFactory(param -> param.getValue().getLatestSaleTaxPrice());
|
||||
latestSaleTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
latestSalePriceDateColumn.setCellValueFactory(param -> param.getValue().getLatestSalePriceDate());
|
||||
|
||||
latestPurchaseTaxColumn.setCellValueFactory(param -> param.getValue().getLatestPurchaseTax());
|
||||
latestPurchaseTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
latestPurchaseTaxPriceColumn.setCellValueFactory(param -> param.getValue().getLatestPurchaseTaxPrice());
|
||||
latestPurchaseTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
latestPurchasePriceColumn.setCellValueFactory(param -> param.getValue().getLatestPurchasePrice());
|
||||
latestPurchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
latestPurchasePriceDateColumn.setCellValueFactory(param -> param.getValue().getLatestPurchasePriceDate());
|
||||
|
||||
maxSaleTaxColumn.setCellValueFactory(param -> param.getValue().getMaxSaleTax());
|
||||
maxSaleTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
maxSalePriceColumn.setCellValueFactory(param -> param.getValue().getMaxSalePrice());
|
||||
maxSalePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
maxSaleTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMaxSaleTaxPrice());
|
||||
maxSaleTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
maxSalePriceDateColumn.setCellValueFactory(param -> param.getValue().getMaxSalePriceDate());
|
||||
|
||||
maxPurchaseTaxColumn.setCellValueFactory(param -> param.getValue().getMaxPurchaseTax());
|
||||
maxPurchaseTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
maxPurchasePriceDateColumn.setCellValueFactory(param -> param.getValue().getMaxPurchasePriceDate());
|
||||
maxPurchasePriceColumn.setCellValueFactory(param -> param.getValue().getMaxPurchasePrice());
|
||||
maxPurchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
maxPurchaseTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMaxPurchaseTaxPrice());
|
||||
maxPurchaseTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
|
||||
miniSaleTaxColumn.setCellValueFactory(param -> param.getValue().getMiniSaleTax());
|
||||
miniSaleTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
miniSalePriceColumn.setCellValueFactory(param -> param.getValue().getMiniSalePrice());
|
||||
miniSalePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
miniSaleTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMiniSaleTaxPrice());
|
||||
miniSaleTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
miniSalePriceDateColumn.setCellValueFactory(param -> param.getValue().getMiniSalePriceDate());
|
||||
|
||||
miniPurchaseTaxColumn.setCellValueFactory(param -> param.getValue().getMiniPurchaseTax());
|
||||
miniPurchaseTaxColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter()));
|
||||
miniPurchasePriceColumn.setCellValueFactory(param -> param.getValue().getMiniPurchasePrice());
|
||||
miniPurchasePriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
miniPurchasePriceDateColumn.setCellValueFactory(param -> param.getValue().getMiniPurchasePriceDate());
|
||||
miniPurchaseTaxPriceColumn.setCellValueFactory(param -> param.getValue().getMiniPurchaseTaxPrice());
|
||||
miniPurchaseTaxPriceColumn.setCellFactory(TextFieldTableCell.forTableColumn(currencyStringConverter));
|
||||
|
||||
}
|
||||
|
||||
private void onRefreshAction(ActionEvent event) {
|
||||
runAsync(() -> {
|
||||
|
||||
HashMap<Integer, InventoryHistoryPrice> historyPriceMap = new HashMap<>();
|
||||
|
||||
for (InventoryHistoryPrice historyPrice : getService().findAllByInventory(getParent())) {
|
||||
InventoryHistoryPrice oldValue = historyPriceMap.put(historyPrice.getYear().getValue(), historyPrice);
|
||||
if (oldValue != null) {
|
||||
getService().delete(oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
List<ContractItem> items = getContractItemService().findAllByInventory(getParent());
|
||||
items.stream().collect(Collectors.groupingBy(v -> {
|
||||
Contract contract = v.getContract();
|
||||
if (!Hibernate.isInitialized(contract)) {
|
||||
contract = getContractService().findById(contract.getId());
|
||||
v.setContract(contract);
|
||||
}
|
||||
return contract.getSetupDate().getYear();
|
||||
})).forEach((year, list) -> {
|
||||
InventoryHistoryPrice historyPrice = historyPriceMap.computeIfAbsent(year, k -> {
|
||||
InventoryHistoryPrice price = new InventoryHistoryPrice();
|
||||
price.setInventory(getParent());
|
||||
price.setYear(year);
|
||||
return price;
|
||||
});
|
||||
|
||||
list.stream().collect(Collectors.groupingBy(v -> {
|
||||
Contract contract = v.getContract();
|
||||
return contract.getPayWay();
|
||||
})).forEach((payWay, contractItems) -> {
|
||||
if (ContractPayWay.RECEIVE.equals(payWay)) {
|
||||
// 销售
|
||||
list.stream().max(Comparator.comparing(v -> {
|
||||
Contract contract = v.getContract();
|
||||
return contract.getSetupDate();
|
||||
})).ifPresent(v -> update(historyPrice.getLatestSalePrice(), v));
|
||||
|
||||
list.stream().max(Comparator.comparing(ContractItem::getTaxPrice))
|
||||
.ifPresent(v -> update(historyPrice.getMaxSalePrice(), v));
|
||||
list.stream().min(Comparator.comparing(ContractItem::getTaxPrice))
|
||||
.ifPresent(v -> update(historyPrice.getMiniSalePrice(), v));
|
||||
|
||||
} else if (ContractPayWay.PAY.equals(payWay)) {
|
||||
// 采购
|
||||
list.stream().max(Comparator.comparing(v -> {
|
||||
Contract contract = v.getContract();
|
||||
return contract.getSetupDate();
|
||||
})).ifPresent(v -> update(historyPrice.getLatestPurchasePrice(), v));
|
||||
|
||||
list.stream().max(Comparator.comparing(ContractItem::getTaxPrice))
|
||||
.ifPresent(v -> update(historyPrice.getMaxPurchasePrice(), v));
|
||||
list.stream().min(Comparator.comparing(ContractItem::getTaxPrice))
|
||||
.ifPresent(v -> update(historyPrice.getMiniPurchasePrice(), v));
|
||||
} else {
|
||||
|
||||
}
|
||||
});
|
||||
getService().save(historyPrice);
|
||||
});
|
||||
|
||||
loadTableDataSet();
|
||||
});
|
||||
}
|
||||
|
||||
void update(HistoryPrice historyPrice, ContractItem item) {
|
||||
if (item == null) {
|
||||
historyPrice.setTaxRate(0);
|
||||
historyPrice.setPreTaxPrice(0);
|
||||
historyPrice.setPostTaxPrice(0);
|
||||
historyPrice.setMonthDay(null);
|
||||
return;
|
||||
}
|
||||
getContractService();
|
||||
Contract contract = item.getContract();
|
||||
if (!Hibernate.isInitialized(contract)) {
|
||||
contract = getContractService().findById(contract.getId());
|
||||
item.setContract(contract);
|
||||
}
|
||||
historyPrice.setTaxRate((float) item.getTaxRate());
|
||||
historyPrice.setPreTaxPrice(item.getExclusiveTaxPrice());
|
||||
historyPrice.setPostTaxPrice(item.getTaxPrice());
|
||||
historyPrice.setMonthDay(MonthDay.from(contract.getSetupDate()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<InventoryHistoryPrice> getSpecification(Inventory parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, builder) -> {
|
||||
return builder.equal(root.get("inventory"), parent);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
MenuItem item2 = new MenuItem("刷新");
|
||||
item2.setOnAction(this::onTableRefreshAction);
|
||||
contextMenu.getItems().add(item2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.ecep.contract.controller.inventory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.InventoryService;
|
||||
import com.ecep.contract.model.Inventory;
|
||||
import com.ecep.contract.vm.InventoryViewModel;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/inventory/inventory.fxml")
|
||||
public class InventoryWindowController extends AbstEntityController<Inventory, InventoryViewModel> {
|
||||
@FXML
|
||||
public BorderPane root;
|
||||
@FXML
|
||||
public TabPane tabPane;
|
||||
@FXML
|
||||
public Tab baseInfoTab;
|
||||
@FXML
|
||||
public Tab historyPriceTab;
|
||||
@FXML
|
||||
public Tab contractsTab;
|
||||
|
||||
@FXML
|
||||
public TextField nameField;
|
||||
@FXML
|
||||
public CheckBox nameLockField;
|
||||
@FXML
|
||||
public TextField catalogField;
|
||||
@FXML
|
||||
public TextField unitField;
|
||||
@FXML
|
||||
public TextField codeField;
|
||||
@FXML
|
||||
public TextField specificationField;
|
||||
@FXML
|
||||
public CheckBox specificationLockField;
|
||||
@FXML
|
||||
public TextField purchasePriceField;
|
||||
@FXML
|
||||
public TextField purchaseTaxRateField;
|
||||
@FXML
|
||||
public TextField purchaseTaxPriceField;
|
||||
@FXML
|
||||
public TextField creatorField;
|
||||
@FXML
|
||||
public TextField createTimeField;
|
||||
@FXML
|
||||
public TextField updaterField;
|
||||
@FXML
|
||||
public TextField updateDateField;
|
||||
@FXML
|
||||
public TextField saleTaxRateField;
|
||||
@FXML
|
||||
public TextField salePriceField;
|
||||
@FXML
|
||||
public TextField saleTaxPriceField;
|
||||
@FXML
|
||||
public TextArea descriptionField;
|
||||
@FXML
|
||||
public Button syncBtn;
|
||||
@FXML
|
||||
public TextField weightUnitField;
|
||||
@FXML
|
||||
public TextField sizeUnitField;
|
||||
@FXML
|
||||
public TextField volumeUnitField;
|
||||
@FXML
|
||||
public TextField weightField;
|
||||
@FXML
|
||||
public TextField packagedWeightField;
|
||||
@FXML
|
||||
public TextField sizeLengthField;
|
||||
@FXML
|
||||
public TextField sizeWidthField;
|
||||
@FXML
|
||||
public TextField sizeHeightField;
|
||||
@FXML
|
||||
public TextField volumeField;
|
||||
@FXML
|
||||
public TextField packagedSizeLengthField;
|
||||
@FXML
|
||||
public TextField packagedSizeWidthField;
|
||||
@FXML
|
||||
public TextField packagedSizeHeightField;
|
||||
@FXML
|
||||
public TextField packagedVolumeField;
|
||||
|
||||
@Autowired
|
||||
private InventoryService service;
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().bind(Bindings.createStringBinding(
|
||||
() -> "[" + viewModel.getId().get() + "] 存货详情 " + viewModel.getName().getValue() + " "
|
||||
+ viewModel.getSpecification().get(),
|
||||
viewModel.getName(), viewModel.getCode(), viewModel.getSpecification()));
|
||||
root.getScene().getStylesheets().add("/ui/inventory/inventory.css");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Inventory loadEntity() {
|
||||
return service.findById(viewModel.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Inventory saveEntity(Inventory entity) {
|
||||
return service.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab -> new InventoryTabSkinBase(this));
|
||||
registerTabSkin(historyPriceTab, tab -> new InventoryTabSkinHistoryPrice(this));
|
||||
registerTabSkin(contractsTab, tab -> new InventoryTabSkinContracts(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryService getViewModelService() {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.ds.other.service.EmployeeRoleService;
|
||||
import com.ecep.contract.ds.other.service.FunctionService;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
import com.ecep.contract.vm.EmployeeRoleViewModel;
|
||||
|
||||
public abstract class AbstEmployeeRoleBasedTabSkin
|
||||
extends AbstEntityBasedTabSkin<EmployeeRoleWindowController, EmployeeRole, EmployeeRoleViewModel> {
|
||||
|
||||
private EmployeeRoleService roleService;
|
||||
private FunctionService functionService;
|
||||
|
||||
public AbstEmployeeRoleBasedTabSkin(EmployeeRoleWindowController controller) {
|
||||
super(controller);
|
||||
viewModel = controller.getViewModel();
|
||||
}
|
||||
|
||||
EmployeeRoleService getRoleService() {
|
||||
if (roleService == null) {
|
||||
roleService = getBean(EmployeeRoleService.class);
|
||||
}
|
||||
return roleService;
|
||||
}
|
||||
|
||||
FunctionService getFunctionService() {
|
||||
if (functionService == null) {
|
||||
functionService = getBean(FunctionService.class);
|
||||
}
|
||||
return functionService;
|
||||
}
|
||||
|
||||
public PermissionService getPermissionService() {
|
||||
return controller.permissionService;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Description;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.FunctionService;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.Function;
|
||||
import com.ecep.contract.vm.FunctionViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Description("")
|
||||
@FxmlPath("/ui/employee/functions-manager.fxml")
|
||||
@Component
|
||||
public class EmployeeFunctionsManagerWindowController
|
||||
extends AbstManagerWindowController<Function, FunctionViewModel, FunctionManagerSkin> {
|
||||
|
||||
@Autowired
|
||||
PermissionService permissionService;
|
||||
@Autowired
|
||||
FunctionService functionService;
|
||||
|
||||
@FXML
|
||||
public TableColumn<FunctionViewModel, Number> idColumn;
|
||||
@FXML
|
||||
public TableColumn<FunctionViewModel, String> nameColumn;
|
||||
@FXML
|
||||
public TableColumn<FunctionViewModel, String> keyColumn;
|
||||
@FXML
|
||||
public TableColumn<FunctionViewModel, String> controllerColumn;
|
||||
@FXML
|
||||
public TableColumn<FunctionViewModel, String> iconColumn;
|
||||
@FXML
|
||||
public TableColumn<FunctionViewModel, String> descriptionColumn;
|
||||
@FXML
|
||||
public TableColumn<FunctionViewModel, Boolean> activeColumn;
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("功能管理");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FunctionManagerSkin createDefaultSkin() {
|
||||
return new FunctionManagerSkin(this);
|
||||
}
|
||||
|
||||
public void onCreateNewAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
public void onReBuildFilesAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionService getViewModelService() {
|
||||
return functionService;
|
||||
}
|
||||
|
||||
public PermissionService getPermissionService() {
|
||||
return permissionService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.controller.ManagerSkin;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
import com.ecep.contract.vm.EmployeeRoleViewModel;
|
||||
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import lombok.Setter;
|
||||
|
||||
public class EmployeeRoleManagerSkin
|
||||
extends
|
||||
AbstEntityManagerSkin<EmployeeRole, EmployeeRoleViewModel, EmployeeRoleManagerSkin, EmployeeRoleManagerWindowController>
|
||||
implements ManagerSkin, EditableEntityTableTabSkin<EmployeeRole, EmployeeRoleViewModel> {
|
||||
|
||||
@Setter
|
||||
private PermissionService permissionService;
|
||||
|
||||
public EmployeeRoleManagerSkin(EmployeeRoleManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
controller.codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
controller.systemAdministratorColumn.setCellValueFactory(param -> param.getValue().getSystemAdministrator());
|
||||
controller.systemAdministratorColumn.setCellFactory(param -> new CheckBoxTableCell<>());
|
||||
controller.managerColumn.setCellValueFactory(param -> param.getValue().getManager());
|
||||
controller.managerColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.managerColumn));
|
||||
controller.activeColumn.setCellValueFactory(param -> param.getValue().getActive());
|
||||
controller.activeColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.activeColumn));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(EmployeeRoleViewModel item) {
|
||||
EmployeeRoleWindowController.show(item, controller.table.getScene().getWindow());
|
||||
}
|
||||
|
||||
protected PermissionService getPermissionService() {
|
||||
if (permissionService == null) {
|
||||
permissionService = getBean(PermissionService.class);
|
||||
}
|
||||
return permissionService;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.EmployeeRoleService;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
import com.ecep.contract.vm.EmployeeRoleViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/employee/roles-manager.fxml")
|
||||
public class EmployeeRoleManagerWindowController
|
||||
extends AbstManagerWindowController<EmployeeRole, EmployeeRoleViewModel, EmployeeRoleManagerSkin> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmployeeRoleManagerWindowController.class);
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
@Autowired
|
||||
EmployeeRoleService employeeRoleService;
|
||||
|
||||
public TableColumn<EmployeeRoleViewModel, Number> idColumn;
|
||||
public TableColumn<EmployeeRoleViewModel, String> codeColumn;
|
||||
public TableColumn<EmployeeRoleViewModel, String> nameColumn;
|
||||
public TableColumn<EmployeeRoleViewModel, Boolean> systemAdministratorColumn;
|
||||
public TableColumn<EmployeeRoleViewModel, Boolean> managerColumn;
|
||||
public TableColumn<EmployeeRoleViewModel, Boolean> activeColumn;
|
||||
|
||||
@Override
|
||||
protected EmployeeRoleManagerSkin createDefaultSkin() {
|
||||
EmployeeRoleManagerSkin skin = new EmployeeRoleManagerSkin(this);
|
||||
skin.setPermissionService(permissionService);
|
||||
return skin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show(Stage stage) {
|
||||
super.show(stage);
|
||||
getTitle().set("角色管理");
|
||||
}
|
||||
|
||||
public void onCreateNewAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
public void onReBuildFilesAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmployeeRoleService getViewModelService() {
|
||||
return employeeRoleService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
|
||||
public class EmployeeRoleTabSkinBase extends AbstEmployeeRoleBasedTabSkin implements TabSkin {
|
||||
|
||||
public EmployeeRoleTabSkinBase(EmployeeRoleWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
controller.nameField.textProperty().bindBidirectional(viewModel.getName());
|
||||
controller.codeField.textProperty().bindBidirectional(viewModel.getCode());
|
||||
if (Desktop.instance.getActiveEmployee().isSystemAdministrator()) {
|
||||
controller.systemAdministratorField.selectedProperty().bindBidirectional(viewModel.getSystemAdministrator());
|
||||
} else {
|
||||
controller.systemAdministratorField.selectedProperty().bind(viewModel.getSystemAdministrator());
|
||||
}
|
||||
controller.managerField.selectedProperty().bindBidirectional(viewModel.getManager());
|
||||
controller.activeField.selectedProperty().bindBidirectional(viewModel.getActive());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.controlsfx.control.ListSelectionView;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
import com.ecep.contract.model.Function;
|
||||
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.Tab;
|
||||
|
||||
public class EmployeeRoleTabSkinFunctions extends AbstEmployeeRoleBasedTabSkin {
|
||||
|
||||
private final SimpleBooleanProperty changed = new SimpleBooleanProperty(false);
|
||||
private ListSelectionView<Function> functionsField;
|
||||
|
||||
public EmployeeRoleTabSkinFunctions(EmployeeRoleWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeUIComponents() {
|
||||
super.initializeUIComponents();
|
||||
functionsField = controller.functionsField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.functionsTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
Tab tab = getTab();
|
||||
if (viewModel.getSystemAdministrator().get()) {
|
||||
tab.setDisable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
initializeListView();
|
||||
loadSelectedRoles();
|
||||
}
|
||||
|
||||
private void loadSelectedRoles() {
|
||||
List<Function> selectedRoles = getRoleService().getFunctionsByRoleId(viewModel.getId().get());
|
||||
if (selectedRoles != null) {
|
||||
functionsField.getTargetItems().setAll(selectedRoles);
|
||||
}
|
||||
changed.set(false);
|
||||
}
|
||||
|
||||
private void initializeListView() {
|
||||
// 非系统内置账户
|
||||
Specification<Function> spec = (root, query, cb) -> cb.equal(root.get("active"), true);
|
||||
List<Function> roles = getFunctionService().findAll(spec, Pageable.ofSize(500)).getContent();
|
||||
|
||||
functionsField.getSourceItems().setAll(roles);
|
||||
functionsField.setCellFactory(param -> {
|
||||
return new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(Function item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item == null || empty) {
|
||||
setText(null);
|
||||
} else {
|
||||
setText(item.getName());
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
functionsField.getTargetItems().addListener((ListChangeListener<Function>) change -> {
|
||||
while (change.next()) {
|
||||
List<? extends Function> added = change.getAddedSubList();
|
||||
List<? extends Function> removed = change.getRemoved();
|
||||
if (!added.isEmpty() || !removed.isEmpty()) {
|
||||
changed.set(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Node targetFooter = functionsField.getTargetFooter();
|
||||
if (targetFooter instanceof Button btn) {
|
||||
initializeSaveButton(btn);
|
||||
}
|
||||
targetFooter.disableProperty().bind(changed.not());
|
||||
}
|
||||
|
||||
private void initializeSaveButton(Button button) {
|
||||
button.setOnAction(this::saveRoles);
|
||||
}
|
||||
|
||||
private void saveRoles(ActionEvent event) {
|
||||
EmployeeRole entity = getEntity();
|
||||
entity.setFunctions(functionsField.getTargetItems());
|
||||
save(entity);
|
||||
loadSelectedRoles();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import org.controlsfx.control.ListSelectionView;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.EmployeeRoleService;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.EmployeeRole;
|
||||
import com.ecep.contract.vm.EmployeeRoleViewModel;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/employee/role.fxml")
|
||||
public class EmployeeRoleWindowController extends AbstEntityController<EmployeeRole, EmployeeRoleViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmployeeRoleWindowController.class);
|
||||
|
||||
|
||||
public static void show(EmployeeRoleViewModel viewModel, Window window) {
|
||||
show(EmployeeRoleWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
public Tab baseInfoTab;
|
||||
public TextField nameField;
|
||||
public TextField codeField;
|
||||
public CheckBox systemAdministratorField;
|
||||
public CheckBox managerField;
|
||||
public DatePicker createdField;
|
||||
@FXML
|
||||
public CheckBox activeField;
|
||||
public Label versionLabel;
|
||||
/*
|
||||
|
||||
*/
|
||||
public Tab functionsTab;
|
||||
public ListSelectionView<com.ecep.contract.model.Function> functionsField;
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
public Tab permissionsTab;
|
||||
|
||||
|
||||
@Autowired
|
||||
PermissionService permissionService;
|
||||
@Autowired
|
||||
EmployeeRoleService employeeRoleService;
|
||||
|
||||
@Override
|
||||
protected EmployeeRole loadEntity() {
|
||||
return employeeRoleService.findById(viewModel.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EmployeeRole saveEntity(EmployeeRole role) {
|
||||
return employeeRoleService.save(role);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().bind(viewModel.getName().map(name -> "[" + viewModel.getId().get() + "] " + name + " 角色详情"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab -> new EmployeeRoleTabSkinBase(this));
|
||||
registerTabSkin(functionsTab, tab -> new EmployeeRoleTabSkinFunctions(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmployeeRoleService getViewModelService() {
|
||||
return employeeRoleService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.ds.other.service.FunctionService;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.Function;
|
||||
import com.ecep.contract.vm.FunctionViewModel;
|
||||
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
|
||||
public class FunctionManagerSkin
|
||||
extends
|
||||
AbstEntityManagerSkin<Function, FunctionViewModel, FunctionManagerSkin, EmployeeFunctionsManagerWindowController> {
|
||||
|
||||
public FunctionManagerSkin(EmployeeFunctionsManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
controller.nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.nameColumn.setOnEditCommit(this::onNameColumnEditCommit);
|
||||
|
||||
controller.keyColumn.setCellValueFactory(param -> param.getValue().getKey());
|
||||
controller.keyColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.keyColumn.setOnEditCommit(this::onKeyColumnEditCommit);
|
||||
|
||||
controller.controllerColumn.setCellValueFactory(param -> param.getValue().getController());
|
||||
controller.controllerColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.controllerColumn.setOnEditCommit(this::onControllerColumnEditCommit);
|
||||
|
||||
controller.iconColumn.setCellValueFactory(param -> param.getValue().getIcon());
|
||||
controller.iconColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.iconColumn.setOnEditCommit(this::onIconColumnEditCommit);
|
||||
|
||||
controller.descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
|
||||
controller.descriptionColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
controller.descriptionColumn.setOnEditCommit(this::onDescriptionColumnEditCommit);
|
||||
|
||||
controller.activeColumn.setCellValueFactory(param -> param.getValue().getActive());
|
||||
controller.activeColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.activeColumn));
|
||||
}
|
||||
|
||||
private void onNameColumnEditCommit(TableColumn.CellEditEvent<FunctionViewModel, String> event) {
|
||||
acceptCellEditEvent(event, FunctionViewModel::getName);
|
||||
}
|
||||
|
||||
private void onKeyColumnEditCommit(TableColumn.CellEditEvent<FunctionViewModel, String> event) {
|
||||
acceptCellEditEvent(event, FunctionViewModel::getKey);
|
||||
}
|
||||
|
||||
private void onControllerColumnEditCommit(TableColumn.CellEditEvent<FunctionViewModel, String> event) {
|
||||
acceptCellEditEvent(event, FunctionViewModel::getController);
|
||||
}
|
||||
|
||||
private void onIconColumnEditCommit(TableColumn.CellEditEvent<FunctionViewModel, String> event) {
|
||||
acceptCellEditEvent(event, FunctionViewModel::getIcon);
|
||||
}
|
||||
|
||||
private void onDescriptionColumnEditCommit(TableColumn.CellEditEvent<FunctionViewModel, String> event) {
|
||||
acceptCellEditEvent(event, FunctionViewModel::getDescription);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(FunctionViewModel item) {
|
||||
showInOwner(FunctionWindowController.class, item);
|
||||
}
|
||||
|
||||
protected PermissionService getPermissionService() {
|
||||
return controller.getPermissionService();
|
||||
}
|
||||
|
||||
protected FunctionService getFunctionService() {
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.model.Function;
|
||||
import com.ecep.contract.vm.FunctionViewModel;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
|
||||
public class FunctionTabSkinBase
|
||||
extends AbstEntityBasedTabSkin<FunctionWindowController, Function, FunctionViewModel> {
|
||||
|
||||
public FunctionTabSkinBase(FunctionWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
// 绑定UI元素与viewModel的属性
|
||||
controller.nameField.textProperty().bindBidirectional(viewModel.getName());
|
||||
controller.keyField.textProperty().bindBidirectional(viewModel.getKey());
|
||||
controller.controllerField.textProperty().bindBidirectional(viewModel.getController());
|
||||
controller.iconField.textProperty().bindBidirectional(viewModel.getIcon());
|
||||
controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());
|
||||
controller.activeField.selectedProperty().bindBidirectional(viewModel.getActive());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.other.service.PermissionService;
|
||||
import com.ecep.contract.model.Function;
|
||||
import com.ecep.contract.model.Permission;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.FunctionViewModel;
|
||||
import com.ecep.contract.vm.PermissionViewModel;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
|
||||
@FxmlPath("/ui/employee/function-tab-permission.fxml")
|
||||
public class FunctionTabSkinPermission
|
||||
extends
|
||||
AbstEntityTableTabSkin<FunctionWindowController, Function, FunctionViewModel, Permission, PermissionViewModel> {
|
||||
|
||||
@FXML
|
||||
public TableColumn<PermissionViewModel, Number> idColumn;
|
||||
@FXML
|
||||
public TableColumn<PermissionViewModel, String> nameColumn;
|
||||
@FXML
|
||||
public TableColumn<PermissionViewModel, String> keyColumn;
|
||||
@FXML
|
||||
public TableColumn<PermissionViewModel, String> descriptionColumn;
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
public FunctionTabSkinPermission(FunctionWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.permissionTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionService getViewModelService() {
|
||||
if (permissionService == null) {
|
||||
permissionService = getBean(PermissionService.class);
|
||||
}
|
||||
return permissionService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
keyColumn.setCellValueFactory(param -> param.getValue().getKey());
|
||||
// descriptionColumn.setCellValueFactory(param ->
|
||||
// param.getValue().getDescription());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<Permission> getSpecification(Function parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, criteriaBuilder) -> {
|
||||
return criteriaBuilder.equal(root.get("function"), parent);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.other.service.FunctionService;
|
||||
import com.ecep.contract.model.Function;
|
||||
import com.ecep.contract.vm.FunctionViewModel;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import lombok.Getter;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/employee/function.fxml")
|
||||
public class FunctionWindowController extends AbstEntityController<Function, FunctionViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(FunctionWindowController.class);
|
||||
|
||||
/**
|
||||
* 显示界面
|
||||
*/
|
||||
public static void show(FunctionViewModel viewModel, Window window) {
|
||||
show(FunctionWindowController.class, viewModel, window);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public BorderPane root;
|
||||
@FXML
|
||||
public TabPane tabPane;
|
||||
@FXML
|
||||
public Tab baseInfoTab;
|
||||
@FXML
|
||||
public Tab permissionTab;
|
||||
@FXML
|
||||
public TextField nameField;
|
||||
@FXML
|
||||
public TextField keyField;
|
||||
@FXML
|
||||
public TextField controllerField;
|
||||
@FXML
|
||||
public TextField iconField;
|
||||
@FXML
|
||||
public TextField descriptionField;
|
||||
@FXML
|
||||
public CheckBox activeField;
|
||||
@FXML
|
||||
public Label versionLabel;
|
||||
|
||||
public static void show(Function function, Window owner) {
|
||||
FunctionViewModel model = FunctionViewModel.from(function);
|
||||
show(model, owner);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@Getter
|
||||
FunctionService functionService;
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().bind(viewModel.getName().map(name -> "[" + viewModel.getId().get() + "] " + name + " 功能详情"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, tab -> new FunctionTabSkinBase(this));
|
||||
registerTabSkin(permissionTab, tab -> new FunctionTabSkinPermission(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionService getViewModelService() {
|
||||
return functionService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package com.ecep.contract.controller.permission;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.ManagerSkin;
|
||||
import com.ecep.contract.controller.table.TableTabSkin;
|
||||
import com.ecep.contract.model.Permission;
|
||||
import com.ecep.contract.vm.FunctionViewModel;
|
||||
import com.ecep.contract.vm.PermissionViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import lombok.Setter;
|
||||
|
||||
public class PermissionManagerSkin implements ManagerSkin, TableTabSkin<Permission, PermissionViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(PermissionManagerSkin.class);
|
||||
EmployeeFunctionsManagerWindowController controller;
|
||||
|
||||
@Setter
|
||||
private FunctionViewModel viewModel;
|
||||
@Setter
|
||||
protected TableView<PermissionViewModel> table;
|
||||
private final ObservableList<PermissionViewModel> dataSet = FXCollections.observableArrayList();
|
||||
|
||||
public PermissionManagerSkin(EmployeeFunctionsManagerWindowController controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(String message, Throwable ex) {
|
||||
if (controller != null) {
|
||||
controller.handleException(message, ex);
|
||||
return;
|
||||
}
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(message, ex);
|
||||
}
|
||||
UITools.showExceptionAndWait(message, ex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableView<PermissionViewModel> getTableView() {
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void install() {
|
||||
initializeTable();
|
||||
table.setItems(dataSet);
|
||||
loadTableDataSet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
table.setEditable(true);
|
||||
|
||||
// controller.permissionTable_descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
|
||||
// controller.permissionTable_descriptionColumn.setCellFactory(TextFieldTableCell.forTableColumn());
|
||||
// controller.permissionTable_descriptionColumn.setOnEditCommit(this::onSignMethodTableDescriptionColumnEditCommitAction);
|
||||
|
||||
table.setItems(dataSet);
|
||||
|
||||
if (table.contextMenuProperty().get() == null) {
|
||||
ContextMenu contextMenu = new ContextMenu();
|
||||
createContextMenu(contextMenu);
|
||||
table.setContextMenu(contextMenu);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
MenuItem item1 = new MenuItem("新建");
|
||||
item1.setOnAction(this::onTableCreateNewAction);
|
||||
|
||||
MenuItem item2 = new MenuItem("刷新");
|
||||
item2.setOnAction(this::onTableRefreshAction);
|
||||
|
||||
MenuItem item3 = new MenuItem("删除");
|
||||
item3.setOnAction(this::onTableDeleteAction);
|
||||
|
||||
contextMenu.getItems().addAll(item1, item2, item3);
|
||||
}
|
||||
|
||||
protected void onTableCreateNewAction(ActionEvent event) {
|
||||
Permission newRow = new Permission();
|
||||
com.ecep.contract.model.Function function = controller.functionService.findById(viewModel.getId().get());
|
||||
newRow.setFunction(function);
|
||||
|
||||
Permission saved = controller.permissionService.save(newRow);
|
||||
PermissionViewModel row = PermissionViewModel.from(saved);
|
||||
dataSet.add(row);
|
||||
}
|
||||
|
||||
protected void onTableRefreshAction(ActionEvent event) {
|
||||
loadTableDataSet();
|
||||
}
|
||||
|
||||
protected void onTableDeleteAction(ActionEvent event) {
|
||||
ObservableList<PermissionViewModel> selectedItems = table.getSelectionModel().getSelectedItems();
|
||||
if (selectedItems.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!UITools.showConfirmDialog("删除行", "确认删除选中的" + selectedItems.size() + "条数据?")) {
|
||||
return;
|
||||
}
|
||||
for (PermissionViewModel selectedItem : new ArrayList<>(selectedItems)) {
|
||||
if (deleteRow(selectedItem)) {
|
||||
dataSet.remove(selectedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean deleteRow(PermissionViewModel row) {
|
||||
throw new UnsupportedOperationException("未实现");
|
||||
}
|
||||
|
||||
private void onNameColumnEditCommitAction(TableColumn.CellEditEvent<PermissionViewModel, String> event) {
|
||||
acceptSignMethodCellEditEvent(event, PermissionViewModel::getName);
|
||||
}
|
||||
|
||||
private void onKeyColumnEditCommitAction(TableColumn.CellEditEvent<PermissionViewModel, String> event) {
|
||||
acceptSignMethodCellEditEvent(event, PermissionViewModel::getKey);
|
||||
}
|
||||
|
||||
protected List<PermissionViewModel> loadTableData() {
|
||||
if (viewModel == null) {
|
||||
return List.of();
|
||||
}
|
||||
return controller.permissionService.findByFunctionId(viewModel.getId().get()).stream().map(PermissionViewModel::from).toList();
|
||||
}
|
||||
|
||||
public void loadTableDataSet() {
|
||||
Platform.runLater(() -> {
|
||||
dataSet.clear();
|
||||
CompletableFuture.runAsync(() -> {
|
||||
List<PermissionViewModel> models = loadTableData();
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
dataSet.setAll(models);
|
||||
} catch (Exception e) {
|
||||
handleException(e);
|
||||
}
|
||||
});
|
||||
}).exceptionally(this::handleException);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<Permission> getSpecification() {
|
||||
|
||||
return controller.permissionService.getSpecification(null);
|
||||
}
|
||||
|
||||
private <K> void acceptSignMethodCellEditEvent(TableColumn.CellEditEvent<PermissionViewModel, K> event, Function<PermissionViewModel, Property<K>> function) {
|
||||
PermissionViewModel row = event.getRowValue();
|
||||
Property<K> property = function.apply(row);
|
||||
property.setValue(event.getNewValue());
|
||||
try {
|
||||
save(row);
|
||||
} catch (Exception e) {
|
||||
UITools.showExceptionAndWait("保存出错", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void save(PermissionViewModel row) {
|
||||
int id = row.getId().get();
|
||||
Permission type = controller.permissionService.findById(id);
|
||||
if (row.copyTo(type)) {
|
||||
Permission saved = controller.permissionService.save(type);
|
||||
row.update(saved);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.ds.project.service.ProjectService;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.vm.ProjectViewModel;
|
||||
|
||||
public abstract class AbstProjectBasedTabSkin
|
||||
extends AbstEntityBasedTabSkin<ProjectWindowController, Project, ProjectViewModel>
|
||||
implements TabSkin {
|
||||
|
||||
public AbstProjectBasedTabSkin(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
viewModel = controller.getViewModel();
|
||||
}
|
||||
|
||||
public ProjectService getProjectService() {
|
||||
return controller.projectService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.AbstEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.project.service.ProjectService;
|
||||
import com.ecep.contract.model.IdentityEntity;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.IdentityViewModel;
|
||||
import com.ecep.contract.vm.ProjectBasedViewModel;
|
||||
import com.ecep.contract.vm.ProjectViewModel;
|
||||
|
||||
public abstract class AbstProjectTableTabSkin<T extends IdentityEntity, TV extends IdentityViewModel<T>>
|
||||
extends AbstEntityTableTabSkin<ProjectWindowController, Project, ProjectViewModel, T, TV>
|
||||
implements TabSkin {
|
||||
|
||||
public AbstProjectTableTabSkin(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
public ProjectService getProjectService() {
|
||||
return controller.projectService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TV createNewViewModel() {
|
||||
TV model = super.createNewViewModel();
|
||||
if (model instanceof ProjectBasedViewModel m) {
|
||||
m.getProject().set(getEntity());
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Specification<T> getSpecification(Project parent) {
|
||||
return SpecificationUtils.and(getSpecification(), (root, query, builder) -> {
|
||||
return builder.equal(root.get("project"), parent);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.ds.project.service.ProjectService;
|
||||
import com.ecep.contract.ds.project.service.SaleTypeService;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectSaleType;
|
||||
import com.ecep.contract.vm.ProjectViewModel;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/project/apply-new-project.fxml")
|
||||
public class ApplyNewProjectWindowController extends BaseController {
|
||||
@Autowired
|
||||
private ProjectService projectService;
|
||||
@Autowired
|
||||
private SaleTypeService saleTypeService;
|
||||
@Autowired
|
||||
private EmployeeService employeeService;
|
||||
|
||||
|
||||
public ComboBox<ProjectSaleType> saleTypeComboBox;
|
||||
public TextField codeYearField;
|
||||
public Label codeYearLabel;
|
||||
|
||||
public TextField codeSequenceNumberField;
|
||||
public Label codeSequenceNumberLabel;
|
||||
|
||||
public Label codePreviewLabel;
|
||||
public Label codeLabel;
|
||||
|
||||
public Label applicantLabel;
|
||||
|
||||
public Button cancelBtn;
|
||||
public Button applyBtn;
|
||||
|
||||
|
||||
private ProjectViewModel viewModel = new ProjectViewModel();
|
||||
private ObjectProperty<Consumer<Project>> onApplied = new SimpleObjectProperty<>();
|
||||
|
||||
public void setOnApplied(Consumer<Project> onApplied) {
|
||||
this.onApplied.set(onApplied);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stage show(FXMLLoader loader, Window owner, Modality modality) {
|
||||
return super.show(loader, owner, Modality.APPLICATION_MODAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().set("申请新项目编号");
|
||||
|
||||
viewModel.getCodeYear().set(25);
|
||||
|
||||
initializeSaleTypeField(saleTypeComboBox);
|
||||
|
||||
|
||||
NumberStringConverter stringConverter = new NumberStringConverter();
|
||||
Bindings.bindBidirectional(codeYearField.textProperty(), viewModel.getCodeYear(), stringConverter);
|
||||
|
||||
Bindings.bindBidirectional(codeSequenceNumberField.textProperty(), viewModel.getCodeSequenceNumber(), stringConverter);
|
||||
initializeApplicantLabel(applicantLabel);
|
||||
initializeCodePreviewLabel(codePreviewLabel);
|
||||
|
||||
cancelBtn.setOnAction(event -> {
|
||||
cancelBtn.getScene().getWindow().hide();
|
||||
});
|
||||
|
||||
|
||||
applyBtn.disableProperty().bind(viewModel.getSaleType().isNull());
|
||||
applyBtn.setOnAction(event -> {
|
||||
Project newProject = new Project();
|
||||
newProject.setCodeYear(viewModel.getCodeYear().get());
|
||||
int codeSequenceNumber = viewModel.getCodeSequenceNumber().get();
|
||||
if (codeSequenceNumber == 0) {
|
||||
codeSequenceNumberLabel.setText("项目序号不能为0");
|
||||
codeSequenceNumberLabel.setStyle("-fx-text-fill: #ffa2a2");
|
||||
return;
|
||||
} else {
|
||||
codeSequenceNumberLabel.setText("");
|
||||
codeSequenceNumberLabel.setStyle("");
|
||||
}
|
||||
|
||||
|
||||
newProject.setCodeSequenceNumber(codeSequenceNumber);
|
||||
newProject.setSaleType(viewModel.getSaleType().get());
|
||||
|
||||
Project exist = projectService.findBySaleTypeAndCodeYearAndCodeSequenceNumber(newProject.getSaleType(), newProject.getCodeYear(), newProject.getCodeSequenceNumber());
|
||||
if (exist != null) {
|
||||
codeLabel.setText("项目编号已存在");
|
||||
codeLabel.setStyle("-fx-text-fill: #ffa2a2");
|
||||
return;
|
||||
} else {
|
||||
codeLabel.setText("");
|
||||
codeLabel.setStyle("");
|
||||
}
|
||||
|
||||
// 暂时的项目编号
|
||||
newProject.setCode(codePreviewLabel.getText());
|
||||
|
||||
newProject.setApplicant(viewModel.getApplicant().get());
|
||||
newProject.setCreated(LocalDate.now());
|
||||
Project saved = projectService.save(newProject);
|
||||
Consumer<Project> consumer = onApplied.get();
|
||||
if (consumer != null) {
|
||||
consumer.accept(saved);
|
||||
}
|
||||
applyBtn.getScene().getWindow().hide();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void initializeApplicantLabel(Label applicantLabel) {
|
||||
Employee operator = employeeService.findById(Desktop.instance.getActiveEmployeeId());
|
||||
viewModel.getApplicant().set(operator);
|
||||
|
||||
applicantLabel.textProperty().bind(Bindings.createObjectBinding(() -> {
|
||||
Employee employee = viewModel.getApplicant().get();
|
||||
if (employee == null) {
|
||||
return "- 异常,未取得当前操作员信息 -";
|
||||
}
|
||||
return employee.getName();
|
||||
|
||||
}, viewModel.getApplicant()));
|
||||
}
|
||||
|
||||
private void initializeCodePreviewLabel(Label codePreviewLabel) {
|
||||
codePreviewLabel.textProperty().bind(Bindings.createObjectBinding(() -> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ProjectSaleType saleType = viewModel.getSaleType().get();
|
||||
if (saleType == null) {
|
||||
return "";
|
||||
}
|
||||
sb.append(saleType.getCode());
|
||||
|
||||
|
||||
int year = viewModel.getCodeYear().get();
|
||||
if (year < 10) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(year);
|
||||
|
||||
int sn = viewModel.getCodeSequenceNumber().get();
|
||||
if (sn < 10) {
|
||||
sb.append("00");
|
||||
} else if (sn < 100) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(sn);
|
||||
return sb.toString();
|
||||
}, viewModel.getSaleType(), viewModel.getCodeYear(), viewModel.getCodeSequenceNumber()));
|
||||
}
|
||||
|
||||
private void initializeSaleTypeField(ComboBox<ProjectSaleType> field) {
|
||||
ObservableList<ProjectSaleType> list = FXCollections.observableArrayList();
|
||||
saleTypeService.findAll().stream().filter(ProjectSaleType::isActive).forEach(list::add);
|
||||
field.setItems(list);
|
||||
field.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
viewModel.getSaleType().set(newValue);
|
||||
// 当 SequenceNumber 为 0 时, 自动检索最新的 SequenceNumber
|
||||
if (viewModel.getCodeYear().get() != 0) {
|
||||
int nextCodeSequenceNumber = projectService.getNextCodeSequenceNumber(newValue, viewModel.getCodeYear().get());
|
||||
viewModel.getCodeSequenceNumber().set(nextCodeSequenceNumber);
|
||||
}
|
||||
});
|
||||
EntityStringConverter<ProjectSaleType> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(saleType -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getId(), saleType.getId())).findFirst().orElse(null);
|
||||
});
|
||||
converter.setFromString(name -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getName(), name)).findFirst().orElse(null);
|
||||
});
|
||||
field.setConverter(converter);
|
||||
field.valueProperty().bindBidirectional(viewModel.getSaleType());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import com.ecep.contract.controller.AbstEntityManagerSkin;
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.controller.ComboBoxUtils;
|
||||
import com.ecep.contract.controller.ManagerSkin;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.ds.project.service.ProductTypeService;
|
||||
import com.ecep.contract.ds.project.service.ProjectService;
|
||||
import com.ecep.contract.ds.project.service.ProjectTypeService;
|
||||
import com.ecep.contract.ds.project.service.SaleTypeService;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.ProductType;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectSaleType;
|
||||
import com.ecep.contract.model.ProjectType;
|
||||
import com.ecep.contract.ui.table.cell.CompanyTableCell;
|
||||
import com.ecep.contract.util.SpecificationUtils;
|
||||
import com.ecep.contract.vm.ProjectViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ProjectManagerSkin
|
||||
extends AbstEntityManagerSkin<Project, ProjectViewModel, ProjectManagerSkin, ProjectManagerWindowController>
|
||||
implements ManagerSkin {
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
@Setter
|
||||
private ProjectTypeService projectTypeService;
|
||||
@Setter
|
||||
private SaleTypeService saleTypeService;
|
||||
@Setter
|
||||
private ProductTypeService productTypeService;
|
||||
|
||||
|
||||
public ProjectManagerSkin(ProjectManagerWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
public ProjectService getProjectService() {
|
||||
return controller.getViewModelService();
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService(){
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
public SaleTypeService getSaleTypeService() {
|
||||
if (saleTypeService == null) {
|
||||
saleTypeService = getBean(SaleTypeService.class);
|
||||
}
|
||||
return saleTypeService;
|
||||
}
|
||||
|
||||
public ProjectTypeService getProjectTypeService() {
|
||||
if (projectTypeService == null) {
|
||||
projectTypeService = getBean(ProjectTypeService.class);
|
||||
}
|
||||
return projectTypeService;
|
||||
}
|
||||
|
||||
public ProductTypeService getProductTypeService() {
|
||||
if (productTypeService == null) {
|
||||
productTypeService = getBean(ProductTypeService.class);
|
||||
}
|
||||
return productTypeService;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Specification<Project> getSpecification() {
|
||||
Specification<Project> spec = super.getSpecification();
|
||||
if (controller.saleTypeSelector.getValue() != null) {
|
||||
spec = SpecificationUtils.and(spec, (root, query, builder) -> {
|
||||
return builder.equal(root.get("saleType"), controller.saleTypeSelector.getValue());
|
||||
});
|
||||
}
|
||||
return spec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
ComboBoxUtils.initialComboBox(controller.saleTypeSelector, getSaleTypeService().findAll(), true);
|
||||
controller.saleTypeSelector.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
loadTableDataSet(false);
|
||||
});
|
||||
|
||||
controller.idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
controller.codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
controller.nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
|
||||
controller.amountColumn.setCellValueFactory(param -> param.getValue().getAmount());
|
||||
controller.amountColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter(getLocale())));//, "#,##0"
|
||||
|
||||
initializeSaleTypeColumn(controller.saleTypeColumn);
|
||||
initializeCustomerColumn(controller.customerColumn);
|
||||
initializeProjectTypeColumn(controller.projectTypeColumn);
|
||||
initializeProductTypeColumn(controller.productTypeColumn);
|
||||
|
||||
controller.useBidColumn.setCellValueFactory(param -> param.getValue().getUseBid());
|
||||
controller.useBidColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.useBidColumn));
|
||||
controller.useOfferColumn.setCellValueFactory(param -> param.getValue().getUseOffer());
|
||||
controller.useOfferColumn.setCellFactory(CheckBoxTableCell.forTableColumn(controller.useOfferColumn));
|
||||
|
||||
|
||||
controller.createdColumn.setCellValueFactory(param -> param.getValue().getCreated());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
getTableView().getSortOrder().add(controller.idColumn);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void initializeCustomerColumn(TableColumn<ProjectViewModel, Company> column) {
|
||||
column.setCellValueFactory(param -> param.getValue().getCustomer());
|
||||
column.setCellFactory(param-> new CompanyTableCell<>(getCompanyService()));
|
||||
}
|
||||
|
||||
private void initializeProductTypeColumn(TableColumn<ProjectViewModel, String> column) {
|
||||
EntityStringConverter<ProductType> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(productType -> getProductTypeService().findById(productType.getId()));
|
||||
converter.setFromString(name -> getProductTypeService().findByName(name));
|
||||
column.setCellValueFactory(param -> param.getValue().getProductType().map(converter::toString));
|
||||
}
|
||||
|
||||
private void initializeProjectTypeColumn(TableColumn<ProjectViewModel, String> column) {
|
||||
EntityStringConverter<ProjectType> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(projectType -> getProjectTypeService().findById(projectType.getId()));
|
||||
converter.setFromString(name -> getProjectTypeService().findByName(name));
|
||||
column.setCellValueFactory(param -> param.getValue().getProjectType().map(converter::toString));
|
||||
}
|
||||
|
||||
private void initializeSaleTypeColumn(TableColumn<ProjectViewModel, String> column) {
|
||||
EntityStringConverter<ProjectSaleType> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(saleType -> getSaleTypeService().findById(saleType.getId()));
|
||||
converter.setFromString(name -> getSaleTypeService().findByName(name));
|
||||
column.setCellValueFactory(param -> param.getValue().getSaleType().map(converter::toString));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(ProjectViewModel item) {
|
||||
showInOwner(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableCreateNewAction(ActionEvent event) {
|
||||
BaseController.show(ApplyNewProjectWindowController.class, getTableView().getScene().getWindow(), controller -> {
|
||||
controller.setOnApplied(project -> {
|
||||
ProjectViewModel viewModel = ProjectViewModel.from(project);
|
||||
dataSet.addFirst(viewModel);
|
||||
showInOwner(viewModel);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void showInOwner(ProjectViewModel model) {
|
||||
showInOwner(ProjectWindowController.class, model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.controller.AbstManagerWindowController;
|
||||
import com.ecep.contract.controller.BaseController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.project.industry.ProjectIndustryManagerWindowController;
|
||||
import com.ecep.contract.controller.project.product_type.ProductTypeManagerWindowController;
|
||||
import com.ecep.contract.controller.project.project_type.ProjectTypeManagerWindowController;
|
||||
import com.ecep.contract.controller.project.sale_type.ProjectSaleTypeManagerWindowController;
|
||||
import com.ecep.contract.controller.project.usage.ProductUsageManagerWindowController;
|
||||
import com.ecep.contract.ds.project.service.ProjectService;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectSaleType;
|
||||
import com.ecep.contract.vm.ProjectViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.stage.WindowEvent;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/project/project-manager.fxml")
|
||||
public class ProjectManagerWindowController
|
||||
extends AbstManagerWindowController<Project, ProjectViewModel, ProjectManagerSkin> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProjectManagerWindowController.class);
|
||||
|
||||
public ComboBox<ProjectSaleType> saleTypeSelector;
|
||||
|
||||
public TableColumn<ProjectViewModel, Number> idColumn;
|
||||
public TableColumn<ProjectViewModel, String> codeColumn;
|
||||
public TableColumn<ProjectViewModel, String> nameColumn;
|
||||
public TableColumn<ProjectViewModel, String> saleTypeColumn;
|
||||
public TableColumn<ProjectViewModel, String> projectTypeColumn;
|
||||
public TableColumn<ProjectViewModel, String> productTypeColumn;
|
||||
public TableColumn<ProjectViewModel, LocalDate> createdColumn;
|
||||
public TableColumn<ProjectViewModel, Company> customerColumn;
|
||||
public TableColumn<ProjectViewModel, Boolean> useBidColumn;
|
||||
public TableColumn<ProjectViewModel, Boolean> useOfferColumn;
|
||||
public TableColumn<ProjectViewModel, Number> amountColumn;
|
||||
|
||||
@Autowired
|
||||
private ProjectService projectService;
|
||||
|
||||
@Override
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
getTitle().set("项目管理");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectService getViewModelService() {
|
||||
return projectService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectManagerSkin createDefaultSkin() {
|
||||
return new ProjectManagerSkin(this);
|
||||
}
|
||||
|
||||
public void onReBuildFilesAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
public void onBaseTableRefreshAction(ActionEvent event) {
|
||||
getSkin().loadTableDataSet(true);
|
||||
}
|
||||
|
||||
public void onCreateNewProjectAction(ActionEvent event) {
|
||||
getSkin().onTableCreateNewAction(event);
|
||||
}
|
||||
|
||||
public void onOpenProjectTypeManagerAction(ActionEvent event) {
|
||||
showInOwner(ProjectTypeManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onOpenSaleTypeManagerAction(ActionEvent event) {
|
||||
showInOwner(ProjectSaleTypeManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onOpenUsedIndustryManagerAction(ActionEvent event) {
|
||||
showInOwner(ProjectIndustryManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onOpenProductTypeManagerAction(ActionEvent event) {
|
||||
showInOwner(ProductTypeManagerWindowController.class);
|
||||
}
|
||||
|
||||
public void onOpenProductUsageManagerAction(ActionEvent event) {
|
||||
showInOwner(ProductUsageManagerWindowController.class);
|
||||
}
|
||||
|
||||
private <T extends BaseController> void showInOwner(Class<T> clz) {
|
||||
show(clz, table.getScene().getWindow());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.ComboBoxUtils;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.ds.project.service.DeliverySignMethodService;
|
||||
import com.ecep.contract.ds.project.service.ProductTypeService;
|
||||
import com.ecep.contract.ds.project.service.ProductUsageService;
|
||||
import com.ecep.contract.ds.project.service.ProjectCostService;
|
||||
import com.ecep.contract.ds.project.service.ProjectIndustryService;
|
||||
import com.ecep.contract.ds.project.service.ProjectTypeService;
|
||||
import com.ecep.contract.ds.project.service.SaleTypeService;
|
||||
import com.ecep.contract.model.DeliverySignMethod;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.ProductType;
|
||||
import com.ecep.contract.model.ProductUsage;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectCost;
|
||||
import com.ecep.contract.model.ProjectIndustry;
|
||||
import com.ecep.contract.model.ProjectSaleType;
|
||||
import com.ecep.contract.model.ProjectType;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 基础信息
|
||||
*/
|
||||
public class ProjectTabSkinBase extends AbstProjectBasedTabSkin implements TabSkin {
|
||||
@Setter
|
||||
EmployeeStringConverter employeeStringConverter;
|
||||
@Setter
|
||||
LocalDateStringConverter localDateStringConverter;
|
||||
@Setter
|
||||
EmployeeService employeeService;
|
||||
|
||||
@Setter
|
||||
private ProjectTypeService projectTypeService;
|
||||
@Setter
|
||||
private ProductTypeService productTypeService;
|
||||
@Setter
|
||||
private SaleTypeService saleTypeService;
|
||||
@Setter
|
||||
private ProductUsageService productUsageService;
|
||||
@Setter
|
||||
private ProjectIndustryService projectIndustryService;
|
||||
@Setter
|
||||
private DeliverySignMethodService deliverySignMethodService;
|
||||
|
||||
|
||||
public ProjectTabSkinBase(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
private EmployeeService getEmployeeService() {
|
||||
if (employeeService == null) {
|
||||
employeeService = getBean(EmployeeService.class);
|
||||
}
|
||||
return employeeService;
|
||||
}
|
||||
|
||||
private ProjectTypeService getProjectTypeService() {
|
||||
if (projectTypeService == null) {
|
||||
projectTypeService = getBean(ProjectTypeService.class);
|
||||
}
|
||||
return projectTypeService;
|
||||
}
|
||||
|
||||
private ProductTypeService getProductTypeService() {
|
||||
if (productTypeService == null) {
|
||||
productTypeService = getBean(ProductTypeService.class);
|
||||
}
|
||||
return productTypeService;
|
||||
}
|
||||
|
||||
private SaleTypeService getSaleTypeService() {
|
||||
if (saleTypeService == null) {
|
||||
saleTypeService = getBean(SaleTypeService.class);
|
||||
}
|
||||
return saleTypeService;
|
||||
}
|
||||
|
||||
private ProductUsageService getProductUsageService() {
|
||||
if (productUsageService == null) {
|
||||
productUsageService = getBean(ProductUsageService.class);
|
||||
}
|
||||
return productUsageService;
|
||||
}
|
||||
|
||||
private ProjectIndustryService getProjectIndustryService() {
|
||||
if (projectIndustryService == null) {
|
||||
projectIndustryService = getBean(ProjectIndustryService.class);
|
||||
}
|
||||
return projectIndustryService;
|
||||
}
|
||||
|
||||
private DeliverySignMethodService getDeliverySignMethodService() {
|
||||
if (deliverySignMethodService == null) {
|
||||
deliverySignMethodService = getBean(DeliverySignMethodService.class);
|
||||
}
|
||||
return deliverySignMethodService;
|
||||
}
|
||||
|
||||
private EmployeeStringConverter getEmployeeStringConverter() {
|
||||
if (employeeStringConverter == null) {
|
||||
employeeStringConverter = getBean(EmployeeStringConverter.class);
|
||||
}
|
||||
return employeeStringConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
controller.deleteBtn.setOnAction(this::onDeleteAction);
|
||||
controller.nameField.textProperty().bindBidirectional(viewModel.getName());
|
||||
controller.codeField.textProperty().bind(viewModel.getCode());
|
||||
NumberStringConverter stringConverter = new NumberStringConverter();
|
||||
Bindings.bindBidirectional(controller.codeYearField.textProperty(), viewModel.getCodeYear(), stringConverter);
|
||||
Bindings.bindBidirectional(controller.codeSequenceNumberField.textProperty(), viewModel.getCodeSequenceNumber(), stringConverter);
|
||||
|
||||
controller.addressField.textProperty().bindBidirectional(viewModel.getAddress());
|
||||
controller.useBidField.selectedProperty().bindBidirectional(viewModel.getUseBid());
|
||||
controller.useOfferField.selectedProperty().bindBidirectional(viewModel.getUseOffer());
|
||||
controller.standardPayWayField.selectedProperty().bindBidirectional(viewModel.getStandardPayWay());
|
||||
Bindings.bindBidirectional(controller.amountField.textProperty(), viewModel.getAmount(), new NumberStringConverter());
|
||||
|
||||
initializeSaleTypeField(controller.saleTypeField);
|
||||
initializeSaleIndustryField(controller.industryField);
|
||||
initializeProjectTypeField(controller.projectTypeField);
|
||||
initializeProductTypeField(controller.productTypeField);
|
||||
initializeDeliverySignMethodField(controller.saleTypeField, controller.deliverySignMethodField);
|
||||
initializeProductUsageField(controller.productUsageField);
|
||||
|
||||
controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());
|
||||
|
||||
employeeAutoCompletion(controller.applicantField, viewModel.getApplicant());
|
||||
employeeAutoCompletion(controller.authorizerField, viewModel.getAuthorizer());
|
||||
|
||||
controller.createdField.setConverter(localDateStringConverter);
|
||||
controller.createdField.valueProperty().bindBidirectional(viewModel.getCreated());
|
||||
controller.plannedStartTimeField.setConverter(localDateStringConverter);
|
||||
controller.plannedStartTimeField.valueProperty().bindBidirectional(viewModel.getPlannedStartTime());
|
||||
controller.plannedCompletionTimeField.setConverter(localDateStringConverter);
|
||||
controller.plannedCompletionTimeField.valueProperty().bindBidirectional(viewModel.getPlannedCompletionTime());
|
||||
|
||||
controller.versionLabel.textProperty().bind(viewModel.getVersion().asString());
|
||||
}
|
||||
|
||||
private void onDeleteAction(ActionEvent event) {
|
||||
ProjectCostService projectCostService = getBean(ProjectCostService.class);
|
||||
Project project = getEntity();
|
||||
for (ProjectCost cost : projectCostService.findAllByProject(project)) {
|
||||
projectCostService.delete(cost);
|
||||
}
|
||||
getProjectService().delete(project);
|
||||
controller.root.getScene().getWindow().hide();
|
||||
}
|
||||
|
||||
private void initializeSaleIndustryField(ComboBox<ProjectIndustry> field) {
|
||||
ComboBoxUtils.initialComboBox(field, viewModel.getIndustry(), getProjectIndustryService().findAll(), true);
|
||||
}
|
||||
|
||||
private void initializeProjectTypeField(ComboBox<ProjectType> field) {
|
||||
ComboBoxUtils.initialComboBox(field, viewModel.getProjectType(), getProjectTypeService().findAll(), true);
|
||||
}
|
||||
|
||||
private void initializeProductTypeField(ComboBox<ProductType> field) {
|
||||
ObservableList<ProductType> list = FXCollections.observableArrayList();
|
||||
list.add(null);
|
||||
list.addAll(getProductTypeService().findAll());
|
||||
field.setItems(list);
|
||||
field.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
viewModel.getProductType().set(newValue);
|
||||
});
|
||||
EntityStringConverter<ProductType> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(type -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getId(), type.getId())).findFirst().orElse(null);
|
||||
});
|
||||
converter.setFromString(name -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getName(), name)).findFirst().orElse(null);
|
||||
});
|
||||
field.setConverter(converter);
|
||||
field.valueProperty().bindBidirectional(viewModel.getProductType());
|
||||
}
|
||||
|
||||
private void initializeDeliverySignMethodField(
|
||||
ComboBox<ProjectSaleType> saleTypeField,
|
||||
ComboBox<DeliverySignMethod> field
|
||||
) {
|
||||
ObservableList<DeliverySignMethod> list = FXCollections.observableArrayList();
|
||||
list.add(null);
|
||||
list.addAll(getDeliverySignMethodService().findAll());
|
||||
field.setItems(list);
|
||||
|
||||
ProjectSaleType saleType = saleTypeField.getValue();
|
||||
if (saleType != null) {
|
||||
field.setItems(list.filtered(p -> {
|
||||
return p == null || Objects.equals(p.getSaleType(), saleType);
|
||||
}));
|
||||
}
|
||||
|
||||
saleTypeField.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue == null) {
|
||||
field.setItems(list);
|
||||
} else {
|
||||
field.setItems(list.filtered(p -> {
|
||||
return p == null || Objects.equals(p.getSaleType(), newValue);
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
field.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
viewModel.getDeliverySignMethod().set(newValue);
|
||||
});
|
||||
EntityStringConverter<DeliverySignMethod> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(signMethod -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getId(), signMethod.getId())).findFirst().orElse(null);
|
||||
});
|
||||
converter.setFromString(name -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getName(), name)).findFirst().orElse(null);
|
||||
});
|
||||
field.setConverter(converter);
|
||||
field.valueProperty().bindBidirectional(viewModel.getDeliverySignMethod());
|
||||
}
|
||||
|
||||
private void initializeProductUsageField(ComboBox<ProductUsage> field) {
|
||||
ObservableList<ProductUsage> list = FXCollections.observableArrayList();
|
||||
list.add(null);
|
||||
list.addAll(getProductUsageService().findAll());
|
||||
field.setItems(list);
|
||||
field.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
viewModel.getProductUsage().set(newValue);
|
||||
});
|
||||
EntityStringConverter<ProductUsage> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(usage -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getId(), usage.getId())).findFirst().orElse(null);
|
||||
});
|
||||
converter.setFromString(name -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getName(), name)).findFirst().orElse(null);
|
||||
});
|
||||
field.setConverter(converter);
|
||||
field.valueProperty().bindBidirectional(viewModel.getProductUsage());
|
||||
}
|
||||
|
||||
private void initializeSaleTypeField(ComboBox<ProjectSaleType> field) {
|
||||
ObservableList<ProjectSaleType> list = FXCollections.observableArrayList();
|
||||
list.add(null);
|
||||
list.addAll(getSaleTypeService().findAll());
|
||||
field.setItems(list);
|
||||
field.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||
viewModel.getSaleType().set(newValue);
|
||||
// 当 SequenceNumber 为 0 时, 自动检索最新的 SequenceNumber
|
||||
if (viewModel.getCodeSequenceNumber().get() == 0 && viewModel.getCodeYear().get() != 0) {
|
||||
int nextCodeSequenceNumber = getProjectService().getNextCodeSequenceNumber(newValue, viewModel.getCodeYear().get());
|
||||
viewModel.getCodeSequenceNumber().set(nextCodeSequenceNumber);
|
||||
}
|
||||
});
|
||||
field.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(ProjectSaleType item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText("-");
|
||||
setStyle("");
|
||||
} else {
|
||||
setText(item.getName());
|
||||
if (item.isActive()) {
|
||||
this.setStyle("");
|
||||
} else {
|
||||
this.setStyle("-fx-text-fill: grey;");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
EntityStringConverter<ProjectSaleType> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(saleType -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getId(), saleType.getId())).findFirst().orElse(null);
|
||||
});
|
||||
converter.setFromString(name -> {
|
||||
return list.stream().filter(v -> v != null && Objects.equals(v.getName(), name)).findFirst().orElse(null);
|
||||
});
|
||||
field.setConverter(converter);
|
||||
field.valueProperty().bindBidirectional(viewModel.getSaleType());
|
||||
|
||||
}
|
||||
|
||||
private void employeeAutoCompletion(TextField textField, SimpleObjectProperty<Employee> property) {
|
||||
UITools.autoCompletion(textField, property, getEmployeeStringConverter());
|
||||
}
|
||||
|
||||
public void save() {
|
||||
makeProjectCode();
|
||||
super.save();
|
||||
}
|
||||
|
||||
private void makeProjectCode() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
ProjectSaleType saleType = controller.saleTypeField.getValue();
|
||||
if (saleType == null) {
|
||||
sb.append("_");
|
||||
} else {
|
||||
controller.saleTypeField.getItems().stream()
|
||||
.filter(item -> item != null && item.getId().equals(saleType.getId()))
|
||||
.findFirst()
|
||||
.ifPresent(item -> sb.append(item.getCode()));
|
||||
}
|
||||
|
||||
|
||||
int year = 0;
|
||||
{
|
||||
String text = controller.codeYearField.getText();
|
||||
if (StringUtils.hasText(text)) {
|
||||
year = Integer.parseInt(text);
|
||||
}
|
||||
}
|
||||
if (year < 10) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(year);
|
||||
|
||||
int sn = 0;
|
||||
{
|
||||
String text = controller.codeSequenceNumberField.getText();
|
||||
if (StringUtils.hasText(text)) {
|
||||
sn = Integer.parseInt(text);
|
||||
}
|
||||
}
|
||||
if (sn < 10) {
|
||||
sb.append("00");
|
||||
} else if (sn < 100) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(sn);
|
||||
|
||||
DeliverySignMethod signMethod = controller.deliverySignMethodField.getValue();
|
||||
ProductType productType = controller.productTypeField.getValue();
|
||||
ProjectType projectType = controller.projectTypeField.getValue();
|
||||
ProjectIndustry industry = controller.industryField.getValue();
|
||||
ProductUsage productUsage = controller.productUsageField.getValue();
|
||||
|
||||
|
||||
if (!Stream.of(signMethod, productType, projectType, industry, productUsage)
|
||||
.allMatch(Objects::isNull)) {
|
||||
if (signMethod == null) {
|
||||
sb.append("_");
|
||||
} else {
|
||||
controller.deliverySignMethodField.getItems().stream()
|
||||
.filter(item -> item != null && item.getId().equals(signMethod.getId()))
|
||||
.findFirst()
|
||||
.ifPresent(item -> sb.append(item.getCode()));
|
||||
}
|
||||
|
||||
if (productType == null) {
|
||||
sb.append("_");
|
||||
} else {
|
||||
controller.productTypeField.getItems().stream()
|
||||
.filter(item -> item != null && item.getId().equals(productType.getId()))
|
||||
.findFirst()
|
||||
.ifPresent(item -> sb.append(item.getCode()));
|
||||
}
|
||||
|
||||
|
||||
if (projectType == null) {
|
||||
sb.append("_");
|
||||
} else {
|
||||
controller.projectTypeField.getItems().stream()
|
||||
.filter(item -> item != null && item.getId().equals(projectType.getId()))
|
||||
.findFirst()
|
||||
.ifPresent(item -> sb.append(item.getCode()));
|
||||
}
|
||||
|
||||
|
||||
if (industry != null) {
|
||||
controller.industryField.getItems().stream()
|
||||
.filter(item -> item != null && item.getId().equals(industry.getId()))
|
||||
.findFirst()
|
||||
.ifPresent(item -> sb.append(item.getCode()));
|
||||
} else {
|
||||
sb.append("_");
|
||||
}
|
||||
|
||||
|
||||
if (productUsage != null) {
|
||||
controller.productUsageField.getItems().stream()
|
||||
.filter(item -> item != null && item.getId().equals(productUsage.getId()))
|
||||
.findFirst()
|
||||
.ifPresent(item -> sb.append(item.getCode()));
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.getCode().set(sb.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.project.bid.ProjectBidWindowController;
|
||||
import com.ecep.contract.controller.tab.RefreshableSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
|
||||
import com.ecep.contract.ds.project.service.ProjectBidService;
|
||||
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectBid;
|
||||
import com.ecep.contract.service.CompanyStringConverter;
|
||||
import com.ecep.contract.ui.table.cell.EmployeeTableCell;
|
||||
import com.ecep.contract.vm.ProjectBidViewModel;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/project/project-tab-bid.fxml")
|
||||
public class ProjectTabSkinBid
|
||||
extends AbstProjectTableTabSkin<ProjectBid, ProjectBidViewModel>
|
||||
implements TabSkin, EditableEntityTableTabSkin<ProjectBid, ProjectBidViewModel>, RefreshableSkin {
|
||||
|
||||
public TableColumn<ProjectBidViewModel, Number> idColumn;
|
||||
public TableColumn<ProjectBidViewModel, Number> versionColumn;
|
||||
public TableColumn<ProjectBidViewModel, CompanyCustomerEvaluationFormFile> evaluationFileColumn;
|
||||
|
||||
public TableColumn<ProjectBidViewModel, String> descriptionColumn;
|
||||
public TableColumn<ProjectBidViewModel, Employee> applicantColumn;
|
||||
public TableColumn<ProjectBidViewModel, LocalDateTime> applyTimeColumn;
|
||||
public TableColumn<ProjectBidViewModel, Employee> authorizerColumn;
|
||||
public TableColumn<ProjectBidViewModel, LocalDateTime> authorizationTimeColumn;
|
||||
public TableColumn<ProjectBidViewModel, Number> levelColumn;
|
||||
public TableColumn<ProjectBidViewModel, String> standardPayWayColumn;
|
||||
public TableColumn<ProjectBidViewModel, Number> amountColumn;
|
||||
|
||||
@Setter
|
||||
private ProjectBidService projectBidService;
|
||||
@Setter
|
||||
private LocalDateStringConverter localDateStringConverter;
|
||||
@Setter
|
||||
private EmployeeStringConverter employeeStringConverter;
|
||||
@Setter
|
||||
private CompanyStringConverter companyStringConverter;
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
@Setter
|
||||
private CompanyCustomerService customerService;
|
||||
@Setter
|
||||
private CompanyCustomerFileService customerFileService;
|
||||
|
||||
|
||||
public ProjectTabSkinBid(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectBidService getViewModelService() {
|
||||
return getProjectBidService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.bidTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
bindNumberColumn(idColumn, ProjectBidViewModel::getId);
|
||||
|
||||
// levelColumn.setCellValueFactory(param -> param.getValue().getLevel());
|
||||
// levelColumn.setCellFactory(param -> new LevelTableCell());
|
||||
// standardPayWayColumn.setCellValueFactory(param -> param.getValue().getStandardPayWay().map(value -> value == null ? "" : (value ? "标准" : "非标准")));
|
||||
// evaluationFileColumn.setCellValueFactory(param -> param.getValue().getEvaluationFile());
|
||||
// evaluationFileColumn.setCellFactory(param -> new EvaluationFileTableCell());
|
||||
|
||||
|
||||
// amountColumn.setCellValueFactory(param -> param.getValue().getAmount());
|
||||
// amountColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter(getLocale())));
|
||||
|
||||
applicantColumn.setCellValueFactory(param -> param.getValue().getApplicant());
|
||||
applicantColumn.setCellFactory(cell -> new EmployeeTableCell<>(getEmployeeService()));
|
||||
bindLocalDateTimeColumn(applyTimeColumn, ProjectBidViewModel::getApplyTime);
|
||||
authorizerColumn.setCellValueFactory(param -> param.getValue().getAuthorizer());
|
||||
authorizerColumn.setCellFactory(cell -> new EmployeeTableCell<>(getEmployeeService()));
|
||||
bindLocalDateTimeColumn(authorizationTimeColumn, ProjectBidViewModel::getAuthorizationTime);
|
||||
|
||||
bindColumn(descriptionColumn, ProjectBidViewModel::getDescription);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectBidViewModel createNewViewModel() {
|
||||
ProjectBidViewModel model = new ProjectBidViewModel();
|
||||
Project project = getParent();
|
||||
model.getProject().set(project);
|
||||
model.getApplicant().set(project.getApplicant());
|
||||
if (project.getAmount() != null) {
|
||||
model.getAmount().set(project.getAmount());
|
||||
}
|
||||
|
||||
LocalDate created = project.getCreated();
|
||||
if (created == null) {
|
||||
created = LocalDate.now();
|
||||
}
|
||||
model.getApplyTime().set(LocalDateTime.of(created, LocalTime.now()));
|
||||
saveRow(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(ProjectBidViewModel item) {
|
||||
showInOwner(ProjectBidWindowController.class, item);
|
||||
}
|
||||
|
||||
private ProjectBidService getProjectBidService() {
|
||||
if (projectBidService == null) {
|
||||
projectBidService = getBean(ProjectBidService.class);
|
||||
}
|
||||
return projectBidService;
|
||||
}
|
||||
|
||||
private LocalDateStringConverter getLocalDateStringConverter() {
|
||||
if (localDateStringConverter == null) {
|
||||
localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
}
|
||||
return localDateStringConverter;
|
||||
}
|
||||
|
||||
private EmployeeStringConverter getEmployeeStringConverter() {
|
||||
if (employeeStringConverter == null) {
|
||||
employeeStringConverter = getBean(EmployeeStringConverter.class);
|
||||
}
|
||||
return employeeStringConverter;
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
private CompanyStringConverter getCompanyStringConverter() {
|
||||
if (companyStringConverter == null) {
|
||||
companyStringConverter = getBean(CompanyStringConverter.class);
|
||||
}
|
||||
return companyStringConverter;
|
||||
}
|
||||
|
||||
private CompanyCustomerService getCompanyCustomerService() {
|
||||
if (customerService == null) {
|
||||
customerService = getBean(CompanyCustomerService.class);
|
||||
}
|
||||
return customerService;
|
||||
}
|
||||
|
||||
private CompanyCustomerFileService getCompanyCustomerFileService() {
|
||||
if (customerFileService == null) {
|
||||
customerFileService = getBean(CompanyCustomerFileService.class);
|
||||
}
|
||||
return customerFileService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRowData(ProjectBid entity) {
|
||||
getProjectBidService().delete(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectBid loadRowData(ProjectBidViewModel row) {
|
||||
return getProjectBidService().findById(row.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectBid saveRowData(ProjectBid entity) {
|
||||
return getProjectBidService().save(entity);
|
||||
}
|
||||
|
||||
|
||||
private static class LevelTableCell extends TableCell<ProjectBidViewModel, Number> {
|
||||
@Override
|
||||
protected void updateItem(Number item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
return;
|
||||
}
|
||||
// 较差,一般,良好
|
||||
int value = item.intValue();
|
||||
if (value < 0) {
|
||||
setText("-");
|
||||
return;
|
||||
}
|
||||
if (value < 1) {
|
||||
setText("较差");
|
||||
return;
|
||||
}
|
||||
if (value < 2) {
|
||||
setText("一般");
|
||||
return;
|
||||
}
|
||||
if (value < 3) {
|
||||
setText("良好");
|
||||
return;
|
||||
}
|
||||
setText(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.project.ContractWindowController;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.vm.ContractViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
|
||||
@FxmlPath("/ui/project/project-tab-contract.fxml")
|
||||
public class ProjectTabSkinContract
|
||||
extends AbstProjectTableTabSkin<Contract, ContractViewModel>
|
||||
implements TabSkin {
|
||||
public TableColumn<ContractViewModel, Number> idColumn;
|
||||
public TableColumn<ContractViewModel, String> codeColumn;
|
||||
public TableColumn<ContractViewModel, String> nameColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> setupDateColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> inureDateColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> orderDateColumn;
|
||||
public TableColumn<ContractViewModel, LocalDate> varyDateColumn;
|
||||
public MenuItem contractTable_menu_refresh;
|
||||
|
||||
public ProjectTabSkinContract(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContractService getViewModelService() {
|
||||
return getContractService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.contractTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
|
||||
bindNumberColumn(idColumn, ContractViewModel::getId);
|
||||
codeColumn.setCellValueFactory(param -> param.getValue().getCode());
|
||||
nameColumn.setCellValueFactory(param -> param.getValue().getName());
|
||||
|
||||
bindLocalDateColumn(setupDateColumn, ContractViewModel::getSetupDate);
|
||||
bindLocalDateColumn(inureDateColumn, ContractViewModel::getInureDate);
|
||||
bindLocalDateColumn(orderDateColumn, ContractViewModel::getOrderDate);
|
||||
bindLocalDateColumn(varyDateColumn, ContractViewModel::getVaryDate);
|
||||
|
||||
Platform.runLater(() -> {
|
||||
getTableView().getSortOrder().add(setupDateColumn);
|
||||
});
|
||||
|
||||
contractTable_menu_refresh.setOnAction(this::onTableRefreshAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(ContractViewModel item) {
|
||||
ContractWindowController.show(item, controller.root.getScene().getWindow());
|
||||
}
|
||||
|
||||
private ContractService getContractService() {
|
||||
return controller.contractService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.project.cost.ProjectCostWindowController;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.ds.contract.service.ContractItemService;
|
||||
import com.ecep.contract.ds.project.service.ProjectCostItemService;
|
||||
import com.ecep.contract.ds.project.service.ProjectCostService;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectCost;
|
||||
import com.ecep.contract.model.ProjectCostItem;
|
||||
import com.ecep.contract.ui.table.cell.EmployeeTableCell;
|
||||
import com.ecep.contract.ui.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.vm.ProjectCostItemViewModel;
|
||||
import com.ecep.contract.vm.ProjectCostViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/project/project-tab-cost.fxml")
|
||||
public class ProjectTabSkinCost
|
||||
extends AbstProjectTableTabSkin<ProjectCost, ProjectCostViewModel>
|
||||
implements TabSkin {
|
||||
|
||||
public TableColumn<ProjectCostViewModel, Number> idColumn;
|
||||
public TableColumn<ProjectCostViewModel, Employee> applicantColumn;
|
||||
public TableColumn<ProjectCostViewModel, LocalDateTime> applyTimeColumn;
|
||||
public TableColumn<ProjectCostViewModel, Employee> authorizerColumn;
|
||||
public TableColumn<ProjectCostViewModel, LocalDateTime> authorizationTimeColumn;
|
||||
|
||||
public TableColumn<ProjectCostViewModel, Number> grossProfitMarginColumn;
|
||||
public TableColumn<ProjectCostViewModel, Number> inTaxAmountColumn;
|
||||
public TableColumn<ProjectCostViewModel, Number> inExclusiveTaxAmountColumn;
|
||||
public TableColumn<ProjectCostViewModel, Number> outTaxAmountColumn;
|
||||
public TableColumn<ProjectCostViewModel, Number> outExclusiveTaxAmountColumn;
|
||||
public TableColumn<ProjectCostViewModel, Number> versionColumn;
|
||||
|
||||
public TableColumn<ProjectCostViewModel, String> descriptionColumn;
|
||||
|
||||
@Setter
|
||||
private ProjectCostService costService;
|
||||
@Setter
|
||||
private ProjectCostItemService costItemService;
|
||||
@Setter
|
||||
private ContractItemService contractItemService;
|
||||
|
||||
public ProjectTabSkinCost(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectCostService getViewModelService() {
|
||||
return getCostService();
|
||||
}
|
||||
|
||||
private ProjectCostService getCostService() {
|
||||
if (costService == null) {
|
||||
costService = getBean(ProjectCostService.class);
|
||||
}
|
||||
return costService;
|
||||
}
|
||||
|
||||
private ProjectCostItemService getCostItemService() {
|
||||
if (costItemService == null) {
|
||||
costItemService = getBean(ProjectCostItemService.class);
|
||||
}
|
||||
return costItemService;
|
||||
}
|
||||
|
||||
private ContractItemService getContractItemService() {
|
||||
if (contractItemService == null) {
|
||||
contractItemService = getBean(ContractItemService.class);
|
||||
}
|
||||
return contractItemService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.costTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
idColumn.setCellValueFactory(param -> param.getValue().getId());
|
||||
|
||||
applicantColumn.setCellValueFactory(param -> param.getValue().getApplicant());
|
||||
applicantColumn.setCellFactory(cell -> new EmployeeTableCell<>());
|
||||
applyTimeColumn.setCellValueFactory(param -> param.getValue().getApplyTime());
|
||||
applyTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
authorizerColumn.setCellValueFactory(param -> param.getValue().getAuthorizer());
|
||||
authorizerColumn.setCellFactory(cell -> new EmployeeTableCell<>());
|
||||
authorizationTimeColumn.setCellValueFactory(param -> param.getValue().getAuthorizationTime());
|
||||
authorizationTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
inTaxAmountColumn.setCellValueFactory(param -> param.getValue().getInTaxAmount());
|
||||
inTaxAmountColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter(getLocale())));
|
||||
inExclusiveTaxAmountColumn.setCellValueFactory(param -> param.getValue().getInExclusiveTaxAmount());
|
||||
inExclusiveTaxAmountColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter(getLocale())));
|
||||
outTaxAmountColumn.setCellValueFactory(param -> param.getValue().getOutTaxAmount());
|
||||
outTaxAmountColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter(getLocale())));
|
||||
outExclusiveTaxAmountColumn.setCellValueFactory(param -> param.getValue().getOutExclusiveTaxAmount());
|
||||
outExclusiveTaxAmountColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter(getLocale())));
|
||||
|
||||
grossProfitMarginColumn.setCellValueFactory(param -> param.getValue().getGrossProfitMargin());
|
||||
NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
|
||||
numberInstance.setMaximumFractionDigits(2);
|
||||
numberInstance.setMinimumFractionDigits(2);
|
||||
grossProfitMarginColumn.setCellFactory(TextFieldTableCell.forTableColumn(new NumberStringConverter(numberInstance)));
|
||||
|
||||
versionColumn.setCellValueFactory(param -> param.getValue().getVersion());
|
||||
descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
|
||||
|
||||
Platform.runLater(() -> {
|
||||
table.getSortOrder().add(versionColumn);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ProjectCostViewModel createNewViewModel() {
|
||||
ProjectCostViewModel model = new ProjectCostViewModel();
|
||||
Project project = getParent();
|
||||
model.getProject().set(project);
|
||||
ProjectCost latest = getCostService().findLatestByProject(project);
|
||||
if (latest != null) {
|
||||
model.getVersion().set(latest.getVersion() + 1);
|
||||
} else {
|
||||
model.getVersion().set(1);
|
||||
}
|
||||
model.getStampTax().set(0.03f);
|
||||
model.getTaxAndSurcharges().set(11);
|
||||
model.getApplicant().set(project.getApplicant());
|
||||
model.getApplyTime().set(LocalDateTime.now());
|
||||
saveRow(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(ProjectCostViewModel item) {
|
||||
showInOwner(ProjectCostWindowController.class, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createContextMenu(ContextMenu contextMenu) {
|
||||
super.createContextMenu(contextMenu);
|
||||
|
||||
MenuItem menuItem = new MenuItem("复制");
|
||||
menuItem.setOnAction(this::onTableCopyAction);
|
||||
menuItem.visibleProperty().bind(table.getSelectionModel().selectedItemProperty().isNotNull());
|
||||
contextMenu.getItems().add(menuItem);
|
||||
}
|
||||
|
||||
private void onTableCopyAction(ActionEvent event) {
|
||||
ProjectCostViewModel selectedItem = table.getSelectionModel().getSelectedItem();
|
||||
|
||||
ProjectCost selectedCost = loadRowData(selectedItem);
|
||||
ProjectCost projectCost = new ProjectCost();
|
||||
selectedItem.copyTo(projectCost);
|
||||
projectCost.setId(null);
|
||||
projectCost.setVersion(selectedItem.getVersion().get() + 1);
|
||||
projectCost.setApplyTime(LocalDateTime.now());
|
||||
projectCost = saveRowData(projectCost);
|
||||
|
||||
|
||||
ProjectCostItemService costItemService = getCostItemService();
|
||||
for (ProjectCostItem selectedCostItem : costItemService.findByCost(selectedCost)) {
|
||||
ProjectCostItem item = new ProjectCostItem();
|
||||
ProjectCostItemViewModel.from(selectedCostItem).copyTo(item);
|
||||
item.setId(null);
|
||||
item.setCost(projectCost);
|
||||
costItemService.save(item);
|
||||
}
|
||||
|
||||
ProjectCostViewModel model = new ProjectCostViewModel();
|
||||
|
||||
model.update(projectCost);
|
||||
dataSet.add(model);
|
||||
saveRow(model);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.controlsfx.control.textfield.AutoCompletionBinding;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.company.CompanyWindowController;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.company.service.CompanyBankAccountService;
|
||||
import com.ecep.contract.ds.company.service.CompanyContactService;
|
||||
import com.ecep.contract.ds.company.service.CompanyInvoiceInfoService;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.ds.other.service.BankService;
|
||||
import com.ecep.contract.model.Bank;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.CompanyBankAccount;
|
||||
import com.ecep.contract.model.CompanyContact;
|
||||
import com.ecep.contract.model.CompanyInvoiceInfo;
|
||||
import com.ecep.contract.service.CompanyStringConverter;
|
||||
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
@FxmlPath("/ui/project/project-tab-customer.fxml")
|
||||
public class ProjectTabSkinCustomerInfo
|
||||
extends AbstProjectBasedTabSkin
|
||||
implements TabSkin {
|
||||
@FXML
|
||||
public TextField companyField;
|
||||
@FXML
|
||||
public Button companyDetailBtn;
|
||||
@FXML
|
||||
public Label companyLabel;
|
||||
@FXML
|
||||
public TextField bankAccountField;
|
||||
@FXML
|
||||
public Label bankAccountLabel;
|
||||
@FXML
|
||||
public TextField invoiceInfoField;
|
||||
@FXML
|
||||
public Label invoiceInfoLabel;
|
||||
@FXML
|
||||
public TextField mainContactField;
|
||||
@FXML
|
||||
public Label mainContactLabel;
|
||||
@FXML
|
||||
public TextField subContactField;
|
||||
@FXML
|
||||
public Label subContactLabel;
|
||||
|
||||
private CompanyService companyService;
|
||||
private BankService bankService;
|
||||
private CompanyInvoiceInfoService invoiceInfoService;
|
||||
private CompanyBankAccountService bankAccountService;
|
||||
private CompanyContactService contactService;
|
||||
|
||||
|
||||
public ProjectTabSkinCustomerInfo(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.companyTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
initCompanyField();
|
||||
initBankAccountField();
|
||||
initInvoiceInfoField();
|
||||
initMainContactField();
|
||||
initSubContactField();
|
||||
}
|
||||
|
||||
|
||||
private void initCompanyField() {
|
||||
companyAutoCompletion(companyField, companyLabel, viewModel.getCustomer()).setOnAutoCompleted(event -> {
|
||||
Company company = event.getCompletion();
|
||||
viewModel.getCustomer().set(company);
|
||||
|
||||
//
|
||||
// updateAbsent(company.getUniscid(), companyTaxCodeField.textProperty());
|
||||
// updateAbsent(company.getTelephone(), companyTelField.textProperty());
|
||||
//
|
||||
// updateAbsent(
|
||||
// // 优先使用通讯地址
|
||||
// StringUtils.hasText(company.getAddress()) ? company.getAddress() : company.getRegAddr(),
|
||||
// companyAddressField.textProperty());
|
||||
|
||||
// viewModel.getInvoiceInfo();
|
||||
|
||||
|
||||
});
|
||||
|
||||
companyDetailBtn.setOnAction(event -> {
|
||||
Company company = viewModel.getCustomer().get();
|
||||
if (company == null) {
|
||||
return;
|
||||
}
|
||||
CompanyWindowController.show(company, controller.root.getScene().getWindow());
|
||||
});
|
||||
}
|
||||
|
||||
private void initBankAccountField() {
|
||||
bankAccountAutoCompletion(bankAccountField, bankAccountLabel, viewModel.getBankAccount()).setOnAutoCompleted(event -> {
|
||||
CompanyBankAccount account = event.getCompletion();
|
||||
viewModel.getBankAccount().set(account);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void initInvoiceInfoField() {
|
||||
invoiceInfoAutoCompletion(invoiceInfoField, invoiceInfoLabel, viewModel.getInvoiceInfo()).setOnAutoCompleted(event -> {
|
||||
CompanyInvoiceInfo invoiceInfo = event.getCompletion();
|
||||
viewModel.getInvoiceInfo().set(invoiceInfo);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void initMainContactField() {
|
||||
contactAutoCompletion(mainContactField, mainContactLabel, viewModel.getMainContact()).setOnAutoCompleted(event -> {
|
||||
CompanyContact contact = event.getCompletion();
|
||||
viewModel.getMainContact().set(contact);
|
||||
});
|
||||
}
|
||||
|
||||
private void initSubContactField() {
|
||||
contactAutoCompletion(subContactField, subContactLabel, viewModel.getSubContact()).setOnAutoCompleted(event -> {
|
||||
CompanyContact contact = event.getCompletion();
|
||||
viewModel.getSubContact().set(contact);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 property 未为空时
|
||||
*
|
||||
* @param value 要设置的值
|
||||
* @param property 要设置的 property
|
||||
*/
|
||||
private void updateAbsent(String value, StringProperty property) {
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.hasText(property.get())) {
|
||||
return;
|
||||
}
|
||||
property.set(value);
|
||||
}
|
||||
|
||||
private AutoCompletionBinding<Company> companyAutoCompletion(TextField textField, Label label, SimpleObjectProperty<Company> property) {
|
||||
CompanyStringConverter converter = SpringApp.getBean(CompanyStringConverter.class);
|
||||
|
||||
label.textProperty().bind(property.map(company -> {
|
||||
if (company == null) {
|
||||
return "未选择";
|
||||
}
|
||||
|
||||
if (!Hibernate.isInitialized(company)) {
|
||||
company = getCompanyService().findById(company.getId());
|
||||
property.set(company);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("经营状态:");
|
||||
sb.append(company.getEntStatus());
|
||||
sb.append("\n");
|
||||
|
||||
sb.append("统一社会信用代码:");
|
||||
sb.append(company.getUniscid());
|
||||
sb.append("\n");
|
||||
|
||||
sb.append("注册电话:");
|
||||
sb.append(company.getTelephone());
|
||||
sb.append("\n");
|
||||
|
||||
sb.append("注册地址:");
|
||||
sb.append(company.getRegAddr());
|
||||
return sb.toString();
|
||||
}));
|
||||
|
||||
return UITools.autoCompletion(textField, property, converter::suggest, converter);
|
||||
}
|
||||
|
||||
private AutoCompletionBinding<CompanyBankAccount> bankAccountAutoCompletion(TextField textField, Label label, SimpleObjectProperty<CompanyBankAccount> property) {
|
||||
EntityStringConverter<CompanyBankAccount> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(account -> getBankAccountService().findById(account.getId()));
|
||||
|
||||
label.textProperty().bind(property.map(account -> {
|
||||
if (account == null) {
|
||||
return "未选择";
|
||||
}
|
||||
if (!Hibernate.isInitialized(account)) {
|
||||
account = getBankAccountService().findById(account.getId());
|
||||
property.set(account);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("开户行:");
|
||||
Bank bank = account.getBank();
|
||||
if (bank != null) {
|
||||
if (!Hibernate.isInitialized(bank)) {
|
||||
bank = getBankService().findById(bank.getId());
|
||||
account.setBank(bank);
|
||||
}
|
||||
sb.append(bank.toPrettyString());
|
||||
sb.append(" ");
|
||||
}
|
||||
sb.append(account.getOpeningBank());
|
||||
sb.append("\n");
|
||||
|
||||
sb.append("开户账号:");
|
||||
sb.append(account.getAccount());
|
||||
return sb.toString();
|
||||
}));
|
||||
return autoCompletion(textField, property, getBankAccountService()::searchByCompany, converter);
|
||||
}
|
||||
|
||||
private AutoCompletionBinding<CompanyInvoiceInfo> invoiceInfoAutoCompletion(TextField textField, Label label, SimpleObjectProperty<CompanyInvoiceInfo> property) {
|
||||
EntityStringConverter<CompanyInvoiceInfo> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(info -> getInvoiceInfoService().findById(info.getId()));
|
||||
|
||||
label.textProperty().bind(property.map(info -> {
|
||||
if (info == null) {
|
||||
return "未选择";
|
||||
}
|
||||
if (!Hibernate.isInitialized(info)) {
|
||||
info = getInvoiceInfoService().findById(info.getId());
|
||||
property.set(info);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("发票抬头:");
|
||||
sb.append(info.getName());
|
||||
sb.append("\n");
|
||||
|
||||
sb.append("纳税人识别号:");
|
||||
sb.append(info.getTaxId());
|
||||
sb.append("\n");
|
||||
|
||||
sb.append("地址:");
|
||||
sb.append(info.getAddress());
|
||||
sb.append("\n");
|
||||
|
||||
sb.append("电话:");
|
||||
sb.append(info.getPhone());
|
||||
return sb.toString();
|
||||
}));
|
||||
return autoCompletion(textField, property, getInvoiceInfoService()::searchByCompany, converter);
|
||||
}
|
||||
|
||||
private AutoCompletionBinding<CompanyContact> contactAutoCompletion(TextField textField, Label label, SimpleObjectProperty<CompanyContact> property) {
|
||||
EntityStringConverter<CompanyContact> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(contact -> getContactService().findById(contact.getId()));
|
||||
|
||||
label.textProperty().bind(property.map(contact -> {
|
||||
if (contact == null) {
|
||||
return "未选择";
|
||||
}
|
||||
if (!Hibernate.isInitialized(contact)) {
|
||||
contact = getContactService().findById(contact.getId());
|
||||
property.set(contact);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("联系人:");
|
||||
sb.append(contact.getName());
|
||||
|
||||
sb.append("\n");
|
||||
sb.append("职位:");
|
||||
sb.append(contact.getPosition());
|
||||
|
||||
sb.append("\n");
|
||||
sb.append("电话:");
|
||||
sb.append(contact.getPhone());
|
||||
|
||||
sb.append("\n");
|
||||
sb.append("邮箱:");
|
||||
sb.append(contact.getEmail());
|
||||
|
||||
return sb.toString();
|
||||
}));
|
||||
return autoCompletion(textField, property, getContactService()::searchByCompany, converter);
|
||||
}
|
||||
|
||||
public <T> AutoCompletionBinding<T> autoCompletion(
|
||||
TextField textField,
|
||||
SimpleObjectProperty<T> property,
|
||||
BiFunction<Company, String, List<T>> func,
|
||||
StringConverter<T> converter
|
||||
) {
|
||||
return UITools.autoCompletion(textField, property, text -> {
|
||||
Company company = viewModel.getCustomer().get();
|
||||
if (company == null) {
|
||||
return null;
|
||||
}
|
||||
return func.apply(company, text.getUserText());
|
||||
}, converter);
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
public BankService getBankService() {
|
||||
if (bankService == null) {
|
||||
bankService = getBean(BankService.class);
|
||||
}
|
||||
return bankService;
|
||||
}
|
||||
|
||||
public CompanyInvoiceInfoService getInvoiceInfoService() {
|
||||
if (invoiceInfoService == null) {
|
||||
invoiceInfoService = getBean(CompanyInvoiceInfoService.class);
|
||||
}
|
||||
return invoiceInfoService;
|
||||
}
|
||||
|
||||
public CompanyBankAccountService getBankAccountService() {
|
||||
if (bankAccountService == null) {
|
||||
bankAccountService = getBean(CompanyBankAccountService.class);
|
||||
}
|
||||
return bankAccountService;
|
||||
}
|
||||
|
||||
public CompanyContactService getContactService() {
|
||||
if (contactService == null) {
|
||||
contactService = getBean(CompanyContactService.class);
|
||||
}
|
||||
return contactService;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.project.satisfaction_survey.CustomerSatisfactionSurveyWindowController;
|
||||
import com.ecep.contract.controller.tab.RefreshableSkin;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
|
||||
import com.ecep.contract.ds.project.service.CustomerSatisfactionSurveyService;
|
||||
import com.ecep.contract.model.CustomerSatisfactionSurvey;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.service.CompanyStringConverter;
|
||||
import com.ecep.contract.ui.table.cell.EmployeeTableCell;
|
||||
import com.ecep.contract.vm.CustomerSatisfactionSurveyViewModel;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/project/project-tab-customer-satisfaction-survey.fxml")
|
||||
public class ProjectTabSkinCustomerSatisfactionSurvey
|
||||
extends AbstProjectTableTabSkin<CustomerSatisfactionSurvey, CustomerSatisfactionSurveyViewModel>
|
||||
implements RefreshableSkin {
|
||||
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, Number> idColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, String> codeColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, Number> totalScoreColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, Employee> applicantColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, LocalDateTime> applyTimeColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, String> descriptionColumn;
|
||||
public TableColumn<CustomerSatisfactionSurveyViewModel, LocalDate> dateColumn;
|
||||
|
||||
@Setter
|
||||
private CustomerSatisfactionSurveyService satisfactionSurveyService;
|
||||
@Setter
|
||||
private LocalDateStringConverter localDateStringConverter;
|
||||
@Setter
|
||||
private EmployeeStringConverter employeeStringConverter;
|
||||
@Setter
|
||||
private CompanyStringConverter companyStringConverter;
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
@Setter
|
||||
private CompanyCustomerService customerService;
|
||||
@Setter
|
||||
private CompanyCustomerFileService customerFileService;
|
||||
|
||||
public ProjectTabSkinCustomerSatisfactionSurvey(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CustomerSatisfactionSurveyService getViewModelService() {
|
||||
return getCustomerSatisfactionSurveyService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.satisfactionTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
|
||||
bindNumberColumn(idColumn, CustomerSatisfactionSurveyViewModel::getId);
|
||||
bindColumn(codeColumn, CustomerSatisfactionSurveyViewModel::getCode);
|
||||
bindLocalDateColumn(dateColumn, CustomerSatisfactionSurveyViewModel::getDate);
|
||||
bindNumberColumn(totalScoreColumn, CustomerSatisfactionSurveyViewModel::getTotalScore);
|
||||
applicantColumn.setCellValueFactory(param -> param.getValue().getApplicant());
|
||||
applicantColumn.setCellFactory(cell -> new EmployeeTableCell<>(getEmployeeService()));
|
||||
bindLocalDateTimeColumn(applyTimeColumn, CustomerSatisfactionSurveyViewModel::getApplyTime);
|
||||
bindColumn(descriptionColumn, CustomerSatisfactionSurveyViewModel::getDescription);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CustomerSatisfactionSurveyViewModel createNewViewModel() {
|
||||
CustomerSatisfactionSurveyViewModel model = super.createNewViewModel();
|
||||
Project project = getParent();
|
||||
model.getApplicant().set(controller.getCurrentUser());
|
||||
LocalDate created = project.getCreated();
|
||||
if (created == null) {
|
||||
created = LocalDate.now();
|
||||
}
|
||||
model.getApplyTime().set(LocalDateTime.of(created, LocalTime.now()));
|
||||
saveRow(model);
|
||||
|
||||
showInOwner(CustomerSatisfactionSurveyWindowController.class, model);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(CustomerSatisfactionSurveyViewModel item) {
|
||||
showInOwner(CustomerSatisfactionSurveyWindowController.class, item);
|
||||
}
|
||||
|
||||
private CustomerSatisfactionSurveyService getCustomerSatisfactionSurveyService() {
|
||||
if (satisfactionSurveyService == null) {
|
||||
satisfactionSurveyService = getBean(CustomerSatisfactionSurveyService.class);
|
||||
}
|
||||
return satisfactionSurveyService;
|
||||
}
|
||||
|
||||
private LocalDateStringConverter getLocalDateStringConverter() {
|
||||
if (localDateStringConverter == null) {
|
||||
localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
}
|
||||
return localDateStringConverter;
|
||||
}
|
||||
|
||||
private EmployeeStringConverter getEmployeeStringConverter() {
|
||||
if (employeeStringConverter == null) {
|
||||
employeeStringConverter = getBean(EmployeeStringConverter.class);
|
||||
}
|
||||
return employeeStringConverter;
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
private CompanyStringConverter getCompanyStringConverter() {
|
||||
if (companyStringConverter == null) {
|
||||
companyStringConverter = getBean(CompanyStringConverter.class);
|
||||
}
|
||||
return companyStringConverter;
|
||||
}
|
||||
|
||||
private CompanyCustomerService getCompanyCustomerService() {
|
||||
if (customerService == null) {
|
||||
customerService = getBean(CompanyCustomerService.class);
|
||||
}
|
||||
return customerService;
|
||||
}
|
||||
|
||||
private CompanyCustomerFileService getCompanyCustomerFileService() {
|
||||
if (customerFileService == null) {
|
||||
customerFileService = getBean(CompanyCustomerFileService.class);
|
||||
}
|
||||
return customerFileService;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.ecep.contract.ContractPayWay;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.ds.contract.service.ContractPayPlanService;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.project.service.ProjectFundPlanService;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.ContractPayPlan;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectFundPlan;
|
||||
import com.ecep.contract.ui.table.cell.NumberTableCell;
|
||||
import com.ecep.contract.util.NumberUtils;
|
||||
import com.ecep.contract.vm.ProjectFundPlanViewModel;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 项目资金计划
|
||||
* 工单 #2
|
||||
* fxml 文件在 /src/main/resources/ui/ 目录
|
||||
*/
|
||||
@FxmlPath("/ui/project/project-tab-fund-plan.fxml")
|
||||
public class ProjectTabSkinFundPlan
|
||||
extends AbstProjectTableTabSkin<ProjectFundPlan, ProjectFundPlanViewModel>
|
||||
implements TabSkin, EditableEntityTableTabSkin<ProjectFundPlan, ProjectFundPlanViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProjectTabSkinFundPlan.class);
|
||||
|
||||
public TableColumn<ProjectFundPlanViewModel, Number> idColumn;
|
||||
public TableColumn<ProjectFundPlanViewModel, LocalDate> payDateColumn;
|
||||
public TableColumn<ProjectFundPlanViewModel, Number> payRatioColumn;
|
||||
public TableColumn<ProjectFundPlanViewModel, Number> payCurrencyColumn;
|
||||
public TableColumn<ProjectFundPlanViewModel, Number> balanceColumn;
|
||||
public TableColumn<ProjectFundPlanViewModel, String> payTermColumn;
|
||||
public TableColumn<ProjectFundPlanViewModel, LocalDateTime> updateDateColumn;
|
||||
public TableColumn<ProjectFundPlanViewModel, String> payWayColumn;
|
||||
public Button updatePlanBtn;
|
||||
|
||||
@Setter
|
||||
private ProjectFundPlanService projectFundPlanService;
|
||||
|
||||
public ProjectTabSkinFundPlan(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectFundPlanService getViewModelService() {
|
||||
if (projectFundPlanService == null) {
|
||||
projectFundPlanService = getBean(ProjectFundPlanService.class);
|
||||
}
|
||||
return projectFundPlanService;
|
||||
}
|
||||
|
||||
public ContractPayPlanService getContractPayPlanService() {
|
||||
return controller.getCachedBean(ContractPayPlanService.class);
|
||||
}
|
||||
|
||||
private ContractService getContractService() {
|
||||
return controller.getCachedBean(ContractService.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.fundPlanTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
// 关闭所有的排序功能
|
||||
idColumn.setSortable(false);
|
||||
payDateColumn.setSortable(false);
|
||||
payRatioColumn.setSortable(false);
|
||||
payCurrencyColumn.setSortable(false);
|
||||
payTermColumn.setSortable(false);
|
||||
updateDateColumn.setSortable(false);
|
||||
payWayColumn.setSortable(false);
|
||||
balanceColumn.setSortable(false);
|
||||
|
||||
bindNumberColumn(idColumn, ProjectFundPlanViewModel::getId);
|
||||
bindLocalDateColumn(payDateColumn, ProjectFundPlanViewModel::getPayDate);
|
||||
bindColumn(payWayColumn, model -> {
|
||||
javafx.beans.property.SimpleStringProperty property = new javafx.beans.property.SimpleStringProperty();
|
||||
property.set(model.getPayWay().get() != null ? model.getPayWay().get().getText() : "");
|
||||
return property;
|
||||
});
|
||||
bindNumberColumn(payRatioColumn, ProjectFundPlanViewModel::getPayRatio);
|
||||
bindNumberColumn(payCurrencyColumn, ProjectFundPlanViewModel::getPayCurrency);
|
||||
payCurrencyColumn.setCellFactory(
|
||||
NumberTableCell.forTableColumn(controller.getCurrentEmployee().getNumberStringConverter()));
|
||||
bindNumberColumn(balanceColumn, ProjectFundPlanViewModel::getBalance);
|
||||
balanceColumn.setCellFactory(
|
||||
NumberTableCell.forTableColumn(controller.getCurrentEmployee().getNumberStringConverter()));
|
||||
bindColumn(payTermColumn, ProjectFundPlanViewModel::getPayTerm);
|
||||
bindLocalDateTimeColumn(updateDateColumn, ProjectFundPlanViewModel::getUpdateDate);
|
||||
updatePlanBtn.setOnAction(this::onUpdatePlanAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProjectFundPlanViewModel> loadTableData(Project parent) {
|
||||
List<ProjectFundPlanViewModel> rows = super.loadTableData(parent);
|
||||
if (rows == null) {
|
||||
return null;
|
||||
}
|
||||
// TODO 按付款日期排序
|
||||
rows = rows.stream().sorted(java.util.Comparator.comparing(
|
||||
model -> model.getPayDate().get(),
|
||||
java.util.Comparator.nullsFirst(java.util.Comparator.naturalOrder()))).collect(Collectors.toList());
|
||||
|
||||
double balance = 0;
|
||||
for (ProjectFundPlanViewModel row : rows) {
|
||||
if (row.getPayWay().get() == ContractPayWay.RECEIVE) {
|
||||
balance += row.getPayCurrency().get();
|
||||
} else if (row.getPayWay().get() == ContractPayWay.PAY) {
|
||||
balance -= row.getPayCurrency().get();
|
||||
}
|
||||
row.getBalance().set(balance);
|
||||
}
|
||||
|
||||
return rows;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 从合同的付款计划中更新项目的资金计划
|
||||
* 1. 从项目相关的合同中获取付款计划
|
||||
* 2. 更新项目的资金计划
|
||||
*/
|
||||
private void onUpdatePlanAction(ActionEvent event) {
|
||||
try {
|
||||
// 获取当前项目
|
||||
Project project = getParent();
|
||||
if (project == null || project.getId() == null) {
|
||||
setStatus("提示, 无法获取项目信息");
|
||||
return;
|
||||
}
|
||||
|
||||
List<ProjectFundPlan> fundPlans = getViewModelService().findAllByProject(project);
|
||||
// 将现有的项目资金计划转为以 ContractPayPlan 的id为key的map
|
||||
java.util.Map<Number, ProjectFundPlan> fundPlansMap = fundPlans.stream()
|
||||
.filter(plan -> plan.getContractPayPlan() != null && plan.getContractPayPlan().getId() != null)
|
||||
.collect(Collectors.toMap(
|
||||
plan -> plan.getContractPayPlan().getId(),
|
||||
plan -> plan));
|
||||
|
||||
// 获取项目关联的所有合同
|
||||
List<Contract> contracts = getContractService().findAllByProject(project);
|
||||
if (contracts == null || contracts.isEmpty()) {
|
||||
setStatus("提示, 未找到与项目关联的合同");
|
||||
return;
|
||||
}
|
||||
|
||||
// 遍历所有合同
|
||||
for (Contract contract : contracts) {
|
||||
// 获取合同的付款计划
|
||||
List<ContractPayPlan> payPlans = getContractPayPlanService().findAllByContract(contract);
|
||||
|
||||
// 遍历每个付款计划
|
||||
for (ContractPayPlan payPlan : payPlans) {
|
||||
// 检查是否已存在相同的合同付款计划
|
||||
if (fundPlansMap.containsKey(payPlan.getId())) {
|
||||
// 更新
|
||||
ProjectFundPlan fundPlan = fundPlansMap.remove(payPlan.getId());
|
||||
// 检查是否需要更新
|
||||
boolean needsUpdate = false;
|
||||
if (!Objects.equals(fundPlan.getPayWay(), contract.getPayWay())) {
|
||||
fundPlan.setPayWay(contract.getPayWay());
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (!Objects.equals(fundPlan.getPayDate(), payPlan.getPayDate())) {
|
||||
fundPlan.setPayDate(payPlan.getPayDate());
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (!NumberUtils.equals(fundPlan.getPayRatio(), payPlan.getPayRatio())) {
|
||||
fundPlan.setPayRatio(payPlan.getPayRatio());
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (!Objects.equals(fundPlan.getPayTerm(), payPlan.getPayTerm())) {
|
||||
fundPlan.setPayTerm(payPlan.getPayTerm());
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (!NumberUtils.equals(fundPlan.getPayCurrency(), payPlan.getPayCurrency())) {
|
||||
fundPlan.setPayCurrency(payPlan.getPayCurrency());
|
||||
needsUpdate = true;
|
||||
}
|
||||
if (needsUpdate) {
|
||||
fundPlan.setContractPayPlan(payPlan);
|
||||
fundPlan.setUpdateDate(LocalDateTime.now());
|
||||
saveRowData(fundPlan);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 创建新的项目资金计划
|
||||
ProjectFundPlan fundPlan = getViewModelService().newInstanceByProject(project);
|
||||
// 设置资金计划的属性
|
||||
fundPlan.setPayDate(payPlan.getPayDate());
|
||||
fundPlan.setPayWay(contract.getPayWay());
|
||||
fundPlan.setPayRatio(payPlan.getPayRatio());
|
||||
fundPlan.setPayTerm(payPlan.getPayTerm());
|
||||
fundPlan.setPayCurrency(payPlan.getPayCurrency());
|
||||
fundPlan.setContractPayPlan(payPlan);
|
||||
fundPlan.setUpdateDate(LocalDateTime.now());
|
||||
saveRowData(fundPlan);
|
||||
}
|
||||
}
|
||||
|
||||
// 删除
|
||||
if (!fundPlansMap.isEmpty()) {
|
||||
for (ProjectFundPlan fundPlan : fundPlansMap.values()) {
|
||||
getViewModelService().delete(fundPlan);
|
||||
}
|
||||
}
|
||||
// 刷新表格数据
|
||||
refresh();
|
||||
} catch (Exception e) {
|
||||
logger.error("更新项目资金计划失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectFundPlanViewModel createNewViewModel() {
|
||||
ProjectFundPlanViewModel model = new ProjectFundPlanViewModel();
|
||||
Project project = getParent();
|
||||
model.getProject().set(project);
|
||||
model.getUpdateDate().set(LocalDateTime.now());
|
||||
saveRow(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(ProjectFundPlanViewModel item) {
|
||||
// 可以在这里实现双击打开详情窗口的逻辑
|
||||
// 目前暂不实现具体的窗口
|
||||
}
|
||||
|
||||
private ProjectFundPlanService getProjectFundPlanService() {
|
||||
if (projectFundPlanService == null) {
|
||||
projectFundPlanService = getBean(ProjectFundPlanService.class);
|
||||
}
|
||||
return projectFundPlanService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteRowData(ProjectFundPlan entity) {
|
||||
getProjectFundPlanService().delete(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectFundPlan loadRowData(ProjectFundPlanViewModel row) {
|
||||
return getProjectFundPlanService().findById(row.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectFundPlan saveRowData(ProjectFundPlan entity) {
|
||||
return getProjectFundPlanService().save(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.controller.project.quotation.ProjectQuotationWindowController;
|
||||
import com.ecep.contract.controller.tab.RefreshableSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
|
||||
import com.ecep.contract.ds.project.service.ProjectQuotationService;
|
||||
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectQuotation;
|
||||
import com.ecep.contract.service.CompanyStringConverter;
|
||||
import com.ecep.contract.ui.table.cell.EmployeeTableCell;
|
||||
import com.ecep.contract.ui.table.cell.EvaluationFileTableCell;
|
||||
import com.ecep.contract.ui.table.cell.LocalDateTimeTableCell;
|
||||
import com.ecep.contract.vm.ProjectQuotationViewModel;
|
||||
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.util.converter.CurrencyStringConverter;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
@FxmlPath("/ui/project/project-tab-quotation.fxml")
|
||||
public class ProjectTabSkinQuotation
|
||||
extends AbstProjectTableTabSkin<ProjectQuotation, ProjectQuotationViewModel>
|
||||
implements TabSkin, EditableEntityTableTabSkin<ProjectQuotation, ProjectQuotationViewModel>, RefreshableSkin {
|
||||
|
||||
public TableColumn<ProjectQuotationViewModel, Number> idColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, Number> versionColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, CompanyCustomerEvaluationFormFile> evaluationFileColumn;
|
||||
|
||||
public TableColumn<ProjectQuotationViewModel, String> descriptionColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, Employee> applicantColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, LocalDateTime> applyTimeColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, Employee> authorizerColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, LocalDateTime> authorizationTimeColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, Number> levelColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, String> standardPayWayColumn;
|
||||
public TableColumn<ProjectQuotationViewModel, Number> amountColumn;
|
||||
|
||||
@Setter
|
||||
private ProjectQuotationService projectQuotationService;
|
||||
@Setter
|
||||
private LocalDateStringConverter localDateStringConverter;
|
||||
@Setter
|
||||
private EmployeeStringConverter employeeStringConverter;
|
||||
@Setter
|
||||
private CompanyStringConverter companyStringConverter;
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
@Setter
|
||||
private CompanyCustomerService customerService;
|
||||
@Setter
|
||||
private CompanyCustomerFileService customerFileService;
|
||||
|
||||
|
||||
public ProjectTabSkinQuotation(ProjectWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectQuotationService getViewModelService() {
|
||||
return getProjectQuotationService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.quotationApprovalTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTable() {
|
||||
super.initializeTable();
|
||||
levelColumn.setCellValueFactory(param -> param.getValue().getLevel());
|
||||
levelColumn.setCellFactory(param -> new LevelTableCell());
|
||||
standardPayWayColumn.setCellValueFactory(param -> param.getValue().getStandardPayWay().map(value -> value == null ? "" : (value ? "标准" : "非标准")));
|
||||
evaluationFileColumn.setCellValueFactory(param -> param.getValue().getEvaluationFile());
|
||||
evaluationFileColumn.setCellFactory(param -> new EvaluationFileTableCell<>(getCompanyCustomerFileService()));
|
||||
|
||||
|
||||
amountColumn.setCellValueFactory(param -> param.getValue().getAmount());
|
||||
amountColumn.setCellFactory(TextFieldTableCell.forTableColumn(new CurrencyStringConverter(getLocale())));
|
||||
|
||||
applicantColumn.setCellValueFactory(param -> param.getValue().getApplicant());
|
||||
applicantColumn.setCellFactory(column1 -> new EmployeeTableCell<>());
|
||||
applyTimeColumn.setCellValueFactory(param -> param.getValue().getApplyTime());
|
||||
applyTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
authorizerColumn.setCellValueFactory(param -> param.getValue().getAuthorizer());
|
||||
authorizerColumn.setCellFactory(column -> new EmployeeTableCell<>());
|
||||
authorizationTimeColumn.setCellValueFactory(param -> param.getValue().getAuthorizationTime());
|
||||
authorizationTimeColumn.setCellFactory(param -> new LocalDateTimeTableCell<>());
|
||||
|
||||
|
||||
descriptionColumn.setCellValueFactory(param -> param.getValue().getDescription());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProjectQuotationViewModel createNewViewModel() {
|
||||
ProjectQuotationViewModel model = new ProjectQuotationViewModel();
|
||||
Project project = getParent();
|
||||
model.getProject().set(project);
|
||||
model.getApplicant().set(project.getApplicant());
|
||||
if (project.getAmount() != null) {
|
||||
model.getAmount().set(project.getAmount());
|
||||
}
|
||||
|
||||
LocalDate created = project.getCreated();
|
||||
if (created == null) {
|
||||
created = LocalDate.now();
|
||||
}
|
||||
model.getApplyTime().set(LocalDateTime.of(created, LocalTime.now()));
|
||||
saveRow(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTableRowDoubleClickedAction(ProjectQuotationViewModel item) {
|
||||
showInOwner(ProjectQuotationWindowController.class, item);
|
||||
}
|
||||
|
||||
private ProjectQuotationService getProjectQuotationService() {
|
||||
if (projectQuotationService == null) {
|
||||
projectQuotationService = getBean(ProjectQuotationService.class);
|
||||
}
|
||||
return projectQuotationService;
|
||||
}
|
||||
|
||||
private LocalDateStringConverter getLocalDateStringConverter() {
|
||||
if (localDateStringConverter == null) {
|
||||
localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
}
|
||||
return localDateStringConverter;
|
||||
}
|
||||
|
||||
private EmployeeStringConverter getEmployeeStringConverter() {
|
||||
if (employeeStringConverter == null) {
|
||||
employeeStringConverter = getBean(EmployeeStringConverter.class);
|
||||
}
|
||||
return employeeStringConverter;
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
private CompanyStringConverter getCompanyStringConverter() {
|
||||
if (companyStringConverter == null) {
|
||||
companyStringConverter = getBean(CompanyStringConverter.class);
|
||||
}
|
||||
return companyStringConverter;
|
||||
}
|
||||
|
||||
private CompanyCustomerService getCompanyCustomerService() {
|
||||
if (customerService == null) {
|
||||
customerService = getBean(CompanyCustomerService.class);
|
||||
}
|
||||
return customerService;
|
||||
}
|
||||
|
||||
private CompanyCustomerFileService getCompanyCustomerFileService() {
|
||||
if (customerFileService == null) {
|
||||
customerFileService = getBean(CompanyCustomerFileService.class);
|
||||
}
|
||||
return customerFileService;
|
||||
}
|
||||
|
||||
private static class LevelTableCell extends TableCell<ProjectQuotationViewModel, Number> {
|
||||
@Override
|
||||
protected void updateItem(Number item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (empty || item == null) {
|
||||
setText("");
|
||||
return;
|
||||
}
|
||||
// 较差,一般,良好
|
||||
int value = item.intValue();
|
||||
if (value < 0) {
|
||||
setText("-");
|
||||
return;
|
||||
}
|
||||
if (value < 1) {
|
||||
setText("较差");
|
||||
return;
|
||||
}
|
||||
if (value < 2) {
|
||||
setText("一般");
|
||||
return;
|
||||
}
|
||||
if (value < 3) {
|
||||
setText("良好");
|
||||
return;
|
||||
}
|
||||
setText(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package com.ecep.contract.controller.project;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.ecep.contract.SpringApp;
|
||||
import com.ecep.contract.controller.AbstEntityController;
|
||||
import com.ecep.contract.util.FxmlPath;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.other.service.EmployeeService;
|
||||
import com.ecep.contract.ds.project.service.ProjectService;
|
||||
import com.ecep.contract.model.DeliverySignMethod;
|
||||
import com.ecep.contract.model.ProductType;
|
||||
import com.ecep.contract.model.ProductUsage;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectIndustry;
|
||||
import com.ecep.contract.model.ProjectSaleType;
|
||||
import com.ecep.contract.model.ProjectType;
|
||||
import com.ecep.contract.vm.ProjectViewModel;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.DatePicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.Window;
|
||||
import javafx.stage.WindowEvent;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
|
||||
@Lazy
|
||||
@Scope("prototype")
|
||||
@Component
|
||||
@FxmlPath("/ui/project/project.fxml")
|
||||
public class ProjectWindowController extends AbstEntityController<Project, ProjectViewModel> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProjectWindowController.class);
|
||||
|
||||
|
||||
|
||||
public static void show(Project project, Window window) {
|
||||
ProjectViewModel viewModel = new ProjectViewModel();
|
||||
if (!Hibernate.isInitialized(project)) {
|
||||
project = SpringApp.getBean(ProjectService.class).findById(project.getId());
|
||||
}
|
||||
viewModel.update(project);
|
||||
show(viewModel, window);
|
||||
}
|
||||
|
||||
public static void show(ProjectViewModel model, Window window) {
|
||||
show(ProjectWindowController.class, model, window);
|
||||
}
|
||||
|
||||
public BorderPane root;
|
||||
public TabPane tabPane;
|
||||
|
||||
public Button refreshBtn;
|
||||
public Button deleteBtn;
|
||||
|
||||
|
||||
LocalDateStringConverter localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
|
||||
// 基本信息 Tab
|
||||
public Tab baseInfoTab;
|
||||
public TextField nameField;
|
||||
public TextField codeField;
|
||||
public TextField codeYearField;
|
||||
public TextField codeSequenceNumberField;
|
||||
public TextField addressField;
|
||||
public TextArea descriptionField;
|
||||
public CheckBox useBidField;
|
||||
public CheckBox useOfferField;
|
||||
public TextField amountField;
|
||||
public CheckBox standardPayWayField;
|
||||
public ComboBox<ProjectIndustry> industryField;
|
||||
public ComboBox<ProjectSaleType> saleTypeField;
|
||||
public ComboBox<ProjectType> projectTypeField;
|
||||
public ComboBox<ProductType> productTypeField;
|
||||
public ComboBox<DeliverySignMethod> deliverySignMethodField;
|
||||
public ComboBox<ProductUsage> productUsageField;
|
||||
public TextField applicantField;
|
||||
public TextField authorizerField;
|
||||
public DatePicker plannedStartTimeField;
|
||||
public DatePicker plannedCompletionTimeField;
|
||||
public DatePicker createdField;
|
||||
public Label versionLabel;
|
||||
|
||||
/*
|
||||
合同 Tab
|
||||
*/
|
||||
public Tab contractTab;
|
||||
/* 成本审批 */
|
||||
public Tab costTab;
|
||||
|
||||
|
||||
// 文件 Tab
|
||||
public Tab fileTab;
|
||||
public TableView fileTable;
|
||||
public TableColumn fileTable_idColumn;
|
||||
public TableColumn fileTable_typeColumn;
|
||||
public TableColumn fileTable_filePathColumn;
|
||||
public TableColumn fileTable_applyDateColumn;
|
||||
public TableColumn fileTable_descriptionColumn;
|
||||
|
||||
// 客户信息 Tab
|
||||
public Tab companyTab;
|
||||
|
||||
// 报价审批 Tab
|
||||
public Tab quotationApprovalTab;
|
||||
|
||||
/**
|
||||
* 投标 Bid Tab
|
||||
*/
|
||||
public Tab bidTab;
|
||||
/**
|
||||
* 资金计划 Tab
|
||||
*/
|
||||
public Tab fundPlanTab;
|
||||
/**
|
||||
* 顾客满意度 Tab
|
||||
*/
|
||||
public Tab satisfactionTab;
|
||||
|
||||
@Autowired
|
||||
ProjectService projectService;
|
||||
@Autowired
|
||||
private EmployeeService employeeService;
|
||||
@Autowired
|
||||
ContractService contractService;
|
||||
|
||||
public ProjectWindowController() {
|
||||
}
|
||||
|
||||
public void onShown(WindowEvent windowEvent) {
|
||||
super.onShown(windowEvent);
|
||||
refreshBtn.setOnAction(event -> refreshByButton((Button) event.getSource()));
|
||||
getTitle().bind(Bindings.createStringBinding(() -> "[" + viewModel.getId().get() + "] " + viewModel.getCode().get() + " " + viewModel.getName().getValue() + " 项目详情", viewModel.getCode(), viewModel.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Project loadEntity() {
|
||||
return projectService.findById(viewModel.getId().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Project saveEntity(Project entity) {
|
||||
return projectService.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerTabSkins() {
|
||||
registerTabSkin(baseInfoTab, this::createBaseTabSkin);
|
||||
registerTabSkin(companyTab, tab -> new ProjectTabSkinCustomerInfo(this));
|
||||
registerTabSkin(contractTab, tab -> new ProjectTabSkinContract(this));
|
||||
registerTabSkin(costTab, tab -> new ProjectTabSkinCost(this));
|
||||
registerTabSkin(quotationApprovalTab, tab -> new ProjectTabSkinQuotation(this));
|
||||
registerTabSkin(bidTab, tab -> new ProjectTabSkinBid(this));
|
||||
registerTabSkin(fundPlanTab, tab -> new ProjectTabSkinFundPlan(this));
|
||||
// registerTabSkin(costItemTab, this::createCostItemTabSkin);
|
||||
registerTabSkin(satisfactionTab, tab -> new ProjectTabSkinCustomerSatisfactionSurvey(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectService getViewModelService() {
|
||||
return projectService;
|
||||
}
|
||||
|
||||
|
||||
private ProjectTabSkinBase createBaseTabSkin(Tab tab) {
|
||||
ProjectTabSkinBase skin = new ProjectTabSkinBase(this);
|
||||
skin.setLocalDateStringConverter(localDateStringConverter);
|
||||
skin.setEmployeeService(employeeService);
|
||||
return skin;
|
||||
}
|
||||
|
||||
public void onFileReBuildingAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
public void onFileTableContextMenuShowing(WindowEvent windowEvent) {
|
||||
}
|
||||
|
||||
public void onFileTableRefreshAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
public void onFileTableDeleteAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
public void onGetNextCodeSNAction(ActionEvent event) {
|
||||
ProjectSaleType projectSaleType = viewModel.getSaleType().get();
|
||||
int year = viewModel.getCodeYear().get();
|
||||
int sn = viewModel.getCodeSequenceNumber().get();
|
||||
|
||||
int nextSequenceNumber = projectService.getNextCodeSequenceNumber(projectSaleType, year);
|
||||
viewModel.getCodeSequenceNumber().set(nextSequenceNumber);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
package com.ecep.contract.controller.project.bid;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.NumberFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import com.ecep.contract.CompanyCustomerFileType;
|
||||
import com.ecep.contract.ContractFileType;
|
||||
import com.ecep.contract.DesktopUtils;
|
||||
import com.ecep.contract.MyDateTimeUtils;
|
||||
import com.ecep.contract.UITools;
|
||||
import com.ecep.contract.controller.customer.CompanyCustomerEvaluationFormFileWindowController;
|
||||
import com.ecep.contract.controller.project.cost.ProjectCostWindowController;
|
||||
import com.ecep.contract.controller.tab.AbstEntityBasedTabSkin;
|
||||
import com.ecep.contract.controller.tab.TabSkin;
|
||||
import com.ecep.contract.converter.EmployeeStringConverter;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.ds.company.service.CompanyService;
|
||||
import com.ecep.contract.ds.contract.service.ContractFileService;
|
||||
import com.ecep.contract.ds.contract.service.ContractService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerFileService;
|
||||
import com.ecep.contract.ds.customer.service.CompanyCustomerService;
|
||||
import com.ecep.contract.ds.project.service.ProjectCostService;
|
||||
import com.ecep.contract.ds.project.service.ProjectQuotationService;
|
||||
import com.ecep.contract.ds.project.service.ProjectService;
|
||||
import com.ecep.contract.model.Company;
|
||||
import com.ecep.contract.model.CompanyCustomer;
|
||||
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
|
||||
import com.ecep.contract.model.CompanyCustomerFile;
|
||||
import com.ecep.contract.model.Contract;
|
||||
import com.ecep.contract.model.ContractFile;
|
||||
import com.ecep.contract.model.Employee;
|
||||
import com.ecep.contract.model.Project;
|
||||
import com.ecep.contract.model.ProjectBid;
|
||||
import com.ecep.contract.model.ProjectCost;
|
||||
import com.ecep.contract.service.CompanyStringConverter;
|
||||
import com.ecep.contract.vm.ProjectBidViewModel;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.util.converter.LocalDateStringConverter;
|
||||
import javafx.util.converter.LocalDateTimeStringConverter;
|
||||
import javafx.util.converter.NumberStringConverter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class ProjectBidTabSkinBase
|
||||
extends AbstEntityBasedTabSkin<ProjectBidWindowController, ProjectBid, ProjectBidViewModel>
|
||||
implements TabSkin {
|
||||
|
||||
@Setter
|
||||
private LocalDateTimeStringConverter localDateTimeStringConverter;
|
||||
@Setter
|
||||
private ProjectQuotationService projectQuotationService;
|
||||
@Setter
|
||||
private LocalDateStringConverter localDateStringConverter;
|
||||
@Setter
|
||||
private EmployeeStringConverter employeeStringConverter;
|
||||
@Setter
|
||||
private CompanyStringConverter companyStringConverter;
|
||||
@Setter
|
||||
private CompanyService companyService;
|
||||
@Setter
|
||||
private CompanyCustomerService customerService;
|
||||
@Setter
|
||||
private CompanyCustomerFileService customerFileService;
|
||||
@Setter
|
||||
private ProjectService projectService;
|
||||
@Setter
|
||||
private ProjectCostService projectCostService;
|
||||
@Setter
|
||||
private ContractService contractService;
|
||||
@Setter
|
||||
private ContractFileService contractFileService;
|
||||
|
||||
private ProjectService getProjectService() {
|
||||
if (projectService == null) {
|
||||
projectService = getBean(ProjectService.class);
|
||||
}
|
||||
return projectService;
|
||||
}
|
||||
|
||||
ProjectCostService getProjectCostService() {
|
||||
if (projectCostService == null) {
|
||||
projectCostService = getBean(ProjectCostService.class);
|
||||
}
|
||||
return projectCostService;
|
||||
}
|
||||
|
||||
ContractFileService getContractFileService() {
|
||||
if (contractFileService == null) {
|
||||
contractFileService = getBean(ContractFileService.class);
|
||||
}
|
||||
return contractFileService;
|
||||
}
|
||||
|
||||
ContractService getContractService() {
|
||||
if (contractService == null) {
|
||||
contractService = getBean(ContractService.class);
|
||||
}
|
||||
return contractService;
|
||||
}
|
||||
|
||||
public ProjectBidTabSkinBase(ProjectBidWindowController controller) {
|
||||
super(controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTab() {
|
||||
return controller.baseInfoTab;
|
||||
}
|
||||
|
||||
void setSelectedToggle(ToggleGroup group, int targetLevel) {
|
||||
group.getToggles().stream()
|
||||
.filter(toggle -> toggle.getUserData() instanceof Integer)
|
||||
.filter(toggle -> (Integer) toggle.getUserData() == targetLevel)
|
||||
.findFirst()
|
||||
.ifPresent(group::selectToggle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTab() {
|
||||
|
||||
employeeAutoCompletion(controller.applicantField, viewModel.getApplicant());
|
||||
controller.applyTimeField.textProperty().bindBidirectional(viewModel.getApplyTime(),
|
||||
getLocalDateTimeStringConverter());
|
||||
employeeAutoCompletion(controller.authorizerField, viewModel.getAuthorizer());
|
||||
controller.authorizationTimeField.textProperty().bindBidirectional(viewModel.getAuthorizationTime(),
|
||||
getLocalDateTimeStringConverter());
|
||||
|
||||
// viewModel.getLevel();
|
||||
ToggleGroup levelGroup = new ToggleGroup();
|
||||
controller.good_radio_btn.setToggleGroup(levelGroup);
|
||||
controller.good_radio_btn.setUserData(2);
|
||||
controller.bad_radio_btn.setToggleGroup(levelGroup);
|
||||
controller.bad_radio_btn.setUserData(1);
|
||||
controller.poor_radio_btn.setToggleGroup(levelGroup);
|
||||
controller.poor_radio_btn.setUserData(0);
|
||||
setSelectedToggle(levelGroup, viewModel.getLevel().get());
|
||||
// levelGroup;
|
||||
// UI -> ViewModel
|
||||
levelGroup.selectedToggleProperty().addListener((obs, oldToggle, newToggle) -> {
|
||||
if (newToggle != null && newToggle.getUserData() instanceof Integer) {
|
||||
viewModel.getLevel().set((Integer) newToggle.getUserData());
|
||||
}
|
||||
});
|
||||
|
||||
// ViewModel -> UI: 监听 level 属性变化
|
||||
viewModel.getLevel().addListener((obs, oldVal, newVal) -> {
|
||||
if (newVal == null)
|
||||
return;
|
||||
setSelectedToggle(levelGroup, newVal.intValue());
|
||||
});
|
||||
|
||||
controller.standardPayWayField.selectedProperty().bindBidirectional(viewModel.getStandardPayWay());
|
||||
controller.noStandardPayWayTextField.textProperty().bindBidirectional(viewModel.getNoStandardPayWayText());
|
||||
controller.noStandardPayWayTextField.disableProperty().bind(controller.standardPayWayField.selectedProperty());
|
||||
|
||||
controller.standardContractTextField.selectedProperty().bindBidirectional(viewModel.getStandardContractText());
|
||||
controller.noStandardContractTextField.textProperty().bindBidirectional(viewModel.getNoStandardContractText());
|
||||
controller.noStandardContractTextField.disableProperty()
|
||||
.bind(controller.standardContractTextField.selectedProperty());
|
||||
|
||||
controller.amountField.textProperty().bindBidirectional(viewModel.getAmount(),
|
||||
new NumberStringConverter(getLocale()));
|
||||
|
||||
evaluationFileAutoCompletion(controller.evaluationFileField, viewModel.getEvaluationFile());
|
||||
controller.evaluationFileBtn.setOnAction(event -> {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
CompanyCustomerEvaluationFormFile file = viewModel.getEvaluationFile().get();
|
||||
if (file != null) {
|
||||
if (!Hibernate.isInitialized(file)) {
|
||||
file = getCompanyCustomerFileService().findCustomerEvaluationFormFileById(file.getId());
|
||||
}
|
||||
CompanyCustomerEvaluationFormFileWindowController.show(file.getCustomerFile(),
|
||||
getTab().getTabPane().getScene().getWindow());
|
||||
}
|
||||
}).exceptionally(this::handleException);
|
||||
});
|
||||
|
||||
projectCostAutoCompletion(controller.costField, viewModel.getCost());
|
||||
controller.costBtn.setOnAction(event -> {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
ProjectCost cost = viewModel.getCost().get();
|
||||
if (cost != null) {
|
||||
if (!Hibernate.isInitialized(cost)) {
|
||||
cost = getProjectCostService().findById(cost.getId());
|
||||
}
|
||||
ProjectCostWindowController.show(cost, getTab().getTabPane().getScene().getWindow());
|
||||
}
|
||||
}).exceptionally(this::handleException);
|
||||
});
|
||||
|
||||
controller.authorizationFileField.textProperty().bind(viewModel.getAuthorizationFile().map(File::getName));
|
||||
controller.openAuthorizationFileBtn.setOnAction(event -> {
|
||||
DesktopUtils.showInExplorer(viewModel.getAuthorizationFile().get());
|
||||
});
|
||||
controller.openAuthorizationFileBtn.disableProperty().bind(viewModel.getAuthorizationFile().isNull());
|
||||
controller.changeAuthorizationFileBtn.setOnAction(this::onChangeAuthorizationFileAction);
|
||||
|
||||
controller.bidAcceptanceLetterFileField.textProperty()
|
||||
.bind(viewModel.getBidAcceptanceLetterFile().map(File::getName));
|
||||
controller.openBidAcceptanceLetterFileBtn.setOnAction(event -> {
|
||||
DesktopUtils.showInExplorer(viewModel.getBidAcceptanceLetterFile().get());
|
||||
});
|
||||
controller.openBidAcceptanceLetterFileBtn.disableProperty()
|
||||
.bind(viewModel.getBidAcceptanceLetterFile().isNull());
|
||||
controller.changeBidAcceptanceLetterFileBtn.setOnAction(this::onChangeBidAcceptanceLetterFileAction);
|
||||
|
||||
controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());
|
||||
|
||||
controller.importExcelBtn.setOnAction(event -> {
|
||||
FileChooser chooser = new FileChooser();
|
||||
chooser.setTitle("导入投标审批表");
|
||||
File file = chooser.showOpenDialog(getTab().getTabPane().getScene().getWindow());
|
||||
importFromExcel(file);
|
||||
});
|
||||
|
||||
if (getViewModel().getEvaluationFile().get() == null) {
|
||||
CompletableFuture.runAsync(this::tryGetEvaluationFile).exceptionally(this::handleException);
|
||||
}
|
||||
|
||||
if (getViewModel().getAuthorizationFile().get() == null) {
|
||||
CompletableFuture.runAsync(this::tryGetAuthorizationFile).exceptionally(this::handleException);
|
||||
}
|
||||
|
||||
if (getViewModel().getBidAcceptanceLetterFile().get() == null) {
|
||||
CompletableFuture.runAsync(this::tryGetBidAcceptanceLetterFile).exceptionally(this::handleException);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void onChangeAuthorizationFileAction(ActionEvent event) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
setInitialDirectory(fileChooser, viewModel.getAuthorizationFile().get(), viewModel.getProject().get());
|
||||
File selectedFile = fileChooser.showOpenDialog(getTab().getTabPane().getScene().getWindow());
|
||||
if (selectedFile != null) {
|
||||
viewModel.getAuthorizationFile().set(selectedFile);
|
||||
// save();
|
||||
}
|
||||
}
|
||||
|
||||
public void onChangeBidAcceptanceLetterFileAction(ActionEvent event) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
setInitialDirectory(fileChooser, viewModel.getBidAcceptanceLetterFile().get(), viewModel.getProject().get());
|
||||
File selectedFile = fileChooser.showOpenDialog(getTab().getTabPane().getScene().getWindow());
|
||||
if (selectedFile != null) {
|
||||
viewModel.getBidAcceptanceLetterFile().set(selectedFile);
|
||||
// save();
|
||||
}
|
||||
}
|
||||
|
||||
void setInitialDirectory(FileChooser fileChooser, File file, Project project) {
|
||||
if (file == null) {
|
||||
if (project != null) {
|
||||
if (!Hibernate.isInitialized(project)) {
|
||||
project = getProjectService().findById(project.getId());
|
||||
}
|
||||
File path = getProjectService().searchPath(project);
|
||||
if (path != null) {
|
||||
fileChooser.setInitialDirectory(path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileChooser.setInitialDirectory(file.getParentFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取客户资信评估表
|
||||
*/
|
||||
private void tryGetEvaluationFile() {
|
||||
Project project = getViewModel().getProject().get();
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
if (!Hibernate.isInitialized(project)) {
|
||||
project = getProjectService().findById(project.getId());
|
||||
}
|
||||
Company company = project.getCustomer();
|
||||
CompanyCustomer customer = getCompanyCustomerService().findByCompany(company);
|
||||
if (customer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompanyCustomerFileService companyCustomerFileService = getBean(CompanyCustomerFileService.class);
|
||||
List<CompanyCustomerFile> list = companyCustomerFileService.findAllByCustomerAndType(customer,
|
||||
CompanyCustomerFileType.EvaluationForm);
|
||||
if (list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LocalDateTime applyTime = getViewModel().getApplyTime().get();
|
||||
LocalDate verifyDate = applyTime.toLocalDate();
|
||||
CompanyCustomerFile file = list.stream()
|
||||
.filter(v -> v.getSignDate() != null && v.isValid())
|
||||
.filter(v -> v.getType() == CompanyCustomerFileType.EvaluationForm)
|
||||
.filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getSignDate(), v.getSignDate().plusYears(1),
|
||||
7))
|
||||
.findFirst().orElse(null);
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
CompanyCustomerEvaluationFormFile evaluationFile = companyCustomerFileService
|
||||
.findCustomerEvaluationFormFileByCustomerFile(file);
|
||||
if (evaluationFile == null) {
|
||||
return;
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
getViewModel().getEvaluationFile().set(evaluationFile);
|
||||
Integer creditLevel = evaluationFile.getCreditLevel();
|
||||
getViewModel().getLevel().set(creditLevel >= 4 ? 2 : creditLevel >= 2 ? 1 : 0);
|
||||
save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取授权文件
|
||||
*/
|
||||
private void tryGetAuthorizationFile() {
|
||||
getContractFile(viewModel.getAuthorizationFile(), viewModel.getAuthorizationTime(),
|
||||
ContractFileType.BidApprovalForm);
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试获取中标通知文件
|
||||
*/
|
||||
private void tryGetBidAcceptanceLetterFile() {
|
||||
getContractFile(viewModel.getAuthorizationFile(), viewModel.getAuthorizationTime(),
|
||||
ContractFileType.BidAcceptanceLetter);
|
||||
}
|
||||
|
||||
private void getContractFile(SimpleObjectProperty<File> fileProperty,
|
||||
SimpleObjectProperty<LocalDateTime> dateTimeProperty, ContractFileType type) {
|
||||
Project project = getViewModel().getProject().get();
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
List<ContractFile> list = new ArrayList<>();
|
||||
for (Contract contract : getContractService().findAllSalesByProject(project)) {
|
||||
list.addAll(getContractFileService().findAllByContractAndFileType(contract, type));
|
||||
}
|
||||
if (list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContractFile contractFile = list.stream().max(Comparator.comparing(ContractFile::getApplyDate))
|
||||
.orElse(null);
|
||||
if (contractFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (contractFile.getApplyDate() != null && dateTimeProperty.get() == null) {
|
||||
LocalDateTime localDateTime = LocalDateTime.of(contractFile.getApplyDate(), LocalTime.MIN);
|
||||
dateTimeProperty.set(localDateTime);
|
||||
}
|
||||
Contract c = contractFile.getContract();
|
||||
;
|
||||
File file = new File(c.getPath(), contractFile.getFileName());
|
||||
if (file.exists()) {
|
||||
Platform.runLater(() -> {
|
||||
getViewModel().getAuthorizationFile().set(file);
|
||||
save();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDateTimeStringConverter getLocalDateTimeStringConverter() {
|
||||
if (localDateTimeStringConverter == null) {
|
||||
localDateTimeStringConverter = new LocalDateTimeStringConverter(
|
||||
DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN), null);
|
||||
}
|
||||
return localDateTimeStringConverter;
|
||||
}
|
||||
|
||||
private void uploadScanFile(File file) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void importFromExcel(File file) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
private void projectCostAutoCompletion(TextField textField, SimpleObjectProperty<ProjectCost> property) {
|
||||
EntityStringConverter<ProjectCost> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(formFile -> getProjectCostService().findById(formFile.getId()));
|
||||
NumberFormat numberInstance = NumberFormat.getNumberInstance(getLocale());
|
||||
numberInstance.setMinimumFractionDigits(2);
|
||||
numberInstance.setMaximumFractionDigits(2);
|
||||
converter.setFormater(cost -> {
|
||||
return "v" + cost.getVersion() + ", GM:" + numberInstance.format(cost.getGrossProfitMargin()) + "%";
|
||||
});
|
||||
converter.setSuggestion(searchText -> {
|
||||
Project project = getViewModel().getProject().get();
|
||||
if (project == null) {
|
||||
return null;
|
||||
}
|
||||
return getProjectCostService().findAllByProject(project);
|
||||
});
|
||||
UITools.autoCompletion(textField, property, converter).setOnAutoCompleted(event -> {
|
||||
property.set(event.getCompletion());
|
||||
});
|
||||
}
|
||||
|
||||
private void evaluationFileAutoCompletion(TextField textField,
|
||||
SimpleObjectProperty<CompanyCustomerEvaluationFormFile> property) {
|
||||
EntityStringConverter<CompanyCustomerEvaluationFormFile> converter = new EntityStringConverter<>();
|
||||
converter.setInitialized(
|
||||
formFile -> getCompanyCustomerFileService().findCustomerEvaluationFormFileById(formFile.getId()));
|
||||
converter.setFormater(formFile -> {
|
||||
CompanyCustomerFile customerFile = formFile.getCustomerFile();
|
||||
if (customerFile == null) {
|
||||
return "无";
|
||||
}
|
||||
File file = new File(customerFile.getFilePath());
|
||||
return file.getName() + ", 等级:" + formFile.getCreditLevel();
|
||||
});
|
||||
converter.setSuggestion(searchText -> {
|
||||
Project project = getViewModel().getProject().get();
|
||||
if (project == null) {
|
||||
return null;
|
||||
}
|
||||
if (!Hibernate.isInitialized(project)) {
|
||||
project = getProjectService().findById(project.getId());
|
||||
}
|
||||
Company company = project.getCustomer();
|
||||
if (company == null) {
|
||||
return null;
|
||||
}
|
||||
CompanyCustomer customer = getCompanyCustomerService().findByCompany(company);
|
||||
if (customer == null) {
|
||||
return null;
|
||||
}
|
||||
return getCompanyCustomerFileService().searchEvaluationFile(customer, searchText);
|
||||
});
|
||||
UITools.autoCompletion(textField, property, converter).setOnAutoCompleted(event -> {
|
||||
CompanyCustomerEvaluationFormFile evaluationFile = event.getCompletion();
|
||||
Integer creditLevel = evaluationFile.getCreditLevel();
|
||||
viewModel.getLevel().set(creditLevel >= 4 ? 2 : creditLevel >= 2 ? 1 : 0);
|
||||
property.set(evaluationFile);
|
||||
});
|
||||
}
|
||||
|
||||
private void employeeAutoCompletion(TextField textField, SimpleObjectProperty<Employee> property) {
|
||||
UITools.autoCompletion(textField, property, getEmployeeStringConverter());
|
||||
}
|
||||
|
||||
private void companyAutoCompletion(TextField textField, SimpleObjectProperty<Company> property) {
|
||||
UITools.autoCompletion(textField, property, getCompanyStringConverter());
|
||||
}
|
||||
|
||||
private ProjectQuotationService getProjectQuotationService() {
|
||||
if (projectQuotationService == null) {
|
||||
projectQuotationService = getBean(ProjectQuotationService.class);
|
||||
}
|
||||
return projectQuotationService;
|
||||
}
|
||||
|
||||
private LocalDateStringConverter getLocalDateStringConverter() {
|
||||
if (localDateStringConverter == null) {
|
||||
localDateStringConverter = new LocalDateStringConverter(DateTimeFormatter.ISO_LOCAL_DATE, null);
|
||||
}
|
||||
return localDateStringConverter;
|
||||
}
|
||||
|
||||
private EmployeeStringConverter getEmployeeStringConverter() {
|
||||
if (employeeStringConverter == null) {
|
||||
employeeStringConverter = getBean(EmployeeStringConverter.class);
|
||||
}
|
||||
return employeeStringConverter;
|
||||
}
|
||||
|
||||
public CompanyService getCompanyService() {
|
||||
if (companyService == null) {
|
||||
companyService = getBean(CompanyService.class);
|
||||
}
|
||||
return companyService;
|
||||
}
|
||||
|
||||
private CompanyStringConverter getCompanyStringConverter() {
|
||||
if (companyStringConverter == null) {
|
||||
companyStringConverter = getBean(CompanyStringConverter.class);
|
||||
}
|
||||
return companyStringConverter;
|
||||
}
|
||||
|
||||
private CompanyCustomerService getCompanyCustomerService() {
|
||||
if (customerService == null) {
|
||||
customerService = getBean(CompanyCustomerService.class);
|
||||
}
|
||||
return customerService;
|
||||
}
|
||||
|
||||
private CompanyCustomerFileService getCompanyCustomerFileService() {
|
||||
if (customerFileService == null) {
|
||||
customerFileService = getBean(CompanyCustomerFileService.class);
|
||||
}
|
||||
return customerFileService;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user