一周目存档

main 0.0.1
lensfrex 2 years ago
commit b663130083
Signed by: lensfrex
GPG Key ID: 0F69A0A2FBEE98A0
  1. 107
      .gitignore
  2. 43
      README.md
  3. 140
      disillusion-client-jfx17/pom.xml
  4. 48
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/ClientMain.java
  5. 104
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/config/Constants.java
  6. 8
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/CommunicativeController.java
  7. 180
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/LoginMainController.java
  8. 54
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/ComponentFactory.java
  9. 32
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/application/ApplicationDealPane.java
  10. 96
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/application/ApplicationListItem.java
  11. 75
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/application/ApplicationListPage.java
  12. 106
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/application/ApplicationOfferCard.java
  13. 24
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/application/ApplicationTableItem.java
  14. 69
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/application/ResumeDownloadPane.java
  15. 90
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/application/StudentInfoPage.java
  16. 134
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/offer/EmployerOfferCard.java
  17. 93
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/employer/offer/EmployerOfferDetailPane.java
  18. 140
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/student/application/ApplicationCard.java
  19. 83
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/student/application/ApplicationPostPane.java
  20. 119
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/student/offer/EmployerInfoPage.java
  21. 95
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/student/offer/OfferDetailPane.java
  22. 174
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/student/offer/StudentOfferCard.java
  23. 172
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/student/resume/ResumeCard.java
  24. 95
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/components/student/resume/ResumeUploadPane.java
  25. 91
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/employer/EmployerApplicationManagePage.java
  26. 136
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/employer/EmployerMainController.java
  27. 114
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/employer/EmployerOfferManagePage.java
  28. 206
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/employer/EmployerProfilePage.java
  29. 106
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/student/ApplicationManagePage.java
  30. 204
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/student/OfferSquarePage.java
  31. 194
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/student/ResumeManagePage.java
  32. 174
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/student/StudentMainController.java
  33. 235
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/controller/page/student/StudentProfilePage.java
  34. 45
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/ResponseCode.java
  35. 20
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/request/ApplicationRequest.java
  36. 36
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/request/OfferPublishRequest.java
  37. 21
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/request/ResumeRequest.java
  38. 37
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/response/ApplicationResponse.java
  39. 41
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/response/EmployerInfoResponse.java
  40. 61
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/response/OfferResponse.java
  41. 40
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/response/PublicEmployerInfoResponse.java
  42. 38
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/response/PublicStudentInfoResponse.java
  43. 31
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/response/ResumeResponse.java
  44. 43
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/data/response/StudentInfoResponse.java
  45. 8
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/util/Consumer.java
  46. 130
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/util/DialogMaker.java
  47. 20
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/util/ImageUtil.java
  48. 173
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/util/OkhttpUtil.java
  49. 72
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/util/ResponseHandler.java
  50. 43
      disillusion-client-jfx17/src/main/java/net/lensfrex/disillusion/client/util/ThreadSafeDialogMaker.java
  51. 3
      disillusion-client-jfx17/src/main/resources/META-INF/MANIFEST.MF
  52. 13
      disillusion-client-jfx17/src/main/resources/exampleFile.txt
  53. 60
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/css/style.css
  54. 32
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/application/applicationDealPane.fxml
  55. 55
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/application/applicationListItem.fxml
  56. 15
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/application/applicationListPage.fxml
  57. 57
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/application/applicationManagePage.fxml
  58. 50
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/application/applicationOfferCard.fxml
  59. 22
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/application/resumeDownloadPane.fxml
  60. 174
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/application/studentProfile.fxml
  61. 113
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/employerMain.fxml
  62. 59
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/offer/offerCard.fxml
  63. 110
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/offer/offerDetailPane.fxml
  64. 53
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/offer/offerManagePage.fxml
  65. 183
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/employer/profile.fxml
  66. 89
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/loginMain.fxml
  67. 59
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/application/applicationCard.fxml
  68. 42
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/application/applicationManagePage.fxml
  69. 22
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/application/applicationPost.fxml
  70. 22
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/application/applicationPostPage.fxml
  71. 170
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/offer/employerProfile.fxml
  72. 78
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/offer/offerCard.fxml
  73. 131
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/offer/offerDetail.fxml
  74. 67
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/offer/offerSquare.fxml
  75. 218
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/profile.fxml
  76. 59
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/resume/resumeCard.fxml
  77. 53
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/resume/resumeManagePage.fxml
  78. 77
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/resume/resumeUpload.fxml
  79. 121
      disillusion-client-jfx17/src/main/resources/net/lensfrex/disillusion/client/fxml/student/studentMain.fxml
  80. 67
      disillusion/.gitignore
  81. 101
      disillusion/backend/.flattened-pom.xml
  82. 170
      disillusion/backend/pom.xml
  83. 13
      disillusion/backend/src/main/java/net/lensfrex/disillusion/BackendMain.java
  84. 24
      disillusion/backend/src/main/java/net/lensfrex/disillusion/DocumentMain.java
  85. 10
      disillusion/backend/src/main/java/net/lensfrex/disillusion/annotation/CheckAuth.java
  86. 24
      disillusion/backend/src/main/java/net/lensfrex/disillusion/configure/ApplicationContextHelper.java
  87. 24
      disillusion/backend/src/main/java/net/lensfrex/disillusion/configure/GlobalConfigure.java
  88. 38
      disillusion/backend/src/main/java/net/lensfrex/disillusion/configure/InterceptorConfigure.java
  89. 35
      disillusion/backend/src/main/java/net/lensfrex/disillusion/configure/SwaggerConfigure.java
  90. 83
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/DaoBase.java
  91. 14
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/OfferApplicationTable.java
  92. 12
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/OfferStatusTable.java
  93. 14
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/OfferTable.java
  94. 14
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/ResumeTable.java
  95. 14
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/UserInfoTable.java
  96. 14
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/UserTable.java
  97. 16
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/index/EmployerOfferIndex.java
  98. 15
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/index/StudentResumeIndex.java
  99. 15
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/index/application/EmployerApplicationIndex.java
  100. 15
      disillusion/backend/src/main/java/net/lensfrex/disillusion/dao/index/application/OfferApplicationIndex.java
  101. Some files were not shown because too many files have changed in this diff Show More

107
.gitignore vendored

@ -0,0 +1,107 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
.mvn
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
*/.flattened-pom.xml
/.flattened-pom.xml
out
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
*.log
*.class
mvnw
mvnw.cmd
/database/
/delombok/
*/.mvn

@ -0,0 +1,43 @@
# disillusion
某个课设的完整工程代码
其实核心就只是后端部分模拟的数据库以及后端对数据的处理
用的是java
写得不咋的,纯纯的答辩
一大堆东西只是写着玩的,基本上就是写着写着写嗨了的产物
这里的git仓库是一周目的存档,原仓库是分开来的,这里都放到了一起
以后基本上不会再碰这个东西了
嘛,反正也没人看
---
环境要求:
后端:
- Java 17+
客户端:
- Java 17+,带Javafx SDK运行环境
---
关于客户端的运行
由于Java高版本(8+后版本以及大部分openjdk发行版)将javafx库从标准库中分离成为了独立项目,因此如要运行客户端,需要手动加上jvm运行参数:
`--module-path "./javafx-sdk/lib" --add-modules javafx.controls,javafx.fxml --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-exports javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED`
可参见:[【Java】错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序 的解决方案](https://blog.csdn.net/weixin_44746306/article/details/117768300)
Javafx sdk可在:[JavaFX](https://gluonhq.com/products/javafx/)下载
当然,也可以[直接下载release](https://git.ciduid.top/lensfrex/disillusion-archive/releases)
~~真的会有人看来吗?~~

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.lensfrex</groupId>
<artifactId>disillusion-client-jfx11</artifactId>
<version>1.0-SNAPSHOT</version>
<name>disillusion-client-jfx11</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.9.1</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.jfoenix/jfoenix -->
<dependency>
<groupId>com.jfoenix</groupId>
<artifactId>jfoenix</artifactId>
<version>9.0.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.13</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-json</artifactId>
<version>5.8.12</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-crypto</artifactId>
<version>5.8.13</version>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.19</version>
</dependency>
<dependency>
<groupId>io.github.typhon0</groupId>
<artifactId>AnimateFX</artifactId>
<version>1.2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx</artifactId>
<version>17</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>17</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>net.lensfrex.disillusion.client.ClientMain</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>com.gluonhq</groupId>
<artifactId>gluonfx-maven-plugin</artifactId>
<version>1.0.16</version>
<configuration>
<target>host</target>
<mainClass>net.lensfrex.disillusion.client.ClientMain</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,48 @@
package net.lensfrex.disillusion.client;
import cn.hutool.core.thread.ThreadUtil;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.LoginMainController;
import okhttp3.OkHttpClient;
import java.io.File;
import java.io.IOException;
public class ClientMain extends Application {
private static final OkHttpClient okhttp = Constants.globalClient;
private static Stage stage;
public static Stage getStage() {
return stage;
}
@Override
public void start(Stage stage) throws IOException {
ClientMain.stage = stage;
// 抗锯齿
System.setProperty("prism.lcdtext", "false");
File tokenFile = new File(Constants.tokenFile);
if (tokenFile.exists()) {
}
FXMLLoader fxmlLoader = new FXMLLoader(ClientMain.class.getResource("fxml/loginMain.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 1000, 600);
stage.setTitle("disillusion - login");
stage.setScene(scene);
stage.show();
LoginMainController loginMainController = fxmlLoader.getController();
loginMainController.setMainStage(stage);
}
public static void main(String[] args) {
launch();
}
}

@ -0,0 +1,104 @@
package net.lensfrex.disillusion.client.config;
import okhttp3.OkHttpClient;
import java.net.InetSocketAddress;
import java.net.Proxy;
public class Constants {
public static final String tokenFile = "token";
public static final String numberPattern = "^\\d+$";
// public static final OkHttpClient globalClient = new OkHttpClient.Builder()
// .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 8080)))
// .build();
public static final OkHttpClient globalClient = new OkHttpClient();
public static final String SERVER_ADDRESS = "http://127.0.0.1:8888";
public static final String BASE_URL = "/api";
public static class UserRequestUrls {
public static final String LOGIN_URL = SERVER_ADDRESS + BASE_URL + "/user/login";
public static final String REGISTER_URL = SERVER_ADDRESS + BASE_URL + "/user/register";
public static final String TOKEN_REFRESH_URL = SERVER_ADDRESS + BASE_URL + "/user/refresh";
public static final String USER_INFO_EDIT_URL = SERVER_ADDRESS + BASE_URL + "/user/info/edit";
public static final String USER_INFO_VIEW_URL = SERVER_ADDRESS + BASE_URL + "/user/info/view";
public static final String USER_PUBLIC_INFO_VIEW_URL = SERVER_ADDRESS + BASE_URL + "/user/info/view/public";
public static final String USER_AVATAR_VIEW_URL = SERVER_ADDRESS + BASE_URL + "/user/info/avatar";
public static final String USER_AVATAR_EDIT_URL = SERVER_ADDRESS + BASE_URL + "/user/info/avatar/upload";
}
public static class ResumeRequestUrls {
public static final String RESUME_UPLOAD_URL = SERVER_ADDRESS + BASE_URL + "/student/resume/add";
public static final String RESUME_GET_ALL_URL = SERVER_ADDRESS + BASE_URL + "/student/resume/all";
public static final String RESUME_DELETE_URL = SERVER_ADDRESS + BASE_URL + "/student/resume/delete";
public static final String RESUME_FILE_URL = SERVER_ADDRESS + BASE_URL + "/student/resume/getFile";
public static final String RESUME_UPDATE_URL = SERVER_ADDRESS + BASE_URL + "/student/resume/update";
public static final String RESUME_VIEW_URL = SERVER_ADDRESS + BASE_URL + "/student/resume/view";
}
public static class ApplicationRequestUrls {
public static final String APPLICATION_PUBLISH_URL = SERVER_ADDRESS + BASE_URL + "/student/application/publish";
public static final String APPLICATION_DELETE_URL = SERVER_ADDRESS + BASE_URL + "/student/application/delete";
public static final String APPLICATION_STUDENT_VIEW_URL = SERVER_ADDRESS + BASE_URL + "/student/application/view";
public static final String APPLICATION_EMPLOYER_VIEW_URL = SERVER_ADDRESS + BASE_URL + "/employer/application/view";
public static final String APPLICATION_DEAL_URL = SERVER_ADDRESS + BASE_URL + "/employer/application/deal";
}
public static class OfferRequestUrls {
public static final String OFFER_FILTER_EMPLOYER = "by_employer";
public static final String OFFER_FILTER_JOB_NAME = "by_job_name";
public static final String OFFER_FILTER_SALARY = "by_salary";
public static final String GET_ALL_OFFER_URL = SERVER_ADDRESS + BASE_URL + "/offer/getAll";
public static final String GET_OFFER_URL = SERVER_ADDRESS + BASE_URL + "/offer/get";
public static final String OFFER_PROGRESS_URL = SERVER_ADDRESS + BASE_URL + "/offer/progress";
public static final String OFFER_GET_BY_EMPLOYER_SELF_URL = SERVER_ADDRESS + BASE_URL + "/employer/offer/view";
public static final String OFFER_DELETE_URL = SERVER_ADDRESS + BASE_URL + "/employer/offer/delete";
public static final String OFFER_PUBLISH_URL = SERVER_ADDRESS + BASE_URL + "/employer/offer/publish";
public static final String OFFER_UPDATE_URL = SERVER_ADDRESS + BASE_URL + "/employer/offer/update";
public static final String OFFER_SEARCH_URL = SERVER_ADDRESS + BASE_URL + "/offer/search";
}
public static final String USER_TYPE_STUDENT = "0";
public static final String USER_TYPE_EMPLOYER = "1";
public static final String sample = " 前期经过自愿报名并审核成功的学生,根据所报微专业的培养方案,自行选择相应课程。\n" +
"\n" +
" 9.认真对照培养方案,选课时务必仔细核对课程信息,确保“课程代码”、“课程名称”、“学分”这三项重要信息与培养方案要求相符。\n" +
"\n" +
" 10.禁止同一时间修读两门及以上课程,系统会提示时间冲突并禁止选课。提前了解专业教学进程(实习、实践、课程设计等)情况,不能选择与本专业其它教学任务周次有冲突的课堂。\n" +
"\n" +
" 11.因培养方案变动、转专业等原因,计划修读的课程确定不再开课的,请先查询本科生课程学分认定对照表并咨询开课学院,再进行选课。待课程修读完获得学分后,再按照本科生院发布的相关要求办理学分认定。\n" +
"\n" +
" 12.学生选课、听课、考核必须一致。学生不能参加未选择课程的学习和考核,即使参加了学习和考核,如果没有选课,也是无效的,将不记录成绩。\n" +
"\n" +
" 13.学生凭学号、密码选课,认真对待,并对自己的选课行为负责。密码必须妥善保管,不得代替他人选课,不得借用、盗用他人学号及密码选课。\n" +
"\n" +
" 14.学生登录本科教学综合管理系统需通过学校统一身份认证平台登录,登录方式、密码重置方式详见以下两个通知:https://jwc.wust.edu.cn/2022/0226/c1925a255654/page.htm、https://jwc.wust.edu.cn/2022/0302/c1925a255786/page.htm。";
public static class Svg {
public static final String deleteSvg = "M96 128h832v64H96zM128 256h768l-89.024 704H217.024z M384 64h256v96h-256z";
public static final String sendSvg =
"M1008 6.286q18.857 13.714 15.429 36.571l-146.286 877.714q-2.857 16.571-18.286 25.714-8 4.571-17.714 4.571-6.286 " +
"0-13.714-2.857l-258.857-105.714-138.286 168.571q-10.286 13.143-28 13.143-7.429 " +
"0-12.571-2.286-10.857-4-17.429-13.429t-6.571-20.857v-199.429l493.714-605.143-610.857 " +
"528.571-225.714-92.571q-21.143-8-22.857-31.429-1.143-22.857 18.286-33.714l950.857-548.571q8.571-5.143 18.286-5.143 " +
"11.429 0 20.571 6.286z";
public static final String viewSvg =
"M320.06 255.58m28 0l328.07 0q28 0 28 28l0 0q0 28-28 28l-328.07 0q-28 0-28-28l0 0q0-28 28-28Z " +
"M320.06 420.21m28 0l200.42 0q28 0 28 28l0 0q0 28-28 28l-200.42 0q-28 0-28-28l0 0q0-28 28-28Z " +
"M888.35 320h-56.19V135.61a72 72 0 0 0-72-72H264a72 72 0 0 0-72 72V320h-55.79a72 72 0 0 0-72 72v496.22a72 72 0 0 0 72 72h752.14a72 72 0 0 0 72-72V392a72 72 0 0 0-72-72z m0 72v47.59c-0.53 0.27-1.05 0.56-1.57 0.86L832.16 472v-80zM264 135.61h496.16v377l-151.33 88.31-96.55 55.74L264 513.33V135.61zM192 392v79.77l-55.83-32.24V392z m-55.79 496.22V522.67l56.2 32.45 298 173A43 43 0 0 0 502 732.7a35.88 35.88 0 0 0 9.52 1.51h1.61a35.58 35.58 0 0 0 11.65-2.21 42.58 42.58 0 0 0 9-3.94L645 663.17l243.35-140.5v365.55z";
}
}

@ -0,0 +1,8 @@
package net.lensfrex.disillusion.client.controller;
// 可通信的Controller
public interface CommunicativeController<T extends CommunicativeController.InitData> {
void loadData(T initData);
void initialize();
class InitData {}
}

@ -0,0 +1,180 @@
package net.lensfrex.disillusion.client.controller;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jfoenix.controls.*;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.ClientMain;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.page.employer.EmployerMainController;
import net.lensfrex.disillusion.client.controller.page.student.StudentMainController;
import net.lensfrex.disillusion.client.util.Consumer;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import java.net.URL;
@Slf4j
public class LoginMainController {
@FXML
private StackPane rootPane;
@FXML
private JFXTextField usernameTextField;
@FXML
private JFXPasswordField passwordTextField;
private ThreadSafeDialogMaker dialogMaker;
private Stage mainStage;
public void initialize() {
dialogMaker = new ThreadSafeDialogMaker(rootPane);
}
public void setMainStage(Stage mainStage) {
this.mainStage = mainStage;
}
@FXML
void doLogin(ActionEvent event) {
new OkhttpUtil().url(Constants.UserRequestUrls.LOGIN_URL)
.form("username", usernameTextField.getText())
.form("password", passwordTextField.getText())
.failCallback(e -> Platform.runLater(() -> {
dialogMaker.createMessageDialog("啊哈", "登录时发生了网络问题:\n" + e);
}))
.successCallback(loginSuccessCallback)
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
private final Consumer<Response> loginSuccessCallback = response -> {
ResponseHandler.Result result = ResponseHandler.parse(response, s -> dialogMaker.createMessageDialog("啊哈", nullSafe(s)));
if (!result.success) {
return;
}
JSONObject data = JSONUtil.parseObj(result.data);
String token = data.getStr("token");
String userType = data.getStr("user_type");
switch (userType) {
case "0" -> Platform.runLater(() -> this.jumpStudentMainWindow(usernameTextField.getText(), token));
case "1" -> Platform.runLater(() -> this.jumpEmployMainWindow(usernameTextField.getText(), token));
}
};
private static final URL studentMainWindowUrl = ClientMain.class.getResource("fxml/student/studentMain.fxml");
private static final URL employerMainWindowUrl = ClientMain.class.getResource("fxml/employer/employerMain.fxml");
private void jumpStudentMainWindow(String username, String token) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(studentMainWindowUrl);
Scene scene = new Scene(fxmlLoader.load(), 1572, 832);
mainStage.setScene(scene);
scene.getStylesheets().add(ClientMain.class.getResource("css/style.css").toExternalForm());
StudentMainController.InitData initData = StudentMainController.InitData.builder()
.username(username)
.token(token)
.build();
StudentMainController controller = fxmlLoader.getController();
controller.setData(initData);
mainStage.setTitle("disillusion - student");
mainStage.setOnCloseRequest(v -> System.exit(0));
mainStage.setX(100);
mainStage.setY(100);
mainStage.show();
} catch (Exception e) {
e.printStackTrace();
dialogMaker.createMessageDialog("Oppos...😱>︿<", "程序内部出错...请联系@lensfrex这家伙\n调试信息:\n" + e);
}
}
private void jumpEmployMainWindow(String username, String token) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(employerMainWindowUrl);
Scene scene = new Scene(fxmlLoader.load(), 1572, 832);
mainStage.setScene(scene);
scene.getStylesheets().add(ClientMain.class.getResource("css/style.css").toExternalForm());
EmployerMainController controller = fxmlLoader.getController();
controller.setData(token);
mainStage.setTitle("disillusion - employer");
mainStage.setOnCloseRequest(v -> System.exit(0));
mainStage.setX(100);
mainStage.setY(100);
mainStage.show();
} catch (Exception e) {
e.printStackTrace();
dialogMaker.createMessageDialog("Oppos...😱>︿<", "程序内部出错...请联系@lensfrex这家伙\n调试信息:\n" + e);
}
}
@FXML
void doRegister(ActionEvent event) {
JFXRadioButton studentChoice = new JFXRadioButton("学生");
studentChoice.setUserData(Constants.USER_TYPE_STUDENT);
JFXRadioButton employerChoice = new JFXRadioButton("用人单位");
employerChoice.setUserData(Constants.USER_TYPE_EMPLOYER);
ToggleGroup userTypeGroup = new ToggleGroup();
studentChoice.setToggleGroup(userTypeGroup);
employerChoice.setToggleGroup(userTypeGroup);
userTypeGroup.selectToggle(studentChoice);
VBox choiceBox = new VBox(studentChoice, employerChoice);
choiceBox.setSpacing(10);
JFXButton cancelButton = new JFXButton("取消");
JFXButton okButton = new JFXButton("好的");
okButton.setOnAction(actionEvent -> {
String userTypeString = userTypeGroup.getSelectedToggle().getUserData().toString();
this.register(userTypeString);
});
dialogMaker.createDialog("选择要注册的用户类型", choiceBox, cancelButton, okButton);
}
private void register(String userTypeString) {
new OkhttpUtil()
.url(Constants.UserRequestUrls.REGISTER_URL)
.form("username", usernameTextField.getText())
.form("password", passwordTextField.getText())
.form("userType", userTypeString)
.failCallback(e -> {
dialogMaker.createMessageDialog("啊哈", "注册时发生了网络问题:\n" + e);
})
.successCallback(response -> {
ResponseHandler.Result result = ResponseHandler.parse(response, msg -> dialogMaker.createMessageDialog("啊哈", nullSafe(msg)));
if (!result.success) {
return;
}
dialogMaker.createMessageDialog("Message", "好了");
})
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
private static String nullSafe(String str) {
return str == null ? "null" : str;
}
}

@ -0,0 +1,54 @@
package net.lensfrex.disillusion.client.controller.components;
import com.jfoenix.svg.SVGGlyph;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
import javafx.util.Duration;
import net.lensfrex.disillusion.client.ClientMain;
import net.lensfrex.disillusion.client.controller.components.employer.offer.EmployerOfferDetailPane;
import java.io.IOException;
import static javafx.animation.Interpolator.EASE_BOTH;
public class ComponentFactory {
public static <T extends Node> T loadComponent(String location, Class<T> clazz)
throws IOException, InstantiationException, IllegalAccessException {
T controller = clazz.newInstance();
return loadComponent(location, controller);
}
public static <T extends Node> T loadComponent(String location, T controller)
throws IOException {
FXMLLoader loader = new FXMLLoader(ClientMain.class.getResource(location));
return loadComponent(loader, controller);
}
public static <T extends Node> T loadComponent(FXMLLoader loader, T controller)
throws IOException {
loader.setRoot(controller);
loader.setController(controller);
return loader.load();
}
public static void setCardIcon(Button button, String svg) {
SVGGlyph glyph = new SVGGlyph(-1, "send", svg, Color.WHITE);
glyph.setSize(20, 20);
button.setGraphic(glyph);
Timeline animation = new Timeline(new KeyFrame(Duration.millis(240),
new KeyValue(button.scaleXProperty(), 1, EASE_BOTH),
new KeyValue(button.scaleYProperty(), 1, EASE_BOTH)));
animation.setDelay(Duration.millis(100 + 100));
animation.play();
}
}

@ -0,0 +1,32 @@
package net.lensfrex.disillusion.client.controller.components.employer.application;
import com.jfoenix.controls.JFXRadioButton;
import javafx.fxml.FXML;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
public class ApplicationDealPane extends VBox {
@FXML
private JFXRadioButton acceptRadioButton;
@FXML
private JFXRadioButton rejectRadioButton;
private final ToggleGroup opinionGroup = new ToggleGroup();
public void initialize() {
acceptRadioButton.setToggleGroup(opinionGroup);
acceptRadioButton.setUserData("accept");
rejectRadioButton.setToggleGroup(opinionGroup);
rejectRadioButton.setUserData("reject");
opinionGroup.selectToggle(acceptRadioButton);
}
public String getOpinion() {
return (String) opinionGroup.getSelectedToggle().getUserData();
}
}

@ -0,0 +1,96 @@
package net.lensfrex.disillusion.client.controller.components.employer.application;
import cn.hutool.json.JSONUtil;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.data.response.ApplicationResponse;
import net.lensfrex.disillusion.client.data.response.PublicStudentInfoResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.IOException;
@Slf4j
public class ApplicationListItem extends HBox {
private final ApplicationResponse application;
private final ThreadSafeDialogMaker dialogMaker;
private final String token;
private PublicStudentInfoResponse studentInfo;
@FXML
private Text studentNameText;
@FXML
private Text describeText;
public ApplicationListItem(ApplicationResponse application,
ThreadSafeDialogMaker dialogMaker, String token) {
this.application = application;
this.dialogMaker = dialogMaker;
this.token = token;
}
public void initialize() {
this.getStudentInfo();
}
private void getStudentInfo() {
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_PUBLIC_INFO_VIEW_URL)
.addQueryParam("user", application.getPublisherId())
.failCallback(e -> log.warn("获取学生信息时发生网络错误:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> log.warn("获取学生信息不成功:\n" + s))
.successCallback(s -> {
studentInfo = JSONUtil.toBean(s, PublicStudentInfoResponse.class);
studentNameText.setText(studentInfo.getRealName());
describeText.setText(studentInfo.getShortDescribe());
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
@FXML
void dealApplication(ActionEvent event) throws IOException, InstantiationException, IllegalAccessException {
ApplicationDealPane dealPane = ComponentFactory.loadComponent("fxml/employer/application/applicationDealPane.fxml",
ApplicationDealPane.class);
dialogMaker.createDialogWithOKAndCancel("处理Offer申请", dealPane, event1 -> this.dealApplication(dealPane.getOpinion()));
}
private void dealApplication(String opinion) {
new OkhttpUtil()
.url(Constants.ApplicationRequestUrls.APPLICATION_DEAL_URL)
.token(token)
.addQueryParam("id", application.getId())
.addQueryParam("opinion", opinion)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "处理offer申请时出现网络错误:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "处理offer申请失败:\n" + s))
.successCallback(s -> dialogMaker.createMessageDialog("好好好", "处理offer申请成功:\n" + opinion))
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
@FXML
void viewResume(ActionEvent event) throws IOException {
ResumeDownloadPane downloadPane = ComponentFactory.loadComponent("fxml/employer/application/resumeDownloadPane.fxml",
new ResumeDownloadPane(application.getResumeId(), studentInfo.getRealName(), dialogMaker, token));
dialogMaker.createDialogWithOneBtn("下载简历", downloadPane);
}
@FXML
void viewStudentInfo(MouseEvent event) throws IOException {
StudentInfoPage page = ComponentFactory.loadComponent("fxml/employer/application/studentProfile.fxml",
new StudentInfoPage(studentInfo));
dialogMaker.createDialogWithOneBtn("学生信息", page);
}
}

@ -0,0 +1,75 @@
package net.lensfrex.disillusion.client.controller.components.employer.application;
import cn.hutool.json.JSONUtil;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.data.response.ApplicationResponse;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.IOException;
import java.util.List;
@Slf4j
public class ApplicationListPage extends StackPane {
@FXML
private VBox applicationContainer;
private final OfferResponse offer;
private final ThreadSafeDialogMaker dialogMaker;
private final String token;
public ApplicationListPage(ThreadSafeDialogMaker dialogMaker, String token, OfferResponse offer) {
this.dialogMaker = dialogMaker;
this.token = token;
this.offer = offer;
}
public void initialize() {
new OkhttpUtil()
.url(Constants.ApplicationRequestUrls.APPLICATION_EMPLOYER_VIEW_URL)
.token(token)
.addQueryParam("offer_id", offer.getId())
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "获取求职申请列表时发生了网络问题:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "获取求职申请不成功:\n" + s))
.successCallback(s -> Platform.runLater(() -> this.showApplicationList(s)))
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void showApplicationList(String jsonData) {
try {
List<ApplicationResponse> applications = JSONUtil.toList(jsonData, ApplicationResponse.class);
if (applications.isEmpty()) {
Text text = new Text("这里空空如也...");
text.setFont(Font.font(20));
applicationContainer.getChildren().add(text);
}
ObservableList<ApplicationListItem> items = FXCollections.observableArrayList();
for (ApplicationResponse application : applications) {
ApplicationListItem item = ComponentFactory.loadComponent("fxml/employer/application/applicationListItem.fxml",
new ApplicationListItem(application, dialogMaker, token));
items.add(item);
}
applicationContainer.getChildren().addAll(items);
} catch (IOException e) {
e.printStackTrace();
log.error("加载offer申请页面时出错");
}
}
}

@ -0,0 +1,106 @@
package net.lensfrex.disillusion.client.controller.components.employer.application;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
@Slf4j
public class ApplicationOfferCard extends StackPane {
private final OfferResponse offer;
private ThreadSafeDialogMaker dialogMaker;
private String token;
private static final String[] colors = new String[]{
"-fx-background-color: #8F3F7E",
"-fx-background-color: #B5305F",
"-fx-background-color: #CE584A",
"-fx-background-color: #DB8D5C",
"-fx-background-color: #DA854E",
"-fx-background-color: #E9AB44",
"-fx-background-color: #99C286",
"-fx-background-color: #01A05E",
"-fx-background-color: #4A8895",
"-fx-background-color: #16669B",
"-fx-background-color: #2F65A5",
};
public ApplicationOfferCard(OfferResponse offer) {
this.setUserData(offer);
this.offer = offer;
}
public void loadData(String token, ThreadSafeDialogMaker dialogMaker) {
this.token = token;
this.dialogMaker = dialogMaker;
// 查询offer招募进度
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_PROGRESS_URL)
.token(token)
.addQueryParam("id", offer.getId())
.failCallback(e -> log.warn("获取offer进度时出现网络错误:", e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> log.warn("获取offer进度不成功:" + s))
.successCallback(s -> processText.setText("招募进度:" + s))
.process()
)
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
public void initialize() {
String color = colors[Math.abs(offer.getJobName().hashCode()) % colors.length];
header.setStyle(header.getStyle() + color);
jobName.setText(offer.getJobName());
}
@FXML
private StackPane rootPane;
@FXML
private StackPane header;
@FXML
private Label jobName;
@FXML
private StackPane body;
@FXML
private Text processText;
@FXML
void viewApplications(MouseEvent event) {
new OkhttpUtil()
.url(Constants.ApplicationRequestUrls.APPLICATION_EMPLOYER_VIEW_URL)
.token(token)
.addQueryParam("offer_id", offer.getId())
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "获取求职申请列表时发生了网络问题:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "获取求职申请不成功:\n" + s))
.successCallback(s -> showApplicationListPage())
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void showApplicationListPage() {
try {
ApplicationListPage applicationListPage = ComponentFactory.loadComponent("fxml/employer/application/applicationListPage.fxml",
new ApplicationListPage(dialogMaker, token, offer));
dialogMaker.createDialogWithOneBtn(String.format("投递给 '%s' 的求职申请", offer.getJobName()), applicationListPage);
} catch (Exception e) {
log.error("显示简历申请列表页面时出错", e);
}
}
}

@ -0,0 +1,24 @@
package net.lensfrex.disillusion.client.controller.components.employer.application;
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import net.lensfrex.disillusion.client.data.response.ApplicationResponse;
import net.lensfrex.disillusion.client.data.response.PublicStudentInfoResponse;
public class ApplicationTableItem extends RecursiveTreeObject<ApplicationTableItem> {
private final ApplicationResponse application;
private final PublicStudentInfoResponse student;
public ApplicationTableItem(ApplicationResponse application, PublicStudentInfoResponse student) {
this.application = application;
this.student = student;
}
public ApplicationResponse getApplication() {
return application;
}
public PublicStudentInfoResponse getStudent() {
return student;
}
}

@ -0,0 +1,69 @@
package net.lensfrex.disillusion.client.controller.components.employer.application;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class ResumeDownloadPane extends VBox {
@FXML
private VBox rootPane;
private final String fileId;
private final String fileName;
private final ThreadSafeDialogMaker dialogMaker;
private final String token;
public ResumeDownloadPane(String fileId, String fileName, ThreadSafeDialogMaker dialogMaker, String token) {
this.fileId = fileId;
this.fileName = fileName;
this.dialogMaker = dialogMaker;
this.token = token;
}
@FXML
void download(ActionEvent event) {
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setTitle("要将简历文件保存到哪?");
File saveFile = directoryChooser.showDialog(rootPane.getScene().getWindow());
if (saveFile == null) {
return;
}
downloadResume(saveFile.getAbsolutePath(), fileName);
}
private void downloadResume(String saveDir, String fileName) {
Path target = Paths.get(saveDir, fileName);
new OkhttpUtil()
.url(Constants.ResumeRequestUrls.RESUME_FILE_URL)
.addHeader("token", token)
.addQueryParam("id", fileId)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "下载简历文件时出现网络问题:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "下载简历文件不成功:" + s))
.successCallback(bytes -> {
Files.write(target, Base64.decode(bytes), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
Path saved = FileUtil.rename(target,
String.format("%s_%s.%s", fileName, fileId, FileUtil.getType(target.toFile())),
true);
dialogMaker.createMessageDialog("好好好", "下载完成,保存至:\n" + saved);
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
}

@ -0,0 +1,90 @@
package net.lensfrex.disillusion.client.controller.components.employer.application;
import com.jfoenix.controls.JFXTextArea;
import com.jfoenix.controls.JFXTextField;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.data.response.PublicStudentInfoResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import okhttp3.Response;
import java.io.ByteArrayInputStream;
@Slf4j
public class StudentInfoPage extends HBox {
@FXML
private HBox rootPane;
@FXML
private ImageView avatarImageView;
@FXML
private Text usernameText;
@FXML
private Text signText;
@FXML
private JFXTextField realNameTextField;
@FXML
private JFXTextField ageTextField;
@FXML
private Text sexText;
@FXML
private JFXTextField contactTextField;
@FXML
private JFXTextField signTextField;
@FXML
private JFXTextArea describeTextArea;
private final PublicStudentInfoResponse studentInfo;
public StudentInfoPage(PublicStudentInfoResponse studentInfo) {
this.studentInfo = studentInfo;
}
@FXML
public void initialize() {
realNameTextField.setText(studentInfo.getRealName());
signText.setText(studentInfo.getShortDescribe());
signTextField.setText(studentInfo.getShortDescribe());
describeTextArea.setText(studentInfo.getDescribe());
contactTextField.setText(studentInfo.getPhoneNumber());
ageTextField.setText(String.valueOf(studentInfo.getAge()));
sexText.setText(studentInfo.getSex() == 0 ? "男" : "女");
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_VIEW_URL)
.addQueryParam("user", studentInfo.getId())
.failCallback(e -> log.warn("获取头像时发生网络错误:\n" + e))
.successCallback(response -> Platform.runLater(() -> setAvatar(avatarImageView, response)))
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
public static void setAvatar(ImageView avatarImageView, Response response) {
try {
assert response.body() != null;
byte[] data = response.body().bytes();
setAvatar(avatarImageView, data);
} catch (Exception e) {
log.warn("获取头像数据时出现异常", e);
}
}
public static void setAvatar(ImageView avatarImageView, byte[] data) {
Image avatarImage = new Image(new ByteArrayInputStream(data));
avatarImageView.setImage(avatarImage);
}
}

@ -0,0 +1,134 @@
package net.lensfrex.disillusion.client.controller.components.employer.offer;
import com.jfoenix.controls.JFXButton;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.data.request.OfferPublishRequest;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.util.Consumer;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.IOException;
@Slf4j
public class EmployerOfferCard extends StackPane {
private final OfferResponse offer;
private ThreadSafeDialogMaker dialogMaker;
private String token;
private Consumer<String> deleteCallback;
private Consumer<String> updateCallback;
private static final String[] colors = new String[]{
"-fx-background-color: #8F3F7E",
"-fx-background-color: #B5305F",
"-fx-background-color: #CE584A",
"-fx-background-color: #DB8D5C",
"-fx-background-color: #DA854E",
"-fx-background-color: #E9AB44",
"-fx-background-color: #99C286",
"-fx-background-color: #01A05E",
"-fx-background-color: #4A8895",
"-fx-background-color: #16669B",
"-fx-background-color: #2F65A5",
};
public EmployerOfferCard(OfferResponse offer) {
this.setUserData(offer);
this.offer = offer;
}
public void loadData(String token, ThreadSafeDialogMaker dialogMaker,
Consumer<String> deleteCallback, Consumer<String> updateCallback) {
this.token = token;
this.dialogMaker = dialogMaker;
this.deleteCallback = deleteCallback;
this.updateCallback = updateCallback;
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_PROGRESS_URL)
.token(token)
.addQueryParam("id", offer.getId())
.failCallback(e -> log.warn("获取offer进度时出现网络错误:", e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> log.warn("获取offer进度不成功:" + s))
.successCallback(s -> processText.setText("招募进度:" + s))
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
public void initialize() {
String color = colors[Math.abs(offer.getJobName().hashCode()) % colors.length];
header.setStyle(header.getStyle() + color);
jobName.setText(offer.getJobName());
ComponentFactory.setCardIcon(offerDeleteBtn, Constants.Svg.deleteSvg);
}
@FXML
private StackPane rootPane;
@FXML
private StackPane header;
@FXML
private Label jobName;
@FXML
private StackPane body;
@FXML
private Text processText;
@FXML
private JFXButton offerDeleteBtn;
@FXML
void deleteOffer(ActionEvent event) {
dialogMaker.createDialogWithOKAndCancel("Really?", String.format("真的要删除Offer '%s'", offer.getJobName()), event1 -> new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_DELETE_URL)
.token(token)
.addQueryParam("id", offer.getId())
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "删除offer时出现网络问题:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "删除offer不成功:\n" + s))
.successCallback(deleteCallback)
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST)
);
}
@FXML
void viewDetail(MouseEvent event) throws IOException {
EmployerOfferDetailPane offerDetailPane =
ComponentFactory.loadComponent("fxml/employer/offer/offerDetailPane.fxml", new EmployerOfferDetailPane(offer));
dialogMaker.createDialogWithOKAndCancel("更新Offer信息", offerDetailPane, e -> this.updateOffer(offerDetailPane.getData()));
}
private void updateOffer(OfferPublishRequest offerPublishRequest) {
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_UPDATE_URL)
.token(token)
.addQueryParam("id", offer.getId())
.body(offerPublishRequest)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "更新offer信息时发生了网络问题:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "更新offer信息不成功:\n" + s))
.successCallback(s -> updateCallback.accept(s))
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
}

@ -0,0 +1,93 @@
package net.lensfrex.disillusion.client.controller.components.employer.offer;
import cn.hutool.core.util.RandomUtil;
import com.jfoenix.controls.JFXTextArea;
import com.jfoenix.controls.JFXTextField;
import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.data.request.OfferPublishRequest;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
public class EmployerOfferDetailPane extends VBox {
@FXML
private VBox rootPane;
@FXML
private JFXTextField jobNameTextField;
@FXML
private JFXTextField salaryTextField;
@FXML
private JFXTextField planNumberTextField;
@FXML
private JFXTextField placeTextField;
@FXML
private JFXTextField requirementTextField;
@FXML
private JFXTextArea detailTextArea;
private OfferResponse offer;
// 无参构造方法,勿删
public EmployerOfferDetailPane() {
}
public EmployerOfferDetailPane(OfferResponse offer) {
this.offer = offer;
}
public void initialize() {
if (offer == null) {
jobNameTextField.setText(RandomUtil.randomString(Constants.sample, RandomUtil.randomInt(3, 5)));
placeTextField.setText(RandomUtil.randomString(Constants.sample, RandomUtil.randomInt(3, 5)));
requirementTextField.setText(RandomUtil.randomString(Constants.sample, RandomUtil.randomInt(5, 10)));
salaryTextField.setText(RandomUtil.randomNumbers(5));
planNumberTextField.setText(RandomUtil.randomNumbers(2));
detailTextArea.setText(RandomUtil.randomString(Constants.sample, RandomUtil.randomInt(300, 700)));
return;
}
String jobName = offer.getJobName();
String place = offer.getPlace();
String requirement = offer.getRequirement();
Integer salary = offer.getSalary();
Integer targetNumber = offer.getTargetNumber();
String detail = offer.getDetail();
jobNameTextField.setText(jobName);
placeTextField.setText(place);
requirementTextField.setText(requirement);
salaryTextField.setText(salary.toString());
planNumberTextField.setText(targetNumber.toString());
detailTextArea.setText(detail);
}
public OfferPublishRequest getData() {
OfferPublishRequest request = new OfferPublishRequest();
request.setJobName(jobNameTextField.getText());
request.setPlace(placeTextField.getText());
request.setRequirement(requirementTextField.getText());
request.setDetail(detailTextArea.getText());
String targetNumberText = planNumberTextField.getText();
if (!targetNumberText.matches(Constants.numberPattern)) {
request.setTargetNumber(-1);
} else {
request.setTargetNumber(Integer.parseInt(targetNumberText));
}
String salaryText = salaryTextField.getText();
if (!salaryText.matches(Constants.numberPattern)) {
request.setSalary(-1);
} else {
request.setSalary(Integer.parseInt(salaryText));
}
return request;
}
}

@ -0,0 +1,140 @@
package net.lensfrex.disillusion.client.controller.components.student.application;
import cn.hutool.json.JSONUtil;
import com.jfoenix.controls.JFXButton;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.components.student.offer.OfferDetailPane;
import net.lensfrex.disillusion.client.data.response.ApplicationResponse;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.util.Consumer;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.IOException;
@Slf4j
public class ApplicationCard extends StackPane {
private static final String[] colors = new String[]{
"-fx-background-color: #8F3F7E",
"-fx-background-color: #B5305F",
"-fx-background-color: #CE584A",
"-fx-background-color: #DB8D5C",
"-fx-background-color: #DA854E",
"-fx-background-color: #E9AB44",
"-fx-background-color: #99C286",
"-fx-background-color: #01A05E",
"-fx-background-color: #4A8895",
"-fx-background-color: #16669B",
"-fx-background-color: #2F65A5",
};
private final String token;
private final ThreadSafeDialogMaker dialogMaker;
private final ApplicationResponse application;
private final Consumer<String> deleteCallback;
private OfferResponse offer;
public ApplicationCard(String token,
ThreadSafeDialogMaker dialogMaker,
ApplicationResponse application,
Consumer<String> deleteCallback) {
this.token = token;
this.dialogMaker = dialogMaker;
this.application = application;
this.deleteCallback = deleteCallback;
}
@FXML
private StackPane rootPane;
@FXML
private StackPane header;
@FXML
private Label jobName;
@FXML
private StackPane body;
@FXML
private Text statusText;
@FXML
private JFXButton applicationDeleteBtn;
public void initialize() {
String color = colors[Math.abs(application.getOfferId().hashCode()) % colors.length];
header.setStyle(header.getStyle() + color);
this.showJobName();
statusText.setText("状态:" + getStatusText(application.getStatus()));
if ("REJECTED".equals(application.getStatus())){
statusText.setFill(Color.valueOf("#C62828"));
} else if ("ACCEPTED".equals(application.getStatus())) {
statusText.setFill(Color.valueOf("#2E7D32"));
}
ComponentFactory.setCardIcon(applicationDeleteBtn, Constants.Svg.deleteSvg);
}
private void showJobName() {
new OkhttpUtil()
.url(Constants.OfferRequestUrls.GET_OFFER_URL)
.addQueryParam("id", application.getOfferId())
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "获取职位申请时发生了错误:" + e))
.successCallback(response -> new ResponseHandler(response).successCallback(data -> {
this.offer = JSONUtil.toBean(data, OfferResponse.class);
Platform.runLater(() -> jobName.setText(offer.getJobName()));
}).process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private String getStatusText(String status) {
switch (status) {
case "WAITING":
return "等待中";
case "ACCEPTED":
return "已接受";
case "REJECTED":
return "已拒绝";
default:
return status;
}
}
@FXML
void deleteApplication(ActionEvent event) {
dialogMaker.createDialogWithOKAndCancel("确认操作?", String.format("真的要删除 '%s' 的申请吗?", offer.getJobName()),
e -> new OkhttpUtil()
.url(Constants.ApplicationRequestUrls.APPLICATION_DELETE_URL)
.addQueryParam("id", application.getId())
.token(token)
.failCallback(ex -> dialogMaker.createMessageDialog("啊哈", "获取职位申请时发生了错误:" + ex))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "删除offer申请不成功:\n" + s))
.successCallback(deleteCallback)
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST));
}
@FXML
void viewDetail(MouseEvent event) throws IOException {
OfferDetailPane detailPage =
ComponentFactory.loadComponent("fxml/student/offer/offerDetail.fxml", new OfferDetailPane(dialogMaker, this.offer));
dialogMaker.createDialogWithOneBtn("Offer详情", detailPage);
}
}

@ -0,0 +1,83 @@
package net.lensfrex.disillusion.client.controller.components.student.application;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jfoenix.controls.JFXComboBox;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.layout.HBox;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.data.ResponseCode;
import net.lensfrex.disillusion.client.data.response.ResumeResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class ApplicationPostPane extends HBox {
private final ObservableList<String> resumeChoiceList = FXCollections.observableArrayList();
private Map<String, String> resumeNameIdMap;
@FXML
private JFXComboBox<String> resumeComboBox;
private final String token;
public ApplicationPostPane(String token) {
this.token = token;
}
public void initialize() {
this.getResumes();
}
public String getChooseResumeId() {
String selectedName = resumeComboBox.getSelectionModel().getSelectedItem();
if (selectedName == null) {
return null;
}
return resumeNameIdMap.get(selectedName);
}
private void getResumes() {
new OkhttpUtil()
.url(Constants.ResumeRequestUrls.RESUME_GET_ALL_URL)
.token(token)
.successCallback(response -> {
assert response.body() != null;
String responseString = response.body().string();
JSONObject responseJson = JSONUtil.parseObj(responseString);
Integer code = responseJson.getInt("code");
if (code == null || !code.equals(ResponseCode.SUCCESS.getCode())) {
String message = responseJson.getStr("message");
log.warn("获取简历时发生错误:" + message);
}
List<ResumeResponse> resumes = JSONUtil.toList(responseJson.getJSONArray("data"), ResumeResponse.class);
Platform.runLater(() -> this.addResumeItems(resumes));
})
.failCallback(e -> log.warn("获取简历时发生错误:" + e))
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void addResumeItems(List<ResumeResponse> resumes) {
resumeNameIdMap = new HashMap<>(resumes.size());
for (ResumeResponse resume : resumes) {
if (resume == null) {
continue;
}
resumeChoiceList.add(resume.getTitle());
resumeNameIdMap.put(resume.getTitle(), resume.getId());
}
resumeComboBox.setItems(resumeChoiceList);
resumeComboBox.getSelectionModel().select(0);
}
}

@ -0,0 +1,119 @@
package net.lensfrex.disillusion.client.controller.components.student.offer;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import com.jfoenix.controls.JFXTextArea;
import com.jfoenix.controls.JFXTextField;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.data.response.EmployerInfoResponse;
import net.lensfrex.disillusion.client.data.response.PublicEmployerInfoResponse;
import net.lensfrex.disillusion.client.util.ImageUtil;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.Response;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.function.Consumer;
@Slf4j
public class EmployerInfoPage extends HBox {
@FXML
private HBox rootPane;
@FXML
private ImageView avatarImageView;
@FXML
private Text usernameText;
@FXML
private Text shortDescribeText;
@FXML
private JFXTextField employerNameTextField;
@FXML
private JFXTextField industryTextField;
@FXML
private JFXTextField contactTextField;
@FXML
private JFXTextField addressTextField;
@FXML
private JFXTextField shortDescribeTextField;
@FXML
private JFXTextArea describeTextArea;
private File newAvatarFile;
private ThreadSafeDialogMaker dialogMaker;
private final PublicEmployerInfoResponse employerInfo;
public EmployerInfoPage(PublicEmployerInfoResponse employerInfo) {
this.employerInfo = employerInfo;
}
public void initialize() {
this.updateDisplay();
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_VIEW_URL)
.addQueryParam("user", employerInfo.getId())
.successCallback(response -> Platform.runLater(() -> setAvatar(avatarImageView, response)))
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void updateDisplay() {
String name = employerInfo.getName();
String place = employerInfo.getPlace();
String contract = employerInfo.getContract();
String shortDescribe = employerInfo.getShortDescribe();
String describe = employerInfo.getDescribe();
String industry = employerInfo.getIndustry();
usernameText.setText(name);
shortDescribeText.setText(shortDescribe);
employerNameTextField.setText(name);
industryTextField.setText(industry);
contactTextField.setText(contract);
addressTextField.setText(place);
shortDescribeTextField.setText(shortDescribe);
describeTextArea.setText(describe);
}
public static void setAvatar(ImageView avatarImageView, Response response) {
try {
assert response.body() != null;
byte[] data = response.body().bytes();
setAvatar(avatarImageView, data);
} catch (Exception e) {
log.warn("获取头像数据时出现异常", e);
}
}
public static void setAvatar(ImageView avatarImageView, byte[] data) {
Image avatarImage = new Image(new ByteArrayInputStream(data));
avatarImageView.setImage(avatarImage);
}
}

@ -0,0 +1,95 @@
package net.lensfrex.disillusion.client.controller.components.student.offer;
import cn.hutool.json.JSONUtil;
import com.jfoenix.controls.JFXTextArea;
import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.data.response.PublicEmployerInfoResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.IOException;
@Slf4j
public class OfferDetailPane extends VBox {
private final ThreadSafeDialogMaker dialogMaker;
public OfferDetailPane(ThreadSafeDialogMaker dialogMaker, OfferResponse offer,
PublicEmployerInfoResponse employerInfo) {
this.dialogMaker = dialogMaker;
this.offer = offer;
this.employerInfo = employerInfo;
}
public OfferDetailPane(ThreadSafeDialogMaker dialogMaker, OfferResponse offer) {
this.dialogMaker = dialogMaker;
this.offer = offer;
this.getEmployerInfo();
}
private void getEmployerInfo() {
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_PUBLIC_INFO_VIEW_URL)
.addQueryParam("user", offer.getPublisherId())
.failCallback(e -> log.warn("获取企业信息时发生网络错误:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> log.warn("获取企业信息不成功:\n" + s))
.successCallback(s -> {
employerInfo = JSONUtil.toBean(s, PublicEmployerInfoResponse.class);
employerText.setText(employerInfo.getName());
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
public void initialize() {
if (employerInfo != null) {
employerText.setText(employerInfo.getName());
}
jobNameText.setText(offer.getJobName());
placeText.setText(offer.getPlace());
requirementText.setText(offer.getRequirement());
salaryText.setText(offer.getSalary().toString());
targetNumberText.setText(offer.getTargetNumber().toString());
detailText.setText(offer.getDetail());
}
@FXML
void showEmployerDetail() throws IOException {
EmployerInfoPage employerInfoPage =
ComponentFactory.loadComponent("fxml/student/offer/employerProfile.fxml", new EmployerInfoPage(employerInfo));
dialogMaker.createDialogWithOneBtn("企业详情", employerInfoPage);
}
private final OfferResponse offer;
private PublicEmployerInfoResponse employerInfo;
@FXML
private Text jobNameText;
@FXML
private Text salaryText;
@FXML
private Text employerText;
@FXML
private Text placeText;
@FXML
private Text targetNumberText;
@FXML
private Text requirementText;
@FXML
private JFXTextArea detailText;
}

@ -0,0 +1,174 @@
package net.lensfrex.disillusion.client.controller.components.student.offer;
import cn.hutool.json.JSONUtil;
import com.jfoenix.controls.JFXButton;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.CommunicativeController;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.components.student.application.ApplicationPostPane;
import net.lensfrex.disillusion.client.data.request.ApplicationRequest;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.data.response.PublicEmployerInfoResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.IOException;
@Slf4j
public class StudentOfferCard extends StackPane implements CommunicativeController<StudentOfferCard.InitData> {
private final OfferResponse offer;
private PublicEmployerInfoResponse employerInfo;
private ThreadSafeDialogMaker dialogMaker;
private String token;
private static final String[] colors = new String[]{
"-fx-background-color: #8F3F7E",
"-fx-background-color: #B5305F",
"-fx-background-color: #CE584A",
"-fx-background-color: #DB8D5C",
"-fx-background-color: #DA854E",
"-fx-background-color: #E9AB44",
"-fx-background-color: #99C286",
"-fx-background-color: #01A05E",
"-fx-background-color: #4A8895",
"-fx-background-color: #16669B",
"-fx-background-color: #2F65A5",
};
public StudentOfferCard(OfferResponse offer) {
this.offer = offer;
}
@Override
public void loadData(InitData initData) {
this.dialogMaker = initData.dialogMaker;
this.token = initData.token;
}
public void initialize() {
String color = colors[Math.abs(offer.getJobName().hashCode()) % colors.length];
header.setStyle(header.getStyle() + color);
jobName.setText(offer.getJobName());
getEmployerInfo();
workingPlaceText.setText("工作地点:" + offer.getPlace());
if (offer.getSalary() >= 1_0000) {
salaryText.setText("薪资:" + offer.getSalary() / 1_0000.0 + "w");
} else {
salaryText.setText("薪资:" + offer.getSalary() / 1000.0 + "k");
}
ComponentFactory.setCardIcon(applicationSendBtn, Constants.Svg.sendSvg);
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_PROGRESS_URL)
.addQueryParam("id", offer.getId())
.failCallback(e -> log.warn("获取offer进度时出现网络问题:" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> log.warn("获取offer进度失败:" + s))
.successCallback(s -> Platform.runLater(() -> progressText.setText(s)))
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void getEmployerInfo() {
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_PUBLIC_INFO_VIEW_URL)
.addQueryParam("user", offer.getPublisherId())
.failCallback(e -> log.warn("获取企业信息时发生网络错误:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> log.warn("获取企业信息不成功:\n" + s))
.successCallback(s -> {
employerInfo = JSONUtil.toBean(s, PublicEmployerInfoResponse.class);
Platform.runLater(() -> employerNameText.setText("工作单位:" + employerInfo.getName()));
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
@Data
@Builder
@EqualsAndHashCode(callSuper = false)
public static class InitData extends CommunicativeController.InitData {
private ThreadSafeDialogMaker dialogMaker;
private String token;
}
@FXML
private StackPane rootPane;
@FXML
private StackPane header;
@FXML
private Label jobName;
@FXML
private StackPane body;
@FXML
private Text progressText;
@FXML
private Text salaryText;
@FXML
private Text employerNameText;
@FXML
private Text workingPlaceText;
@FXML
private JFXButton applicationSendBtn;
@FXML
void viewDetail(Event event) throws IOException {
OfferDetailPane detailPage = ComponentFactory.loadComponent("fxml/student/offer/offerDetail.fxml",
new OfferDetailPane(dialogMaker, this.offer, employerInfo));
dialogMaker.createDialogWithOneBtn("Offer详情", detailPage);
}
@FXML
void sendApplication(ActionEvent event) {
try {
ApplicationPostPane page = ComponentFactory.loadComponent("fxml/student/application/applicationPostPage.fxml",
new ApplicationPostPane(this.token));
dialogMaker.createDialogWithOKAndCancel("发送求职申请", page,
e -> this.sendApplication(page.getChooseResumeId())
);
} catch (Exception e) {
e.printStackTrace();
}
}
private void sendApplication(String resumeId) {
ApplicationRequest request = new ApplicationRequest(offer.getId(), resumeId);
new OkhttpUtil()
.url(Constants.ApplicationRequestUrls.APPLICATION_PUBLISH_URL)
.body(request)
.addHeader("token", token)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "发送offer申请时出现网络错误"))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "offer申请发送失败:\n" + s))
.successCallback(s -> dialogMaker.createMessageDialog("好好好", "offer申请已发送,请等待处理"))
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
}

@ -0,0 +1,172 @@
package net.lensfrex.disillusion.client.controller.components.student.resume;
import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jfoenix.controls.JFXButton;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.data.ResponseCode;
import net.lensfrex.disillusion.client.data.request.ResumeRequest;
import net.lensfrex.disillusion.client.data.response.ResumeResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.function.Consumer;
public class ResumeCard extends StackPane {
private static final String[] colors = new String[]{
"-fx-background-color: #8F3F7E",
"-fx-background-color: #B5305F",
"-fx-background-color: #CE584A",
"-fx-background-color: #DB8D5C",
"-fx-background-color: #DA854E",
"-fx-background-color: #E9AB44",
"-fx-background-color: #99C286",
"-fx-background-color: #01A05E",
"-fx-background-color: #4A8895",
"-fx-background-color: #16669B",
"-fx-background-color: #2F65A5",
};
private static final OkHttpClient okhttpClient = Constants.globalClient;
private final ResumeResponse resume;
private final String token;
private final ThreadSafeDialogMaker dialogMaker;
private final Consumer<Response> updateCallback;
private final Consumer<Response> deleteCallback;
public ResumeCard(ResumeResponse resume, String token, ThreadSafeDialogMaker dialogMaker,
Consumer<Response> updateCallback, Consumer<Response> deleteCallback) {
this.resume = resume;
this.token = token;
this.dialogMaker = dialogMaker;
this.updateCallback = updateCallback;
this.deleteCallback = deleteCallback;
}
@FXML
private StackPane rootPane;
@FXML
private StackPane header;
@FXML
private Label resumeNameText;
@FXML
private StackPane body;
@FXML
private Text remarkText;
@FXML
private JFXButton resumeDeleteBtn;
public void initialize() {
String color = colors[Math.abs(resume.getTitle().hashCode()) % colors.length];
header.setStyle(header.getStyle() + color);
resumeNameText.setText(resume.getTitle());
remarkText.setText(resume.getRemark());
ComponentFactory.setCardIcon(resumeDeleteBtn, Constants.Svg.deleteSvg);
}
@FXML
void showResumeDetail(MouseEvent event) throws IOException {
ResumeUploadPane resumeUploadPane =
ComponentFactory.loadComponent("fxml/student/resume/resumeUpload.fxml", new ResumeUploadPane(dialogMaker));
ResumeUploadPane.InitData initData = new ResumeUploadPane.InitData();
initData.setName(resume.getTitle());
initData.setRemark(resume.getRemark());
resumeUploadPane.loadData(initData);
dialogMaker.createDialogWithOKAndCancel("更新简历", resumeUploadPane, e -> {
try {
ResumeRequest request = new ResumeRequest();
request.setTitle(resumeUploadPane.getResumeName());
request.setRemark(resumeUploadPane.getRemark());
File resumeFile = resumeUploadPane.getResumeFile();
if (resumeFile != null) {
request.setResumeFileBase64(Base64.encode(resumeFile));
}
this.updateResume(request);
} catch (Exception ex) {
ex.printStackTrace();
dialogMaker.createMessageDialog("啊哈", "读取简历文件时发生错误...\n" + ex);
}
});
}
private void updateResume(ResumeRequest resumeRequest) {
String json = JSONUtil.toJsonStr(resumeRequest);
RequestBody requestBody = RequestBody.create(json, MediaType.get("application/json"));
Request uploadRequest = new Request.Builder()
.url(Constants.ResumeRequestUrls.RESUME_UPDATE_URL + "?id=" + resume.getId())
.addHeader("token", token)
.post(requestBody)
.build();
okhttpClient.newCall(uploadRequest).enqueue(resumeUpdateCallback);
}
private final Callback resumeUpdateCallback = new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
dialogMaker.createMessageDialog("啊哈", "上传简历时发生了网络错误\n" + e);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
assert response.body() != null;
String responseString = response.body().string();
JSONObject responseJson = JSONUtil.parseObj(responseString);
Integer code = responseJson.getInt("code");
if (code == null || !code.equals(ResponseCode.SUCCESS.getCode())) {
String message = responseJson.getStr("message");
dialogMaker.createMessageDialog("啊哈", "获取用户信息时出错了...\n" + message);
} else {
dialogMaker.createMessageDialog("好耶", "上传成功");
Platform.runLater(() -> updateCallback.accept(response));
}
}
};
@FXML
void deleteResume(ActionEvent event) {
dialogMaker.createDialogWithOKAndCancel("Really?", String.format("真的要删除简历 '%s' 吗?", resume.getTitle()),
e -> new OkhttpUtil()
.url(Constants.ResumeRequestUrls.RESUME_DELETE_URL)
.token(token)
.addQueryParam("id", resume.getId())
.failCallback(e1 -> dialogMaker.createMessageDialog("啊哈", "删除简历时发生了网络错误\n" + e1))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "删除简历时出错了...\n" + s))
.successCallback(response1 -> Platform.runLater(() -> deleteCallback.accept(response)))
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST));
}
}

@ -0,0 +1,95 @@
package net.lensfrex.disillusion.client.controller.components.student.resume;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import com.jfoenix.controls.JFXTextField;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.CommunicativeController;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.File;
public class ResumeUploadPane extends VBox implements CommunicativeController<ResumeUploadPane.InitData> {
private final ThreadSafeDialogMaker dialogMaker;
public ResumeUploadPane(ThreadSafeDialogMaker dialogMaker) {
this.dialogMaker = dialogMaker;
}
@Override
public void loadData(InitData initData) {
resumeNameTextField.setText(initData.getName());
remarkTextField.setText(initData.getRemark());
}
@Override
public void initialize() {
resumeNameTextField.setText(RandomUtil.randomString(Constants.sample, 5));
remarkTextField.setText(RandomUtil.randomString(Constants.sample, 15));
}
@Data
@EqualsAndHashCode(callSuper = false)
public static class InitData extends CommunicativeController.InitData {
private String name;
private String remark;
}
@FXML
private VBox rootPane;
@FXML
private JFXTextField resumeNameTextField;
@FXML
private JFXTextField remarkTextField;
@FXML
private Text fileNameText;
private File resumeFile;
@FXML
void addFile(ActionEvent event) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("告诉我在哪?");
File chooseFile = fileChooser.showOpenDialog(rootPane.getScene().getWindow());
if (chooseFile != null) {
String fileType = FileUtil.getType(chooseFile);
switch (fileType) {
case "png":
case "jpg":
case "jpeg":
case "webm":
case "pdf":
case "doc":
case "docx":
fileNameText.setText(chooseFile.getName());
resumeFile = chooseFile;
break;
default:
dialogMaker.createMessageDialog("(;´д`)ゞ", "简历文件不支持:" + fileType + "\n仅支持png, jpg, webm, pdf, word");
}
}
}
public String getResumeName() {
return resumeNameTextField.getText();
}
public String getRemark() {
return remarkTextField.getText();
}
public File getResumeFile() {
return resumeFile;
}
}

@ -0,0 +1,91 @@
package net.lensfrex.disillusion.client.controller.page.employer;
import cn.hutool.json.JSONUtil;
import com.jfoenix.effects.JFXDepthManager;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.components.employer.application.ApplicationOfferCard;
import net.lensfrex.disillusion.client.controller.components.student.resume.ResumeCard;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.util.List;
@Slf4j
public class EmployerApplicationManagePage extends VBox {
@FXML
private VBox rootPane;
@FXML
private ScrollPane scrollPane;
@FXML
private FlowPane offerContainer;
private String token;
private ThreadSafeDialogMaker dialogMaker;
@FXML
void refresh(ActionEvent event) {
this.refreshOfferList();
}
public void loadData(String token, ThreadSafeDialogMaker dialogMaker) {
this.token = token;
this.dialogMaker = dialogMaker;
this.refreshOfferList();
}
public void initialize() {
offerContainer.getChildren().addAll(offerLost);
}
private final ObservableList<ResumeCard> offerLost = FXCollections.observableArrayList();
private void refreshOfferList() {
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_GET_BY_EMPLOYER_SELF_URL)
.token(token)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "获取offer列表时发生了网络错误\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "获取offer列表不成功\n" + s))
.successCallback(data -> {
List<OfferResponse> result = JSONUtil.toList(data, OfferResponse.class);
Platform.runLater(() -> showOffers(result));
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void showOffers(List<OfferResponse> offers) {
try {
ObservableList<Node> cards = offerContainer.getChildren();
cards.clear();
for (OfferResponse offer : offers) {
if (offer == null) {
continue;
}
ApplicationOfferCard card =
ComponentFactory.loadComponent("fxml/employer/application/applicationOfferCard.fxml", new ApplicationOfferCard(offer));
card.loadData(token, dialogMaker);
JFXDepthManager.setDepth(card, 1);
cards.add(card);
}
} catch (Exception e) {
e.printStackTrace();
log.warn("展示offer卡片时发生错误");
}
}
}

@ -0,0 +1,136 @@
package net.lensfrex.disillusion.client.controller.page.employer;
import animatefx.animation.FadeIn;
import animatefx.animation.FadeOut;
import cn.hutool.json.JSONUtil;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.page.student.StudentProfilePage;
import net.lensfrex.disillusion.client.data.response.EmployerInfoResponse;
import net.lensfrex.disillusion.client.util.DialogMaker;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class EmployerMainController {
@FXML
private StackPane rootPane;
@FXML
private ImageView avatarImageView;
@FXML
private Text employerName;
@FXML
private Text usernameText;
@FXML
private Text shortDescribeText;
@FXML
private StackPane containerPane;
private ThreadSafeDialogMaker threadSafeDialogMaker;
private String token;
private EmployerInfoResponse employerInfo;
private final Map<String, Pane> pages = new HashMap<>(4);
public void setData(String token) {
this.token = token;
this.fetchUserInfo();
}
public void initialize() {
threadSafeDialogMaker = new ThreadSafeDialogMaker(rootPane);
try {
pages.put("profile", ComponentFactory.loadComponent("fxml/employer/profile.fxml", EmployerProfilePage.class));
pages.put("offerManage", ComponentFactory.loadComponent("fxml/employer/offer/offerManagePage.fxml", EmployerOfferManagePage.class));
pages.put("applicationManage", ComponentFactory.loadComponent("fxml/employer/application/applicationManagePage.fxml", EmployerApplicationManagePage.class));
} catch (Exception e) {
e.printStackTrace();
DialogMaker.errorMessageDialog("出错啦,请联系lensfrex这家伙\n调试信息:\n" + e);
}
}
private void fetchUserInfo() {
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_INFO_VIEW_URL)
.token(token)
.failCallback(e -> log.error("请求用户数据时发生网络错误"))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> threadSafeDialogMaker.createMessageDialog("啊哈", "获取用户信息不成功:" + s))
.successCallback(this::updateUserInfoUI)
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void updateUserInfoUI(String data) {
employerInfo = JSONUtil.toBean(data, EmployerInfoResponse.class);
Platform.runLater(() -> {
employerName.setText(employerInfo.getName());
usernameText.setText("@" + employerInfo.getId());
shortDescribeText.setText(employerInfo.getShortDescribe());
});
this.updateAvatar();
}
private void updateAvatar() {
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_VIEW_URL)
.token(token)
.failCallback(e -> log.warn("获取头像时发生网络错误:\n" + e))
.successCallback(avatarResponse -> Platform.runLater(() -> StudentProfilePage.setAvatar(avatarImageView, avatarResponse)))
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
@FXML
void showApplicationDealPage(ActionEvent event) {
EmployerApplicationManagePage page = (EmployerApplicationManagePage) this.switchPage("applicationManage");
page.loadData(token, threadSafeDialogMaker);
}
@FXML
void showOfferManagePage(ActionEvent event) {
EmployerOfferManagePage page = (EmployerOfferManagePage) this.switchPage("offerManage");
page.loadData(token, threadSafeDialogMaker);
}
@FXML
void showProfile(ActionEvent event) {
EmployerProfilePage page = (EmployerProfilePage) this.switchPage("profile");
page.loadData(employerInfo, token, threadSafeDialogMaker, r -> fetchUserInfo());
}
private Node switchPage(String page) {
ObservableList<Node> list = containerPane.getChildren();
new FadeOut(list.get(0)).play();
Pane pagePane = pages.get(page);
if (pagePane != null) {
list.clear();
list.add(pagePane);
new FadeIn(pagePane).play();
}
return pagePane;
}
}

@ -0,0 +1,114 @@
package net.lensfrex.disillusion.client.controller.page.employer;
import cn.hutool.json.JSONUtil;
import com.jfoenix.effects.JFXDepthManager;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.components.employer.offer.EmployerOfferCard;
import net.lensfrex.disillusion.client.controller.components.employer.offer.EmployerOfferDetailPane;
import net.lensfrex.disillusion.client.controller.components.student.resume.ResumeCard;
import net.lensfrex.disillusion.client.data.request.OfferPublishRequest;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.util.Consumer;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import java.io.IOException;
import java.util.List;
@Slf4j
public class EmployerOfferManagePage extends VBox {
@FXML
private VBox rootPane;
@FXML
private ScrollPane scrollPane;
@FXML
private FlowPane offerContainer;
private String token;
private ThreadSafeDialogMaker dialogMaker;
public void loadData(String token, ThreadSafeDialogMaker dialogMaker) {
this.token = token;
this.dialogMaker = dialogMaker;
this.refreshOfferList();
}
public void initialize() {
offerContainer.getChildren().addAll(offerLost);
}
private final ObservableList<ResumeCard> offerLost = FXCollections.observableArrayList();
@FXML
void addOffer(ActionEvent event) throws IOException, InstantiationException, IllegalAccessException {
EmployerOfferDetailPane offerDetailPane =
ComponentFactory.loadComponent("fxml/employer/offer/offerDetailPane.fxml", EmployerOfferDetailPane.class);
dialogMaker.createDialogWithOKAndCancel("发布新的offer信息", offerDetailPane, e -> this.publishOffer(offerDetailPane.getData()));
}
private void publishOffer(OfferPublishRequest offerPublishRequest) {
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_PUBLISH_URL)
.token(token)
.body(offerPublishRequest)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "发布offer时发生了网络问题:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "发布offer不成功:\n" + s))
.successCallback(s -> this.refreshOfferList())
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
private void refreshOfferList() {
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_GET_BY_EMPLOYER_SELF_URL)
.token(token)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "获取offer列表时发生了网络错误\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "获取offer列表不成功\n" + s))
.successCallback(data -> {
List<OfferResponse> result = JSONUtil.toList(data, OfferResponse.class);
Platform.runLater(() -> showOffers(result));
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void showOffers(List<OfferResponse> offers) {
try {
ObservableList<Node> cards = offerContainer.getChildren();
cards.clear();
for (OfferResponse offer : offers) {
if (offer == null) {
continue;
}
EmployerOfferCard card =
ComponentFactory.loadComponent("fxml/employer/offer/offerCard.fxml", new EmployerOfferCard(offer));
card.loadData(token, dialogMaker, this.deleteCallback, this.updateCallback);
JFXDepthManager.setDepth(card, 1);
cards.add(card);
}
} catch (Exception e) {
e.printStackTrace();
log.warn("展示offer卡片时发生错误");
}
}
private final Consumer<String> updateCallback = s -> refreshOfferList();
private final Consumer<String> deleteCallback = s -> refreshOfferList();
}

@ -0,0 +1,206 @@
package net.lensfrex.disillusion.client.controller.page.employer;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import com.jfoenix.controls.JFXTextArea;
import com.jfoenix.controls.JFXTextField;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.data.response.EmployerInfoResponse;
import net.lensfrex.disillusion.client.util.ImageUtil;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.Response;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.function.Consumer;
@Slf4j
public class EmployerProfilePage extends HBox {
@FXML
private HBox rootPane;
@FXML
private ImageView avatarImageView;
@FXML
private Text usernameText;
@FXML
private Text shortDescribeText;
@FXML
private JFXTextField employerNameTextField;
@FXML
private JFXTextField industryTextField;
@FXML
private JFXTextField contactTextField;
@FXML
private JFXTextField addressTextField;
@FXML
private JFXTextField shortDescribeTextField;
@FXML
private JFXTextArea describeTextArea;
private File newAvatarFile;
private String token;
private ThreadSafeDialogMaker dialogMaker;
@FXML
void save(ActionEvent event) {
employerInfo.setName(employerNameTextField.getText());
employerInfo.setPlace(addressTextField.getText());
employerInfo.setContract(contactTextField.getText());
employerInfo.setShortDescribe(shortDescribeTextField.getText());
employerInfo.setDescribe(describeTextArea.getText());
employerInfo.setIndustry(industryTextField.getText());
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_INFO_EDIT_URL)
.token(token)
.body(employerInfo)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "更新上传用户信息的时候出错啦:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "更新上传用户信息不成功:" + s))
.successCallback(s -> {
updateCallback.accept(employerInfo);
dialogMaker.createMessageDialog("好耶", "更新成功");
Platform.runLater(this::updateDisplay);
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
@FXML
void replaceAvatar(MouseEvent event) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("选择图片");
File chooseFile = fileChooser.showOpenDialog(rootPane.getScene().getWindow());
if (chooseFile != null) {
String fileType = FileUtil.getType(chooseFile);
switch (fileType) {
case "png":
case "jpg":
case "jpeg":
case "gif":
case "webm":
this.uploadAvatar(chooseFile);
break;
default:
dialogMaker.createMessageDialog(
"(;´д`)ゞ",
"头像文件不支持:" + fileType + "\n仅支持png, jpg, gif, webm"
);
}
}
}
private void uploadAvatar(File avatarFile) {
try {
byte[] avatarData;
// 大于1m的图片就进行压缩
long fileLength = avatarFile.length();
if (fileLength > 1048576) {
// 压缩比例,文件越大压缩程度越大
float percent = (float) Math.pow(0.96, fileLength / 1048576f);
avatarData = ImageUtil.processImage(avatarFile, 0.8f, percent, "jpg");
} else {
avatarData = Files.readAllBytes(Paths.get(avatarFile.toURI()));
}
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_EDIT_URL)
.token(token)
.body(Base64.encode(avatarData), "plain/text")
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "上传头像文件时发生网络错误:" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "获取头像时出现问题:" + s))
.successCallback(s -> {
Platform.runLater(() -> setAvatar(avatarImageView, avatarData));
updateCallback.accept(employerInfo);
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
} catch (IOException e) {
dialogMaker.createMessageDialog("啊哈", "读取头像文件时发生错误:" + e);
}
}
private EmployerInfoResponse employerInfo;
private Consumer<EmployerInfoResponse> updateCallback;
public void loadData(EmployerInfoResponse employerInfo,
String token, ThreadSafeDialogMaker dialogMaker,
Consumer<EmployerInfoResponse> updateCallback) {
this.token = token;
this.employerInfo = employerInfo;
this.dialogMaker = dialogMaker;
this.updateCallback = updateCallback;
this.updateDisplay();
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_VIEW_URL)
.token(token)
.successCallback(response -> Platform.runLater(() -> setAvatar(avatarImageView, response)))
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void updateDisplay() {
String name = employerInfo.getName();
String place = employerInfo.getPlace();
String contract = employerInfo.getContract();
String shortDescribe = employerInfo.getShortDescribe();
String describe = employerInfo.getDescribe();
String industry = employerInfo.getIndustry();
usernameText.setText(name);
shortDescribeText.setText(shortDescribe);
employerNameTextField.setText(name);
industryTextField.setText(industry);
contactTextField.setText(contract);
addressTextField.setText(place);
shortDescribeTextField.setText(shortDescribe);
describeTextArea.setText(describe);
}
public static void setAvatar(ImageView avatarImageView, Response response) {
try {
assert response.body() != null;
byte[] data = response.body().bytes();
setAvatar(avatarImageView, data);
} catch (Exception e) {
log.warn("获取头像数据时出现异常", e);
}
}
public static void setAvatar(ImageView avatarImageView, byte[] data) {
Image avatarImage = new Image(new ByteArrayInputStream(data));
avatarImageView.setImage(avatarImage);
}
}

@ -0,0 +1,106 @@
package net.lensfrex.disillusion.client.controller.page.student;
import cn.hutool.json.JSONUtil;
import com.jfoenix.effects.JFXDepthManager;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.CommunicativeController;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.components.student.application.ApplicationCard;
import net.lensfrex.disillusion.client.data.response.ApplicationResponse;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.*;
import java.util.List;
@Slf4j
public class ApplicationManagePage extends VBox implements CommunicativeController<ApplicationManagePage.InitData> {
@FXML
private VBox rootPane;
@FXML
private ScrollPane scrollPane;
@FXML
private FlowPane applicationContainer;
private String token;
private ThreadSafeDialogMaker dialogMaker;
private static final OkHttpClient okhttpClient = Constants.globalClient;
@Data
@Builder
@EqualsAndHashCode(callSuper = false)
public static class InitData extends CommunicativeController.InitData {
private String token;
private ThreadSafeDialogMaker dialogMaker;
}
@Override
public void loadData(ApplicationManagePage.InitData initData) {
this.token = initData.token;
this.dialogMaker = initData.dialogMaker;
this.refreshApplicationList();
}
public void initialize() {
applicationContainer.getChildren().addAll(applicationList);
}
private final ObservableList<ApplicationCard> applicationList = FXCollections.observableArrayList();
private void refreshApplicationList() {
new OkhttpUtil()
.url(Constants.ApplicationRequestUrls.APPLICATION_STUDENT_VIEW_URL)
.token(token)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "获取简历时发生了网络错误\n" + e))
.successCallback(response -> {
ResponseHandler.Result responseData = ResponseHandler.parse(response,
s -> dialogMaker.createMessageDialog("啊哈", "获取简历时出错了...\n" + s));
if (responseData.data == null || !responseData.success) {
return;
}
List<ApplicationResponse> result = JSONUtil.toList(responseData.data, ApplicationResponse.class);
Platform.runLater(() -> listApplications(result));
})
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private void listApplications(List<ApplicationResponse> applications) {
try {
ObservableList<Node> items = applicationContainer.getChildren();
items.clear();
for (ApplicationResponse application : applications) {
if (application == null) {
continue;
}
ApplicationCard card =
ComponentFactory.loadComponent("fxml/student/application/applicationCard.fxml",
new ApplicationCard(token, dialogMaker, application, s -> this.refreshApplicationList()));
JFXDepthManager.setDepth(card, 1);
card.setUserData(applications);
items.add(card);
}
} catch (Exception e) {
e.printStackTrace();
log.warn("展示求职申请卡片时发生错误");
}
}
}

@ -0,0 +1,204 @@
package net.lensfrex.disillusion.client.controller.page.student;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.effects.JFXDepthManager;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.CommunicativeController;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.components.student.offer.StudentOfferCard;
import net.lensfrex.disillusion.client.data.ResponseCode;
import net.lensfrex.disillusion.client.data.response.OfferResponse;
import net.lensfrex.disillusion.client.util.Consumer;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import java.util.List;
@Slf4j
public class OfferSquarePage
extends VBox
implements CommunicativeController<OfferSquarePage.InitData> {
private static final OkHttpClient okhttpClient = Constants.globalClient;
@FXML
private VBox rootPane;
@FXML
private JFXComboBox<String> filterType;
@FXML
private JFXTextField filterString;
@FXML
private FlowPane offersPane;
@FXML
private ScrollPane scrollPane;
@FXML
private Label pageLabel;
private double totalDrag = 0;
private String token;
private Pane parentRootPane;
private ThreadSafeDialogMaker dialogMaker;
@Override
public void loadData(InitData data) {
this.token = data.token;
this.dialogMaker = data.dialogMaker;
this.refresh(null);
}
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
public static class InitData extends CommunicativeController.InitData {
private String token;
private ThreadSafeDialogMaker dialogMaker;
}
public void initialize() {
ObservableList<String> filterList = FXCollections.observableArrayList();
filterList.add("用人单位");
filterList.add("职位名称");
filterList.add("最低薪资");
filterType.setItems(filterList);
filterType.getSelectionModel().select(0);
scrollPane.addEventHandler(ScrollEvent.SCROLL, e -> {
double downScrollLength = -e.getDeltaY();
if (downScrollLength < 0) {
return;
}
totalDrag += downScrollLength;
if (totalDrag > offersPane.getPrefHeight()) {
refresh(null);
}
});
}
private int currentPage = 0;
private static final int DEFAULT_PAGE_SIZE = 5;
@FXML
void refresh(ActionEvent event) {
this.getOffers(currentPage + 1, DEFAULT_PAGE_SIZE);
}
private void getOffers(int page, int size) {
new OkhttpUtil()
.addQueryParam("page", String.valueOf(page))
.addQueryParam("size", String.valueOf(size))
.url(Constants.OfferRequestUrls.GET_ALL_OFFER_URL)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "请求Offer列表时发生了一下错误\n" + e))
.successCallback(getOfferSuccessCallback)
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
private static final OfferResponse[] EMPTY_OFFERS = new OfferResponse[]{};
private final Consumer<Response> getOfferSuccessCallback = response -> {
assert response.body() != null;
String responseString = response.body().string();
JSONObject responseJson = JSONUtil.parseObj(responseString);
Integer code = responseJson.getInt("code");
if (code == null || !code.equals(ResponseCode.SUCCESS.getCode())) {
dialogMaker.createMessageDialog("啊哈", "获取offer列表时出错了...\n" + responseString);
}
JSONObject data = responseJson.getJSONObject("data");
List<OfferResponse> offers = JSONUtil.toList(data.getJSONArray("result"), OfferResponse.class);
Platform.runLater(() -> {
this.showOfferCards(offers);
currentPage = offers.size() < DEFAULT_PAGE_SIZE ? 0 : data.getInt("page");
});
};
private void showOfferCards(List<OfferResponse> offers) {
try {
ObservableList<Node> items = offersPane.getChildren();
if (currentPage == 0) {
items.clear();
}
for (OfferResponse offer : offers) {
StudentOfferCard studentOfferCard = new StudentOfferCard(offer);
Node item = ComponentFactory.loadComponent("fxml/student/offer/offerCard.fxml", studentOfferCard);
studentOfferCard.loadData(StudentOfferCard.InitData.builder().token(token).dialogMaker(dialogMaker).build());
studentOfferCard.setUserData("offer");
JFXDepthManager.setDepth(item, 1);
items.add(new Pane(item));
}
} catch (Exception e) {
log.error("解析Offer对象数据时出错:\n{}", e.toString());
e.printStackTrace();
}
}
@FXML
void search(ActionEvent event) {
String selected = filterType.getSelectionModel().getSelectedItem();
String filterType = "";
switch (selected) {
case "用人单位":
filterType = Constants.OfferRequestUrls.OFFER_FILTER_EMPLOYER;
break;
case "职位名称":
filterType = Constants.OfferRequestUrls.OFFER_FILTER_JOB_NAME;
break;
case "最低薪资":
filterType = Constants.OfferRequestUrls.OFFER_FILTER_SALARY;
break;
}
new OkhttpUtil()
.url(Constants.OfferRequestUrls.OFFER_SEARCH_URL)
.addQueryParam("filter", filterType)
.addQueryParam("value", filterString.getText())
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "搜索offer时发生了错误:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "搜索offer不成功:\n" + s))
.successCallback(s -> Platform.runLater(() -> {
offersPane.getChildren().clear();
List<OfferResponse> offers = JSONUtil.toList(s, OfferResponse.class);
this.showOfferCards(offers);
}))
.process())
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
}

@ -0,0 +1,194 @@
package net.lensfrex.disillusion.client.controller.page.student;
import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jfoenix.effects.JFXDepthManager;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.CommunicativeController;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.controller.components.student.resume.ResumeCard;
import net.lensfrex.disillusion.client.controller.components.student.resume.ResumeUploadPane;
import net.lensfrex.disillusion.client.data.ResponseCode;
import net.lensfrex.disillusion.client.data.request.ResumeRequest;
import net.lensfrex.disillusion.client.data.response.ResumeResponse;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
@Slf4j
public class ResumeManagePage extends VBox
implements CommunicativeController<ResumeManagePage.InitData> {
private static final OkHttpClient okhttpClient = Constants.globalClient;
private String token;
private ThreadSafeDialogMaker dialogMaker;
@Override
public void loadData(InitData initData) {
this.token = initData.token;
this.dialogMaker = initData.dialogMaker;
this.refreshResumeList();
}
@Data
@EqualsAndHashCode(callSuper = false)
public static class InitData extends CommunicativeController.InitData {
private String token;
private ThreadSafeDialogMaker dialogMaker;
}
public void initialize() {
resumeContainer.getChildren().addAll(resumeList);
}
@FXML
private VBox rootPane;
@FXML
private FlowPane resumeContainer;
private final ObservableList<ResumeCard> resumeList = FXCollections.observableArrayList();
@FXML
void addResume(ActionEvent event) {
try {
ResumeUploadPane resumeUploadPane =
ComponentFactory.loadComponent("fxml/student/resume/resumeUpload.fxml", new ResumeUploadPane(dialogMaker));
dialogMaker.createDialogWithOKAndCancel("上传新的简历", resumeUploadPane, e -> {
try {
ResumeRequest request = new ResumeRequest();
request.setTitle(resumeUploadPane.getResumeName());
request.setRemark(resumeUploadPane.getRemark());
File resumeFile = resumeUploadPane.getResumeFile();
if (resumeFile == null) {
dialogMaker.createMessageDialog("啊哈", "请选择上传一个文件");
return;
}
request.setResumeFileBase64(Base64.encode(resumeFile));
this.uploadResume(request);
} catch (Exception ex) {
ex.printStackTrace();
dialogMaker.createMessageDialog("啊哈", "读取简历文件时发生错误...\n" + ex);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
private void uploadResume(ResumeRequest resumeRequest) {
String json = JSONUtil.toJsonStr(resumeRequest);
RequestBody requestBody = RequestBody.create(json, MediaType.get("application/json"));
Request uploadRequest = new Request.Builder()
.url(Constants.ResumeRequestUrls.RESUME_UPLOAD_URL)
.addHeader("token", token)
.post(requestBody)
.build();
okhttpClient.newCall(uploadRequest).enqueue(resumeUploadCallback);
}
private final Callback resumeUploadCallback = new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
dialogMaker.createMessageDialog("啊哈", "上传简历时发生了网络错误\n" + e);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
assert response.body() != null;
String responseString = response.body().string();
JSONObject responseJson = JSONUtil.parseObj(responseString);
Integer code = responseJson.getInt("code");
if (code == null || !code.equals(ResponseCode.SUCCESS.getCode())) {
String message = responseJson.getStr("message");
dialogMaker.createMessageDialog("啊哈", "获取用户信息时出错了...\n" + message);
} else {
dialogMaker.createMessageDialog("好耶", "上传成功");
Platform.runLater(ResumeManagePage.this::refreshResumeList);
}
}
};
private void refreshResumeList() {
Request uploadRequest = new Request.Builder()
.url(Constants.ResumeRequestUrls.RESUME_GET_ALL_URL)
.addHeader("token", token)
.get()
.build();
okhttpClient.newCall(uploadRequest).enqueue(resumeFetchCallback);
}
private final Callback resumeFetchCallback = new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
dialogMaker.createMessageDialog("啊哈", "获取简历时发生了网络错误\n" + e);
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
assert response.body() != null;
String responseString = response.body().string();
JSONObject responseJson = JSONUtil.parseObj(responseString);
Integer code = responseJson.getInt("code");
if (code == null || !code.equals(ResponseCode.SUCCESS.getCode())) {
String message = responseJson.getStr("message");
dialogMaker.createMessageDialog("啊哈", "获取简历时出错了...\n" + message);
}
List<ResumeResponse> result = JSONUtil.toList(responseJson.getJSONArray("data"), ResumeResponse.class);
Platform.runLater(() -> listResumes(result));
}
};
private void listResumes(List<ResumeResponse> resumes) {
try {
ObservableList<Node> items = resumeContainer.getChildren();
items.clear();
for (ResumeResponse resume : resumes) {
if (resume == null) {
continue;
}
ResumeCard itemController = new ResumeCard(resume, token, dialogMaker, updateCallback, deleteCallback);
ResumeCard item =
ComponentFactory.loadComponent("fxml/student/resume/resumeCard.fxml", itemController);
JFXDepthManager.setDepth(item, 1);
item.setUserData(resume);
items.add(item);
}
} catch (Exception e) {
e.printStackTrace();
log.warn("展示简历卡片时发生错误");
}
}
private final Consumer<Response> updateCallback = response -> refreshResumeList();
private final Consumer<Response> deleteCallback = response -> refreshResumeList();
}

@ -0,0 +1,174 @@
package net.lensfrex.disillusion.client.controller.page.student;
import animatefx.animation.FadeIn;
import animatefx.animation.FadeOut;
import cn.hutool.json.JSONUtil;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.controller.components.ComponentFactory;
import net.lensfrex.disillusion.client.data.response.StudentInfoResponse;
import net.lensfrex.disillusion.client.util.DialogMaker;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.*;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class StudentMainController {
private static final OkHttpClient okhttpClient = Constants.globalClient;
@FXML
private StackPane rootPane;
@FXML
private ImageView avatarImageView;
@FXML
private Text usernameText;
@FXML
private Text realNameText;
@FXML
private StackPane containerPane;
@FXML
private Text signText;
private ThreadSafeDialogMaker threadSafeDialogMaker;
private DialogMaker dialogMaker;
private String token;
private String username;
private StudentInfoResponse studentInfo;
private final Map<String, Pane> pages = new HashMap<>(4);
public void initialize() {
threadSafeDialogMaker = new ThreadSafeDialogMaker(rootPane);
dialogMaker = new DialogMaker(rootPane);
try {
pages.put("offerSquare", ComponentFactory.loadComponent("fxml/student/offer/offerSquare.fxml", OfferSquarePage.class));
pages.put("profile", ComponentFactory.loadComponent("fxml/student/profile.fxml", StudentProfilePage.class));
pages.put("applicationManage", ComponentFactory.loadComponent("fxml/student/application/applicationManagePage.fxml", ApplicationManagePage.class));
pages.put("resumeManage", ComponentFactory.loadComponent("fxml/student/resume/resumeManagePage.fxml", ResumeManagePage.class));
} catch (Exception e) {
e.printStackTrace();
DialogMaker.errorMessageDialog("出错啦,请联系lensfrex这家伙\n调试信息:\n" + e);
}
}
public void setData(InitData data) {
this.token = data.token;
this.username = data.username;
this.updateUserInfo();
}
private void updateUserInfo() {
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_INFO_VIEW_URL)
.token(token)
.failCallback(e -> log.error("请求用户数据时发生网络错误"))
.successCallback(response -> {
ResponseHandler.Result result = ResponseHandler.parse(response,
s -> threadSafeDialogMaker.createMessageDialog("啊哈", "获取用户信息时出错:" + s));
if (!result.success) {
return;
}
studentInfo = JSONUtil.toBean(result.data, StudentInfoResponse.class);
Platform.runLater(() -> {
usernameText.setText(username);
realNameText.textProperty().set("@" + studentInfo.getRealName());
signText.setText(studentInfo.getShortDescribe());
});
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_VIEW_URL)
.token(token)
.successCallback(avatarResponse -> Platform.runLater(() -> StudentProfilePage.setAvatar(avatarImageView, avatarResponse)))
.executeAsync(OkhttpUtil.RequestMethod.GET);
})
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
@FXML
void showApplications(ActionEvent event) {
ApplicationManagePage controller = (ApplicationManagePage) this.switchPage("applicationManage");
controller.loadData(ApplicationManagePage.InitData.builder()
.token(token)
.dialogMaker(threadSafeDialogMaker)
.build()
);
}
@FXML
void showOfferSquare(ActionEvent event) {
OfferSquarePage controller = (OfferSquarePage) this.switchPage("offerSquare");
controller.loadData(OfferSquarePage.InitData.builder()
.token(token)
.dialogMaker(threadSafeDialogMaker)
.build()
);
}
@FXML
void showProfile(ActionEvent event) {
StudentProfilePage controller = (StudentProfilePage) this.switchPage("profile");
controller.setData(studentInfo, token, threadSafeDialogMaker, info -> this.updateUserInfo());
}
@FXML
void showResumeManage(ActionEvent event) {
ResumeManagePage controller = (ResumeManagePage) this.switchPage("resumeManage");
ResumeManagePage.InitData data = new ResumeManagePage.InitData();
data.setToken(token);
data.setDialogMaker(threadSafeDialogMaker);
controller.loadData(data);
}
private String currentWindow = "";
private Node switchPage(String page) {
if (currentWindow.equals(page)) {
return pages.get(page);
}
ObservableList<Node> list = containerPane.getChildren();
new FadeOut(list.get(0)).play();
Pane pagePane = pages.get(page);
if (pagePane != null) {
list.clear();
list.add(pagePane);
new FadeIn(pagePane).play();
currentWindow = page;
}
return pagePane;
}
@Data
@Builder
public static class InitData {
private String token;
private String username;
}
}

@ -0,0 +1,235 @@
package net.lensfrex.disillusion.client.controller.page.student;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import com.jfoenix.controls.JFXRadioButton;
import com.jfoenix.controls.JFXTextArea;
import com.jfoenix.controls.JFXTextField;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.config.Constants;
import net.lensfrex.disillusion.client.data.response.StudentInfoResponse;
import net.lensfrex.disillusion.client.util.ImageUtil;
import net.lensfrex.disillusion.client.util.OkhttpUtil;
import net.lensfrex.disillusion.client.util.ResponseHandler;
import net.lensfrex.disillusion.client.util.ThreadSafeDialogMaker;
import okhttp3.Response;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class StudentProfilePage extends HBox {
@FXML
private HBox rootPane;
@FXML
private ImageView avatarImageView;
@FXML
private Text usernameText;
@FXML
private Text signText;
@FXML
private JFXTextField signEditText;
@FXML
private JFXTextArea describeTextArea;
@FXML
private JFXTextField realNameTextField;
@FXML
private JFXTextField ageTextField;
@FXML
private JFXRadioButton maleRadioButton;
@FXML
private JFXRadioButton femaleRadioButton;
@FXML
private JFXTextField contactTextField;
@FXML
private JFXTextField idNumberTextField;
private File newAvatarFile;
private String token;
private static final Pattern agePattern = Pattern.compile("^\\d{2}$");
private ThreadSafeDialogMaker dialogMaker;
@FXML
void save(ActionEvent event) {
studentInfo.setRealName(realNameTextField.getText());
studentInfo.setShortDescribe(signEditText.getText());
studentInfo.setDescribe(describeTextArea.getText());
studentInfo.setPhoneNumber(contactTextField.getText());
studentInfo.setIdNumber(idNumberTextField.getText());
String inputAge = ageTextField.getText();
Matcher ageMatcher = agePattern.matcher(inputAge);
if (!ageMatcher.matches()) {
dialogMaker.createMessageDialog("啊哈", "年龄格式不正确(2位数字)");
}
studentInfo.setAge(Integer.parseInt(inputAge));
studentInfo.setSex(sexGroup.getSelectedToggle().getUserData().equals("0") ? 0 : 1);
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_INFO_EDIT_URL)
.token(token)
.body(studentInfo)
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "更新上传用户信息的时候出错啦:\n" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "更新上传用户信息不成功:" + s))
.successCallback(s -> {
updateCallback.accept(studentInfo);
dialogMaker.createMessageDialog("好耶", "更新成功");
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
}
@FXML
void replaceAvatar(MouseEvent event) {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("选择图片");
File chooseFile = fileChooser.showOpenDialog(rootPane.getScene().getWindow());
if (chooseFile != null) {
String fileType = FileUtil.getType(chooseFile);
switch (fileType) {
case "png":
case "jpg":
case "jpeg":
case "gif":
case "webm":
this.uploadAvatar(chooseFile);
break;
default:
dialogMaker.createMessageDialog(
"(;´д`)ゞ",
"头像文件不支持:" + fileType + "\n仅支持png, jpg, gif, webm"
);
}
}
}
private void uploadAvatar(File avatarFile) {
try {
byte[] avatarData;
// 大于1m的图片就进行压缩
long fileLength = avatarFile.length();
if (fileLength > 1048576) {
// 压缩比例,文件越大压缩程度越大
float percent = (float) Math.pow(0.96, fileLength / 1048576f);
avatarData = ImageUtil.processImage(avatarFile, 0.8f, percent, "jpg");
} else {
avatarData = Files.readAllBytes(Paths.get(avatarFile.toURI()));
}
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_EDIT_URL)
.token(token)
.body(Base64.encode(avatarData), "plain/text")
.failCallback(e -> dialogMaker.createMessageDialog("啊哈", "上传头像文件时发生网络错误:" + e))
.successCallback(response -> new ResponseHandler(response)
.errorCallback(s -> dialogMaker.createMessageDialog("啊哈", "获取头像时出现问题:" + s))
.successCallback(s -> {
updateCallback.accept(studentInfo);
Platform.runLater(() -> setAvatar(avatarImageView, avatarData));
})
.process())
.executeAsync(OkhttpUtil.RequestMethod.POST);
} catch (IOException e) {
dialogMaker.createMessageDialog("啊哈", "读取头像文件时发生错误:" + e);
}
}
private final ToggleGroup sexGroup = new ToggleGroup();
@FXML
public void initialize() {
maleRadioButton.setUserData("0");
femaleRadioButton.setUserData("1");
maleRadioButton.setToggleGroup(sexGroup);
femaleRadioButton.setToggleGroup(sexGroup);
}
private StudentInfoResponse studentInfo;
private Consumer<StudentInfoResponse> updateCallback;
public void setData(StudentInfoResponse studentInfo,
String token, ThreadSafeDialogMaker dialogMaker,
Consumer<StudentInfoResponse> updateCallback) {
this.studentInfo = studentInfo;
this.token = token;
this.dialogMaker = dialogMaker;
this.updateCallback = updateCallback;
usernameText.setText(studentInfo.getId());
realNameTextField.setText(studentInfo.getRealName());
signText.setText(studentInfo.getShortDescribe());
signEditText.setText(studentInfo.getShortDescribe());
describeTextArea.setText(studentInfo.getDescribe());
contactTextField.setText(studentInfo.getPhoneNumber());
idNumberTextField.setText(studentInfo.getIdNumber());
ageTextField.setText(studentInfo.getAge() + "");
switch (studentInfo.getSex()) {
case 0:
sexGroup.selectToggle(maleRadioButton);
break;
case 1:
sexGroup.selectToggle(femaleRadioButton);
break;
}
new OkhttpUtil()
.url(Constants.UserRequestUrls.USER_AVATAR_VIEW_URL)
.token(token)
.successCallback(response -> Platform.runLater(() -> setAvatar(avatarImageView, response)))
.executeAsync(OkhttpUtil.RequestMethod.GET);
}
public static void setAvatar(ImageView avatarImageView, Response response) {
try {
assert response.body() != null;
byte[] data = response.body().bytes();
setAvatar(avatarImageView, data);
} catch (Exception e) {
log.warn("获取头像数据时出现异常", e);
}
}
public static void setAvatar(ImageView avatarImageView, byte[] data) {
Image avatarImage = new Image(new ByteArrayInputStream(data));
avatarImageView.setImage(avatarImage);
}
}

@ -0,0 +1,45 @@
/*
* Class created by lensfrex.
*/
package net.lensfrex.disillusion.client.data;
public enum ResponseCode {
SUCCESS(20000, "成功"),
REQUEST_TOO_FAST(20001, "技能冷却中..."),
INVALID_REQUEST(30000, "非法请求"),
PARAM_WRONG(30001, "参数错误"),
PERMISSION_DENIED(40000, "权限不足"),
TOKEN_EXPIRED(40001, "token过期"),
TOKEN_INVALID(40002, "token无效"),
IDENTIFY_ERROR(40100, "用户不存在或密码错误"),
USER_ALREADY_EXISTS(40101, "用户名已经被注册"),
USER_NOT_EXISTS(40103, "用户不存在"),
SERVER_INTERNAL_ERROR(50000, "服务器内部错误"),
API_NOT_IMPLEMENT(0, "接口未实现"),
REQUEST_FILE_DOES_NOT_EXIST(60701, "请求的文件不存在");
private final int code;
private final String message;
ResponseCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}

@ -0,0 +1,20 @@
package net.lensfrex.disillusion.client.data.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApplicationRequest {
/**
* 申请的offerId
*/
private String offerId;
/**
* 简历id
*/
private String resumeId;
}

@ -0,0 +1,36 @@
package net.lensfrex.disillusion.client.data.request;
import lombok.Data;
@Data
public class OfferPublishRequest {
/**
* 岗位名称
*/
private String jobName;
/**
* 工作地点
*/
private String place;
/**
* 要求
*/
private String requirement;
/**
* 预期薪资
*/
private int salary;
/**
* 目标人数
*/
private int targetNumber;
/**
* 详细信息
*/
private String detail;
}

@ -0,0 +1,21 @@
package net.lensfrex.disillusion.client.data.request;
import lombok.Data;
@Data
public class ResumeRequest {
/**
* 简历标题名称
*/
private String title;
/**
* 简历备注信息
*/
private String remark;
/**
* 简历文件数据base64
*/
private String resumeFileBase64;
}

@ -0,0 +1,37 @@
package net.lensfrex.disillusion.client.data.response;
import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import lombok.Data;
/**
* 求职申请
*/
@Data
public class ApplicationResponse {
private String id;
/**
* 发布者id
*/
private String publisherId;
/**
* 目标公司id
*/
private String targetId;
/**
* 申请的offerId
*/
private String offerId;
/**
* 简历id
*/
private String resumeId;
/**
* 申请状态
*/
private String status;
}

@ -0,0 +1,41 @@
package net.lensfrex.disillusion.client.data.response;
import lombok.Data;
/**
* 用人单位信息
*/
@Data
public class EmployerInfoResponse {
private String id;
/**
* 公司名称
*/
private String name;
/**
* 总部地址
*/
private String place;
/**
* 联系方式
*/
private String contract;
/**
* 公司简要介绍
*/
private String shortDescribe;
/**
* 公司介绍
*/
private String describe;
/**
* 所属行业
*/
private String industry;
}

@ -0,0 +1,61 @@
package net.lensfrex.disillusion.client.data.response;
import lombok.Data;
import java.util.Objects;
/**
* 招聘信息
*/
@Data
public class OfferResponse {
private String id;
/**
* 发布公司
*/
private String publisherId;
/**
* 岗位名称
*/
private String jobName;
/**
* 工作地点
*/
private String place;
/**
* 要求
*/
private String requirement;
/**
* 预期薪资
*/
private Integer salary;
/**
* 目标人数
*/
private Integer targetNumber;
/**
* 详细信息
*/
private String detail;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OfferResponse offer = (OfferResponse) o;
return id.equals(offer.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}

@ -0,0 +1,40 @@
package net.lensfrex.disillusion.client.data.response;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class PublicEmployerInfoResponse {
private String id;
/**
* 公司名称
*/
private String name;
/**
* 总部地址
*/
private String place;
/**
* 联系方式
*/
private String contract;
/**
* 公司简要介绍
*/
private String shortDescribe;
/**
* 公司介绍
*/
private String describe;
/**
* 所属行业
*/
private String industry;
}

@ -0,0 +1,38 @@
package net.lensfrex.disillusion.client.data.response;
import lombok.Data;
@Data
public class PublicStudentInfoResponse {
private String id;
/**
* 真名
*/
private String realName;
/**
* 简介
*/
private String shortDescribe;
/**
* 介绍
*/
private String describe;
/**
* 电话号
*/
private String phoneNumber;
/**
* 年龄
*/
private int age;
/**
* 性别01
*/
private int sex;
}

@ -0,0 +1,31 @@
package net.lensfrex.disillusion.client.data.response;
import lombok.Data;
/**
* 简历
*/
@Data
public class ResumeResponse {
private String id;
/**
* 学生id
*/
private String ownerId;
/**
* 简历标题名称
*/
private String title;
/**
* 简历备注信息
*/
private String remark;
/**
* 简历文件id一般来说等同于简历id
*/
private String resumeFileId;
}

@ -0,0 +1,43 @@
package net.lensfrex.disillusion.client.data.response;
import lombok.Data;
@Data
public class StudentInfoResponse {
private String id;
/**
* 真名
*/
private String realName;
/**
* 简介
*/
private String shortDescribe;
/**
* 介绍
*/
private String describe;
/**
* 电话号
*/
private String phoneNumber;
/**
* 身份证号
*/
private String idNumber;
/**
* 年龄
*/
private int age;
/**
* 性别01
*/
private int sex;
}

@ -0,0 +1,8 @@
package net.lensfrex.disillusion.client.util;
import java.io.IOException;
public interface Consumer<T> {
void accept(T t) throws IOException;
}

@ -0,0 +1,130 @@
package net.lensfrex.disillusion.client.util;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXDialogLayout;
import javafx.beans.NamedArg;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class DialogMaker {
Pane rootPane;
public DialogMaker(@NamedArg("rootPane") Pane rootPane) {
this.rootPane = rootPane;
}
public void createMessageDialog(@NamedArg("title") String title, @NamedArg("message") String message) {
JFXButton OKButton = new JFXButton("了解!");
OKButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD, 12));
OKButton.setPrefWidth(60);
OKButton.setPrefHeight(30);
Text messageText = new Text(message);
messageText.setFont(Font.font("Microsoft YaHei", 14));
createDialog(title, messageText, OKButton);
}
//创建只有一个按钮的dialog
public void createDialogWithOneBtn(@NamedArg("title") String title, @NamedArg("theBody") Node body, @NamedArg("OKEvent") EventHandler<ActionEvent> event) {
//dialog.setPrefHeight(rootPane.getPrefHeight());
//dialog.setPrefWidth(rootPane.getPrefWidth());
JFXButton OKButton = new JFXButton("好的!");
OKButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD, 12));
OKButton.setPrefWidth(60);
OKButton.setPrefHeight(30);
createDialog(title, body, OKButton);
if (event != null) {
OKButton.addEventHandler(ActionEvent.ACTION, event);
}
}
public void createDialogWithOneBtn(@NamedArg("title") String title, @NamedArg("theBody") Node body) {
createDialogWithOneBtn(title, body, null);
}
//创建有OK和cancel按钮的dialog
public void createDialogWithOKAndCancel(@NamedArg("title") String title, @NamedArg("message") String message, @NamedArg("OKEvent") EventHandler<ActionEvent> OKEvent) {
Text messageText = new Text(message);
messageText.setFont(Font.font("Microsoft YaHei", 14));
createDialogWithOKAndCancel(title, messageText, OKEvent);
}
//创建有OK和cancel按钮的dialog
public void createDialogWithOKAndCancel(@NamedArg("title") String title, @NamedArg("body") Node body, @NamedArg("OKEvent") EventHandler<ActionEvent> OKEvent) {
JFXButton CancelButton = new JFXButton("手滑了");
CancelButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD, 12));
CancelButton.setPrefWidth(60);
CancelButton.setPrefHeight(30);
JFXButton OKButton = new JFXButton("是!");
OKButton.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD, 12));
OKButton.setPrefWidth(60);
OKButton.setPrefHeight(30);
OKButton.setTextFill(Paint.valueOf("red"));
OKButton.addEventHandler(ActionEvent.ACTION, OKEvent);
createDialog(title, body, CancelButton, OKButton);
}
public void createDialog(@NamedArg("title") String title, @NamedArg("theBody") Node body, @NamedArg("buttons") JFXButton... buttons) {
JFXDialogLayout content = new JFXDialogLayout();
Label titleLabel = new Label(title);
titleLabel.setFont(Font.font("Microsoft YaHei", FontWeight.BOLD, 22));
content.setHeading(titleLabel);
content.setBody(body);
content.setAlignment(Pos.CENTER);
StackPane tempPane = new StackPane();
tempPane.setPrefHeight(rootPane.getPrefHeight());
tempPane.setPrefWidth(rootPane.getPrefWidth());
rootPane.getChildren().add(tempPane);
JFXDialog dialog = new JFXDialog(tempPane, content, JFXDialog.DialogTransition.TOP);
dialog.setOnDialogClosed(event -> rootPane.getChildren().remove(tempPane));
for (JFXButton button : buttons) {
button.addEventHandler(ActionEvent.ACTION, e -> dialog.close());
}
content.setActions(buttons);
dialog.show();
}
public static void errorMessageDialog(String message) {
HBox box = new HBox(new TextArea(message));
box.setAlignment(Pos.CENTER);
Scene scene = new Scene(box, 500, 350);
Stage stage = new Stage();
stage.setTitle("出事了");
stage.setScene(scene);
stage.show();
}
}

@ -0,0 +1,20 @@
package net.lensfrex.disillusion.client.util;
import net.coobird.thumbnailator.Thumbnails;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
public class ImageUtil {
public static byte[] processImage(File inputFile, float scale, float level, String format) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Thumbnails.of(inputFile)
.scale(scale)
.outputQuality(level)
.outputFormat(format)
.toOutputStream(byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
}
}

@ -0,0 +1,173 @@
package net.lensfrex.disillusion.client.util;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import net.lensfrex.disillusion.client.config.Constants;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class OkhttpUtil {
private static final OkHttpClient client = Constants.globalClient;
private Request request;
private RequestBody requestBody;
private final Request.Builder requestBuilder;
private FormBody.Builder formBuilder;
private Consumer<Response> successCallback;
private java.util.function.Consumer<IOException> failCallback;
private String url;
private final Callback callbackWrapper = new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
try {
failCallback.accept(e);
} catch (Exception ex) {
e.printStackTrace();
}
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
try {
successCallback.accept(response);
} catch (Exception e) {
e.printStackTrace();
}
}
};
public OkhttpUtil() {
requestBuilder = new Request.Builder();
}
public OkhttpUtil url(String url) {
this.url = url;
return this;
}
private Map<String, String> queryParams;
public OkhttpUtil addQueryParam(String key, String value) {
if (queryParams == null) {
queryParams = new HashMap<>(10);
}
queryParams.put(key, value);
return this;
}
public OkhttpUtil token(String token) {
return this.addHeader("token", token);
}
public OkhttpUtil addHeader(String key, String value) {
requestBuilder.addHeader(key, value);
return this;
}
public OkhttpUtil successCallback(Consumer<Response> successCallback) {
this.successCallback = successCallback;
return this;
}
public OkhttpUtil failCallback(java.util.function.Consumer<IOException> failCallbackCallback) {
this.failCallback = failCallbackCallback;
return this;
}
public OkhttpUtil callback(Consumer<Response> successCallback, java.util.function.Consumer<IOException> failCallbackCallback) {
this.successCallback = successCallback;
this.failCallback = failCallbackCallback;
return this;
}
public OkhttpUtil form(String key, String value) {
if (formBuilder == null) {
formBuilder = new FormBody.Builder();
}
formBuilder.add(key, value);
return this;
}
public OkhttpUtil body(String data, String contentType) {
requestBody = RequestBody.create(data, MediaType.parse(contentType));
return this;
}
public OkhttpUtil body(Object data) {
String jsonData = JSONUtil.toJsonStr(data);
return body(jsonData, "application/json");
}
public OkhttpUtil body(byte[] data, String contentType) {
requestBody = RequestBody.create(data, MediaType.parse(contentType));
return this;
}
private static final byte[] EMPTY_DATA = "".getBytes(StandardCharsets.UTF_8);
public void executeAsync(RequestMethod method) {
this.execute(method).enqueue(callbackWrapper);
}
public Response executeSync(RequestMethod method) {
try {
return execute(method).execute();
} catch (IOException e) {
if (failCallback != null) {
failCallback.accept(e);
}
}
return null;
}
private Call execute(RequestMethod method) {
if (queryParams == null) {
requestBuilder.url(URLUtil.url(url));
} else {
String queryParamString = URLUtil.buildQuery(queryParams, StandardCharsets.UTF_8);
requestBuilder.url(URLUtil.url(url + "?" + queryParamString));
}
switch (method) {
case GET:
request = requestBuilder.get().build();
return client.newCall(request);
case POST:
if (requestBody == null) {
if (formBuilder == null) {
requestBody = RequestBody.create(EMPTY_DATA);
} else {
requestBody = formBuilder.build();
}
}
request = requestBuilder.post(requestBody).build();
return client.newCall(request);
default:
throw new IllegalArgumentException();
}
}
public static enum RequestMethod {
GET, POST
}
}

@ -0,0 +1,72 @@
package net.lensfrex.disillusion.client.util;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.disillusion.client.data.ResponseCode;
import okhttp3.Response;
import java.io.IOException;
@Slf4j
public class ResponseHandler {
@SafeVarargs
public static Result parse(Response response, Consumer<String>... errorCallbacks) throws IOException {
assert response.body() != null;
String responseString = response.body().string();
JSONObject responseJson = JSONUtil.parseObj(responseString);
boolean success = true;
Integer code = responseJson.getInt("code");
String message = responseJson.getStr("message");
if (code == null || !code.equals(ResponseCode.SUCCESS.getCode())) {
if (message == null) {
message = responseString;
}
if (errorCallbacks != null) {
for (Consumer<String> errorCallback : errorCallbacks) {
errorCallback.accept(message);
}
}
success = false;
log.warn("请求错误:" + message);
}
return new Result(success, message, responseJson.getStr("data"));
}
private final Response response;
private Consumer<String> errorCallback;
private Consumer<String> successCallback;
public ResponseHandler(Response response) {
this.response = response;
}
public ResponseHandler errorCallback(Consumer<String> errorCallback) {
this.errorCallback = errorCallback;
return this;
}
public ResponseHandler successCallback(Consumer<String> successCallback) {
this.successCallback = successCallback;
return this;
}
public void process() throws IOException {
Result result = parse(response, errorCallback);
if (result.success) {
successCallback.accept(result.data);
}
}
@AllArgsConstructor
public static class Result {
public final boolean success;
public final String message;
public final String data;
}
}

@ -0,0 +1,43 @@
package net.lensfrex.disillusion.client.util;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.events.JFXDialogEvent;
import javafx.application.Platform;
import javafx.beans.NamedArg;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
public class ThreadSafeDialogMaker extends DialogMaker {
public ThreadSafeDialogMaker(@NamedArg("rootPane") Pane rootPane) {
super(rootPane);
}
public void createMessageDialog(@NamedArg("title") String title, @NamedArg("message") String message) {
Platform.runLater(() -> super.createMessageDialog(title, message));
}
//创建只有一个按钮的dialog
public void createDialogWithOneBtn(@NamedArg("title") String title, @NamedArg("theBody") Node body, @NamedArg("OKEvent") EventHandler<ActionEvent> event) {
Platform.runLater(() -> super.createDialogWithOneBtn(title, body, event));
}
public void createDialogWithOneBtn(@NamedArg("title") String title, @NamedArg("theBody") Node body) {
createDialogWithOneBtn(title, body, null);
}
//创建有OK和cancel按钮的dialog
public void createDialogWithOKAndCancel(@NamedArg("title") String title, @NamedArg("message") String message, @NamedArg("OKEvent") EventHandler<ActionEvent> OKEvent) {
Platform.runLater(() -> super.createDialogWithOKAndCancel(title, message, OKEvent));
}
//创建有OK和cancel按钮的dialog
public void createDialogWithOKAndCancel(@NamedArg("title") String title, @NamedArg("body") Node body, @NamedArg("OKEvent") EventHandler<ActionEvent> OKEvent) {
Platform.runLater(() -> super.createDialogWithOKAndCancel(title, body, OKEvent));
}
public void createDialog(@NamedArg("title") String title, @NamedArg("theBody") Node body, @NamedArg("buttons") JFXButton... buttons) {
Platform.runLater(() -> super.createDialog(title, body, buttons));
}
}

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: net.lensfrex.disillusion.client.ClientMain

@ -0,0 +1,13 @@
前期经过自愿报名并审核成功的学生,根据所报微专业的培养方案,自行选择相应课程。
9.认真对照培养方案,选课时务必仔细核对课程信息,确保“课程代码”、“课程名称”、“学分”这三项重要信息与培养方案要求相符。
10.禁止同一时间修读两门及以上课程,系统会提示时间冲突并禁止选课。提前了解专业教学进程(实习、实践、课程设计等)情况,不能选择与本专业其它教学任务周次有冲突的课堂。
11.因培养方案变动、转专业等原因,计划修读的课程确定不再开课的,请先查询本科生课程学分认定对照表并咨询开课学院,再进行选课。待课程修读完获得学分后,再按照本科生院发布的相关要求办理学分认定。
12.学生选课、听课、考核必须一致。学生不能参加未选择课程的学习和考核,即使参加了学习和考核,如果没有选课,也是无效的,将不记录成绩。
13.学生凭学号、密码选课,认真对待,并对自己的选课行为负责。密码必须妥善保管,不得代替他人选课,不得借用、盗用他人学号及密码选课。
14.学生登录本科教学综合管理系统需通过学校统一身份认证平台登录,登录方式、密码重置方式详见以下两个通知:https://jwc.wust.edu.cn/2022/0226/c1925a255654/page.htm、https://jwc.wust.edu.cn/2022/0302/c1925a255786/page.htm。

@ -0,0 +1,60 @@
/*******************************************************************************
* *
* Scroll Bar *
* *
******************************************************************************/
.scroll-bar:vertical > .track-background, .scroll-bar:horizontal > .track-background {
-fx-background-color: #F1F1F1;
-fx-background-insets: 0.0;
}
.scroll-bar:vertical > .thumb, .scroll-bar:horizontal > .thumb {
-fx-background-color: #BCBCBC;
-fx-background-insets: 0.0;
-fx-background-radius: 1.0;
}
.scroll-bar > .increment-button, .scroll-bar > .decrement-button {
-fx-padding: 5 2 5 2;
}
.scroll-bar > .increment-button, .scroll-bar > .decrement-button, .scroll-bar:hover > .increment-button, .scroll-bar:hover > .decrement-button {
-fx-background-color: transparent;
}
.scroll-bar > .increment-button > .increment-arrow, .scroll-bar > .decrement-button > .decrement-arrow {
-fx-background-color: rgb(150.0, 150.0, 150.0);
}
.scroll-bar > .increment-button > .increment-arrow {
-fx-shape: "M298 426h428l-214 214z";
}
.scroll-bar > .decrement-button > .decrement-arrow {
-fx-shape: "M298 598l214-214 214 214h-428z";
}
/*******************************************************************************
* *
* Scroll Pane *
* *
******************************************************************************/
.scroll-pane {
-fx-background: white;
-fx-background-insets: 0;
-fx-padding: 0;
}
.scroll-pane:focused {
-fx-background-insets: 0;
}
.scroll-pane .corner {
-fx-background-insets: 0;
}
.jfx-list-cell:odd:selected .jfx-rippler .jfx-list-cell:even:selected {
-fx-background-color: rgba(255, 0, 0, 0.2);
}

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXRadioButton?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="89.0" prefWidth="275.0" spacing="15.0" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label text="处理意见">
<font>
<Font size="16.0" />
</font>
</Label>
<HBox spacing="50.0">
<children>
<JFXRadioButton fx:id="acceptRadioButton" selected="true" text="接受">
<font>
<Font size="16.0" />
</font>
</JFXRadioButton>
<JFXRadioButton fx:id="rejectRadioButton" text="拒绝">
<font>
<Font size="16.0" />
</font>
</JFXRadioButton>
</children>
</HBox>
</children>
</fx:root>

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="523.0" style="-fx-background-color: white;" type="HBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox onMouseClicked="#viewStudentInfo" HBox.hgrow="ALWAYS">
<children>
<Text fx:id="studentNameText" strokeType="OUTSIDE" strokeWidth="0.0" text="名字" wrappingWidth="300.0">
<font>
<Font size="30.0" />
</font>
</Text>
<Text fx:id="describeText" strokeType="OUTSIDE" strokeWidth="0.0" text="简单的介绍自己" wrappingWidth="300.0">
<font>
<Font size="14.0" />
</font>
</Text>
</children>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</VBox>
<HBox alignment="CENTER" spacing="10.0">
<children>
<JFXButton onAction="#viewResume" prefHeight="40.0" prefWidth="90.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 20;" text="查看简历" textFill="WHITE">
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
<font>
<Font size="14.0" />
</font>
</JFXButton>
<JFXButton onAction="#dealApplication" prefHeight="40.0" prefWidth="90.0" style="-fx-background-color: #43A047; -fx-background-radius: 20;" text="处理" textFill="WHITE">
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
<font>
<Font size="14.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</fx:root>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="460.0" prefWidth="550.0" type="StackPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ScrollPane hbarPolicy="NEVER" pannable="true" prefHeight="460.0" style="-fx-background: white;" styleClass="edge-to-edge">
<content>
<VBox fx:id="applicationContainer" alignment="TOP_CENTER" spacing="10.0" style="-fx-background-color: #FAFAFA;" />
</content>
</ScrollPane>
</children>
</fx:root>

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="740.0" prefWidth="959.0" spacing="5.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox alignment="CENTER_LEFT">
<children>
<VBox spacing="10.0" HBox.hgrow="ALWAYS">
<children>
<Label text="求职申请管理">
<font>
<Font name="System Bold" size="23.0" />
</font>
</Label>
<Label text="在这里可以管理接收到的求职申请(未处理的)">
<font>
<Font size="15.0" />
</font>
</Label>
</children>
</VBox>
<JFXButton onAction="#refresh" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 18;" text="刷新" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
</children>
</HBox>
<ScrollPane fx:id="scrollPane" fitToWidth="true" hbarPolicy="NEVER" pannable="true" style="-fx-background: white;" styleClass="edge-to-edge" VBox.vgrow="ALWAYS">
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<content>
<FlowPane fx:id="offerContainer" columnHalignment="CENTER" hgap="20.0" vgap="20.0">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</FlowPane>
</content>
</ScrollPane>
</children>
<padding>
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
</padding>
</fx:root>

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#viewApplications" type="StackPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox>
<children>
<StackPane fx:id="header" alignment="TOP_LEFT" style="-fx-background-radius: 10 10 0 0; -fx-background-color: #4A8895;" VBox.vgrow="ALWAYS">
<children>
<Label fx:id="jobName" alignment="TOP_LEFT" cache="true" prefHeight="90.0" prefWidth="225.0" style="-fx-font-smoothing-type: gray;" text="武汉 高级Golang开发&#10;第二行&#10;第三行" textFill="WHITE">
<font>
<Font size="23.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="15.0" />
</padding>
</StackPane>
<StackPane fx:id="body" style="-fx-background-radius: 0 0 10 10; -fx-background-color: rgb(255,255,255,0.87);">
<children>
<HBox prefHeight="70.0">
<children>
<VBox alignment="CENTER_LEFT" prefHeight="60.0" HBox.hgrow="ALWAYS">
<children>
<Text fx:id="processText" strokeType="OUTSIDE" strokeWidth="0.0" text="招募进度:2/5">
<font>
<Font size="14.0" />
</font>
</Text>
</children>
<HBox.margin>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</HBox.margin>
</VBox>
</children>
</HBox>
</children>
</StackPane>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="118.0" prefWidth="273.0" spacing="15.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label text="点击以下载简历文件">
<font>
<Font size="16.0" />
</font>
</Label>
<JFXButton onAction="#download" prefHeight="40.0" prefWidth="90.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 20;" text="下载" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
</JFXButton>
</children>
</fx:root>

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="588.0" prefWidth="1000.0" style="-fx-background-color: white;" type="HBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox prefWidth="263.0" spacing="20.0">
<children>
<StackPane style="-fx-border-color: black; -fx-border-width: 2; -fx-border-radius: 100;">
<children>
<ImageView fx:id="avatarImageView" fitHeight="200.0" fitWidth="200.0" pickOnBounds="true">
<image>
<Image url="@../../../../../../../../../../../../pixiv/pixez/61212844_p0_compress_2.png" />
</image>
<cursor>
<Cursor fx:constant="DEFAULT" />
</cursor>
<clip>
<Circle centerX="100" centerY="100" fill="cyan">
<radius>100</radius>
</Circle>
</clip>
</ImageView>
</children>
</StackPane>
<VBox spacing="7.0">
<children>
<Text fx:id="usernameText" strokeType="OUTSIDE" strokeWidth="0.0" text="lensfrex" wrappingWidth="200.0">
<font>
<Font size="22.0" />
</font>
</Text>
<Text fx:id="signText" strokeType="OUTSIDE" strokeWidth="0.0" text="这个人很懒,什么都没写" wrappingWidth="200.0" />
</children>
</VBox>
</children>
<padding>
<Insets left="50.0" top="30.0" />
</padding>
</VBox>
<VBox prefWidth="100.0" HBox.hgrow="ALWAYS">
<padding>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</padding>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="20.0" VBox.vgrow="ALWAYS">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="60.0" prefWidth="670.0" spacing="10.0">
<children>
<VBox prefWidth="183.0">
<children>
<Label text="真名">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="realNameTextField" editable="false" prefHeight="30.0" prefWidth="177.0" text="是真名">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="52.0" stroke="#a8a8a8">
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin>
</Line>
<VBox>
<children>
<Label text="年龄">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="ageTextField" editable="false" prefHeight="30.0" prefWidth="147.0" text="22">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="52.0" stroke="#a8a8a8">
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin>
</Line>
<VBox spacing="15.0" HBox.hgrow="ALWAYS">
<children>
<Label text="性别">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<Text fx:id="sexText" strokeType="OUTSIDE" strokeWidth="0.0" text="男">
<font>
<Font size="14.0" />
</font>
</Text>
</children>
</VBox>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="55.0" prefWidth="670.0" spacing="10.0">
<children>
<VBox prefHeight="55.0" prefWidth="375.0">
<children>
<Label text="联系方式">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="contactTextField" editable="false" text="asdf@outlook.com">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
</HBox>
<VBox>
<children>
<Label text="个性签名">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="signTextField" editable="false" prefHeight="29.0" prefWidth="614.0" text="没有个性签名">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
<VBox.margin>
<Insets top="40.0" />
</VBox.margin>
</VBox>
<VBox>
<children>
<Label text="自我介绍">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextArea fx:id="describeTextArea" editable="false" text="自我介绍自我介绍">
<font>
<Font size="16.0" />
</font>
</JFXTextArea>
</children>
</VBox>
</children>
</VBox>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Rectangle2D?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.effect.DropShadow?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<StackPane fx:id="rootPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1" fx:controller="net.lensfrex.disillusion.client.controller.page.employer.EmployerMainController">
<children>
<HBox style="-fx-background-color: white;">
<children>
<VBox alignment="TOP_CENTER" prefHeight="740.0" prefWidth="300.0" spacing="20.0" style="-fx-background-color: #BBDEFB;">
<children>
<HBox prefHeight="135.0" prefWidth="320.0" VBox.vgrow="ALWAYS">
<children>
<ImageView fx:id="avatarImageView" fitHeight="64.0" fitWidth="64.0" pickOnBounds="true" preserveRatio="true">
<viewport>
<Rectangle2D />
</viewport>
<image>
<Image url="@../../../../../../../../../../../pixiv/pixez/93285655_p0.png" />
</image>
<clip>
<Circle centerX="32" centerY="32" fill="cyan">
<radius>32</radius>
</Circle>
</clip>
<effect>
<DropShadow>
<radius>5</radius>
<offsetY>2.0</offsetY>
</DropShadow>
</effect>
</ImageView>
<VBox prefHeight="102.0" prefWidth="186.0" spacing="2.0">
<children>
<Text fx:id="employerName" strokeType="OUTSIDE" strokeWidth="0.0" text="lensfrex" wrappingWidth="199.0">
<font>
<Font size="28.0" />
</font>
</Text>
<Text fx:id="usernameText" strokeType="OUTSIDE" strokeWidth="0.0" text="\@lensferno" wrappingWidth="199.0">
<font>
<Font size="13.0" />
</font>
</Text>
<Text fx:id="shortDescribeText" strokeType="OUTSIDE" strokeWidth="0.0" text="这个人真的很懒,什么都没写" wrappingWidth="198.240234375">
<VBox.margin>
<Insets top="2.0" />
</VBox.margin>
</Text>
</children>
<padding>
<Insets left="10.0" />
</padding>
</VBox>
</children>
<padding>
<Insets left="30.0" right="10.0" top="30.0" />
</padding>
</HBox>
<VBox alignment="TOP_CENTER" prefHeight="591.0" prefWidth="318.0" spacing="35.0" VBox.vgrow="ALWAYS">
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<children>
<JFXButton onAction="#showOfferManagePage" prefHeight="51.0" prefWidth="230.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="Offer管理" textFill="WHITE" VBox.vgrow="ALWAYS">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
<JFXButton onAction="#showApplicationDealPage" prefHeight="51.0" prefWidth="230.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="求职申请处理" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
<JFXButton onAction="#showProfile" prefHeight="51.0" prefWidth="230.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="企业信息" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
</children>
</VBox>
</children>
</VBox>
<StackPane fx:id="containerPane" style="-fx-background-color: white;" HBox.hgrow="ALWAYS">
<children>
<Pane prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" />
</children>
</StackPane>
</children>
</HBox>
</children>
</StackPane>

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#viewDetail" type="StackPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox>
<children>
<StackPane fx:id="header" alignment="TOP_LEFT" style="-fx-background-radius: 10 10 0 0; -fx-background-color: #4A8895;" VBox.vgrow="ALWAYS">
<children>
<Label fx:id="jobName" alignment="TOP_LEFT" cache="true" prefHeight="90.0" prefWidth="225.0" style="-fx-font-smoothing-type: gray;" text="武汉 高级Golang开发&#10;第二行&#10;第三行" textFill="WHITE">
<font>
<Font size="23.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="15.0" />
</padding>
</StackPane>
<StackPane fx:id="body" style="-fx-background-radius: 0 0 10 10; -fx-background-color: rgb(255,255,255,0.87);">
<children>
<HBox prefHeight="70.0" prefWidth="275.0">
<children>
<VBox alignment="CENTER_LEFT" prefHeight="60.0" HBox.hgrow="ALWAYS">
<children>
<Text fx:id="processText" strokeType="OUTSIDE" strokeWidth="0.0" text="招聘进度:2/5">
<font>
<Font size="14.0" />
</font>
</Text>
</children>
<HBox.margin>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</HBox.margin>
</VBox>
<VBox alignment="CENTER" prefHeight="60.0" prefWidth="84.0">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<children>
<JFXButton fx:id="offerDeleteBtn" buttonType="RAISED" minHeight="40.0" minWidth="40.0" onAction="#deleteOffer" prefHeight="40.0" prefWidth="40.0" ripplerFill="#4a8895" scaleX="0.0" scaleY="0.0" style="-fx-background-radius: 40; -fx-background-color: #01A05E;" />
</children>
</VBox>
</children>
</HBox>
</children>
</StackPane>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="535.0" prefWidth="825.0" spacing="20.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox spacing="50.0">
<children>
<VBox spacing="5.0">
<children>
<Label text="职位名称">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXTextField fx:id="jobNameTextField">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<VBox spacing="5.0">
<children>
<Label text="预期薪资">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXTextField fx:id="salaryTextField">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<VBox spacing="5.0">
<children>
<Label text="计划招聘人数">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXTextField fx:id="planNumberTextField">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
</HBox>
<HBox spacing="50.0">
<children>
<VBox spacing="5.0">
<children>
<Label text="地点">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXTextField fx:id="placeTextField">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<VBox spacing="5.0" HBox.hgrow="ALWAYS">
<children>
<Label text="要求">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXTextField fx:id="requirementTextField">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
</HBox>
<HBox />
<HBox VBox.vgrow="ALWAYS">
<children>
<VBox HBox.hgrow="ALWAYS">
<children>
<Label text="详细信息">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXTextArea fx:id="detailTextArea" labelFloat="true" VBox.vgrow="ALWAYS">
<font>
<Font size="14.0" />
</font>
</JFXTextArea>
</children>
</VBox>
</children>
</HBox>
</children>
</fx:root>

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox spacing="10.0">
<children>
<Label text="Offer管理">
<font>
<Font name="System Bold" size="23.0" />
</font>
</Label>
<Label text="在这里你可以自己发布的Offer,也可以添加一些Offer">
<font>
<Font size="15.0" />
</font>
</Label>
</children>
</VBox>
<ScrollPane fx:id="scrollPane" fitToWidth="true" hbarPolicy="NEVER" pannable="true" prefHeight="661.0" prefWidth="1000.0" style="-fx-background: white;" styleClass="edge-to-edge">
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<content>
<FlowPane fx:id="offerContainer" columnHalignment="CENTER" hgap="20.0" vgap="20.0">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</FlowPane>
</content>
</ScrollPane>
<HBox alignment="CENTER_LEFT" prefHeight="59.0" prefWidth="1000.0" spacing="30.0">
<children>
<JFXButton buttonType="RAISED" minHeight="40.0" onAction="#addOffer" prefWidth="120.0" style="-fx-background-color: #1976D2; -fx-background-radius: 25;" text="添加" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
<padding>
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
</padding>
</fx:root>

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" type="HBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox prefHeight="740.0" prefWidth="263.0" spacing="20.0">
<children>
<StackPane style="-fx-border-color: black; -fx-border-width: 2; -fx-border-radius: 100;">
<children>
<ImageView fx:id="avatarImageView" fitHeight="200.0" fitWidth="200.0" onMouseClicked="#replaceAvatar" pickOnBounds="true">
<image>
<Image url="@../../../../../../../../../../../pixiv/pixez/61212844_p0_compress.png" />
</image>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
<clip>
<Circle centerX="100" centerY="100" fill="cyan">
<radius>100</radius>
</Circle>
</clip>
</ImageView>
</children>
</StackPane>
<VBox spacing="7.0">
<children>
<Text fx:id="usernameText" strokeType="OUTSIDE" strokeWidth="0.0" text="lensfrex" wrappingWidth="200.0">
<font>
<Font size="22.0" />
</font>
</Text>
<Text fx:id="shortDescribeText" strokeType="OUTSIDE" strokeWidth="0.0" text="这个人很懒,什么都没写" wrappingWidth="200.0" />
</children>
</VBox>
</children>
<padding>
<Insets left="100.0" top="30.0" />
</padding>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" HBox.hgrow="ALWAYS">
<padding>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</padding>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="20.0" VBox.vgrow="ALWAYS">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="60.0" prefWidth="670.0" spacing="10.0">
<children>
<VBox prefHeight="60.0" prefWidth="187.0">
<children>
<Label text="企业名称">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="employerNameTextField" prefHeight="30.0" prefWidth="177.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="52.0" stroke="#a8a8a8" />
<VBox>
<children>
<Label text="所属行业">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="industryTextField" prefHeight="30.0" prefWidth="147.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="55.0" prefWidth="670.0" spacing="5.0">
<children>
<VBox prefHeight="56.0" prefWidth="183.0">
<children>
<Label text="联系方式">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="contactTextField" prefHeight="29.0" prefWidth="66.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="55.0" fill="#a4a4a4" stroke="#a8a8a8">
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin>
</Line>
<VBox>
<children>
<Label text="地址">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="addressTextField" prefHeight="30.0" prefWidth="420.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
</HBox>
<VBox>
<children>
<Label text="简要介绍">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="shortDescribeTextField" prefHeight="29.0" prefWidth="614.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
<padding>
<Insets top="30.0" />
</padding>
</VBox>
<VBox>
<children>
<Label text="详细介绍">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextArea fx:id="describeTextArea">
<font>
<Font size="16.0" />
</font>
</JFXTextArea>
</children>
</VBox>
</children>
</VBox>
<HBox alignment="CENTER_RIGHT">
<children>
<JFXButton buttonType="RAISED" onAction="#save" prefHeight="43.0" prefWidth="127.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="保存" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
</children>
</HBox>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXPasswordField?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<StackPane fx:id="rootPane" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1" fx:controller="net.lensfrex.disillusion.client.controller.LoginMainController">
<children>
<VBox prefHeight="580.0" prefWidth="979.0" style="-fx-background-color: white;">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="49.0" prefWidth="979.0" style="-fx-background-color: #0090ff;">
<children>
<Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="disillusion">
<font>
<Font size="24.0" />
</font>
</Text>
</children>
<padding>
<Insets left="25.0" />
</padding>
</HBox>
<VBox alignment="TOP_CENTER" prefHeight="496.0" prefWidth="979.0" spacing="20.0" VBox.vgrow="ALWAYS">
<children>
<Text fill="#0090ff" strokeType="OUTSIDE" strokeWidth="0.0" text="在一切开始之前,请先登录或者注册">
<font>
<Font name="System Bold" size="35.0" />
</font>
</Text>
<VBox spacing="45.0">
<children>
<HBox alignment="CENTER" prefHeight="30.0" prefWidth="979.0" spacing="10.0">
<children>
<JFXTextField fx:id="usernameTextField" labelFloat="true" prefWidth="400.0" promptText="用户名">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</HBox>
<HBox alignment="CENTER" prefHeight="30.0" prefWidth="979.0" spacing="10.0">
<children>
<JFXPasswordField fx:id="passwordTextField" labelFloat="true" prefWidth="400.0" promptText="密码">
<font>
<Font size="14.0" />
</font>
</JFXPasswordField>
</children>
</HBox>
</children>
<VBox.margin>
<Insets top="60.0" />
</VBox.margin>
</VBox>
<HBox alignment="CENTER" spacing="40.0">
<VBox.margin>
<Insets top="40.0" />
</VBox.margin>
<children>
<JFXButton onAction="#doRegister" prefHeight="40.0" prefWidth="200.0" ripplerFill="#a5e9ff" style="-fx-background-color: #43A047; -fx-background-radius: 20;" text="注册" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
</JFXButton>
<JFXButton onAction="#doLogin" prefHeight="40.0" prefWidth="200.0" ripplerFill="#a5e9ff" style="-fx-background-color: #1E88E5; -fx-background-radius: 20;" text="登录" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
<padding>
<Insets top="30.0" />
</padding>
<VBox.margin>
<Insets top="30.0" />
</VBox.margin>
</VBox>
</children>
</VBox>
</children>
</StackPane>

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#viewDetail" type="StackPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox>
<children>
<StackPane fx:id="header" alignment="TOP_LEFT" style="-fx-background-radius: 10 10 0 0; -fx-background-color: #4A8895;" VBox.vgrow="ALWAYS">
<children>
<Label fx:id="jobName" alignment="TOP_LEFT" cache="true" prefHeight="90.0" prefWidth="225.0" style="-fx-font-smoothing-type: gray;" text="武汉 高级Golang开发&#10;第二行&#10;第三行" textFill="WHITE">
<font>
<Font size="23.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="15.0" />
</padding>
</StackPane>
<StackPane fx:id="body" style="-fx-background-radius: 0 0 10 10; -fx-background-color: rgb(255,255,255,0.87);">
<children>
<HBox prefHeight="70.0" prefWidth="275.0">
<children>
<VBox alignment="CENTER_LEFT" prefHeight="60.0" HBox.hgrow="ALWAYS">
<children>
<Text fx:id="statusText" strokeType="OUTSIDE" strokeWidth="0.0" text="状态:等待接受中">
<font>
<Font size="15.0" />
</font>
</Text>
</children>
<HBox.margin>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</HBox.margin>
</VBox>
<VBox alignment="CENTER" prefHeight="60.0" prefWidth="84.0">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<children>
<JFXButton fx:id="applicationDeleteBtn" buttonType="RAISED" minHeight="40.0" minWidth="40.0" onAction="#deleteApplication" prefHeight="40.0" prefWidth="40.0" ripplerFill="#4a8895" scaleX="0.0" scaleY="0.0" style="-fx-background-radius: 40; -fx-background-color: #01A05E;" />
</children>
</VBox>
</children>
</HBox>
</children>
</StackPane>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox spacing="10.0">
<children>
<Label text="求职申请管理">
<font>
<Font name="System Bold" size="23.0" />
</font>
</Label>
<Label text="在这里你可以管理发送的求职申请">
<font>
<Font size="15.0" />
</font>
</Label>
</children>
</VBox>
<ScrollPane fx:id="scrollPane" fitToWidth="true" hbarPolicy="NEVER" pannable="true" prefHeight="661.0" prefWidth="1000.0" style="-fx-background: white;" styleClass="edge-to-edge" VBox.vgrow="ALWAYS">
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<content>
<FlowPane fx:id="applicationContainer" columnHalignment="CENTER" hgap="20.0" vgap="20.0">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</FlowPane>
</content>
</ScrollPane>
</children>
<padding>
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
</padding>
</fx:root>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<HBox prefHeight="138.0" prefWidth="516.0" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox spacing="5.0">
<children>
<Label text="选择附带的简历">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXComboBox fx:id="resumeComboBox" prefHeight="23.0" prefWidth="204.0" />
</children>
</VBox>
</children>
</HBox>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root prefHeight="138.0" prefWidth="516.0" style="-fx-background-color: white;" type="HBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox spacing="5.0">
<children>
<Label text="选择附带的简历">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXComboBox fx:id="resumeComboBox" prefHeight="23.0" prefWidth="204.0" />
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="590.0" prefWidth="1000.0" style="-fx-background-color: white;" type="HBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox prefHeight="740.0" spacing="20.0">
<children>
<StackPane style="-fx-border-color: black; -fx-border-width: 2; -fx-border-radius: 100;">
<children>
<ImageView fx:id="avatarImageView" fitHeight="200.0" fitWidth="200.0" pickOnBounds="true">
<image>
<Image url="@../../../../../../../../../../../../pixiv/pixez/93334965_p0.png" />
</image>
<cursor>
<Cursor fx:constant="DEFAULT" />
</cursor>
<clip>
<Circle centerX="100" centerY="100" fill="cyan">
<radius>100</radius>
</Circle>
</clip>
</ImageView>
</children>
</StackPane>
<VBox spacing="7.0">
<children>
<Text fx:id="usernameText" strokeType="OUTSIDE" strokeWidth="0.0" text="lensfrex" wrappingWidth="200.0">
<font>
<Font size="22.0" />
</font>
</Text>
<Text fx:id="shortDescribeText" strokeType="OUTSIDE" strokeWidth="0.0" text="这个人很懒,什么都没写" wrappingWidth="200.0" />
</children>
</VBox>
</children>
<padding>
<Insets left="50.0" top="30.0" />
</padding>
</VBox>
<VBox prefHeight="200.0" HBox.hgrow="ALWAYS">
<padding>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</padding>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="20.0" VBox.vgrow="ALWAYS">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="60.0" prefWidth="670.0" spacing="10.0">
<children>
<VBox prefHeight="60.0" prefWidth="187.0">
<children>
<Label text="企业名称">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="employerNameTextField" editable="false" prefHeight="30.0" prefWidth="177.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="52.0" stroke="#a8a8a8" />
<VBox>
<children>
<Label text="所属行业">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="industryTextField" editable="false" prefHeight="30.0" prefWidth="147.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="55.0" fill="#a4a4a4" stroke="#a8a8a8">
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin>
</Line>
<VBox prefHeight="56.0" prefWidth="183.0" HBox.hgrow="ALWAYS">
<children>
<Label text="联系方式">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="contactTextField" editable="false" prefHeight="29.0" prefWidth="66.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="55.0" prefWidth="670.0" spacing="5.0">
<children>
<VBox HBox.hgrow="ALWAYS">
<children>
<Label text="地址">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="addressTextField" editable="false" prefHeight="30.0" prefWidth="420.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
</HBox>
<VBox>
<children>
<Label text="简要介绍">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="shortDescribeTextField" editable="false" prefHeight="29.0" prefWidth="614.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
<padding>
<Insets top="30.0" />
</padding>
</VBox>
<VBox>
<children>
<Label text="详细介绍">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextArea fx:id="describeTextArea" editable="false">
<font>
<Font size="16.0" />
</font>
</JFXTextArea>
</children>
</VBox>
</children>
</VBox>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#viewDetail" type="StackPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox>
<children>
<StackPane fx:id="header" alignment="TOP_LEFT" style="-fx-background-radius: 10 10 0 0; -fx-background-color: #4A8895;" VBox.vgrow="ALWAYS">
<children>
<VBox>
<children>
<Label fx:id="jobName" alignment="TOP_LEFT" cache="true" prefHeight="90.0" prefWidth="225.0" style="-fx-font-smoothing-type: gray;" text="武汉 高级Golang开发" textFill="WHITE">
<font>
<Font size="23.0" />
</font>
</Label>
<Text fx:id="progressText" fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0">
<font>
<Font size="14.0" />
</font>
</Text>
</children>
</VBox>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="15.0" />
</padding>
</StackPane>
<StackPane fx:id="body" style="-fx-background-radius: 0 0 10 10; -fx-background-color: rgb(255,255,255,0.87);">
<children>
<HBox prefHeight="70.0" prefWidth="275.0">
<children>
<VBox prefHeight="60.0" HBox.hgrow="ALWAYS">
<children>
<Text fx:id="salaryText" strokeType="OUTSIDE" strokeWidth="0.0" text="月薪:3.5w">
<font>
<Font size="14.0" />
</font>
</Text>
<Text fx:id="employerNameText" strokeType="OUTSIDE" strokeWidth="0.0" text="公司:xx信息">
<font>
<Font size="14.0" />
</font>
</Text>
<Text fx:id="workingPlaceText" strokeType="OUTSIDE" strokeWidth="0.0" text="工作地点:武汉">
<font>
<Font size="14.0" />
</font>
</Text>
</children>
<HBox.margin>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</HBox.margin>
</VBox>
<VBox alignment="CENTER" prefHeight="60.0" prefWidth="84.0">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<children>
<JFXButton fx:id="applicationSendBtn" buttonType="RAISED" minHeight="40.0" minWidth="40.0" onAction="#sendApplication" prefHeight="40.0" prefWidth="40.0" ripplerFill="#4a8895" scaleX="0.0" scaleY="0.0" style="-fx-background-radius: 40; -fx-background-color: #01A05E;" />
</children>
</VBox>
</children>
</HBox>
</children>
</StackPane>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="456.0" prefWidth="767.0" spacing="20.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox>
<children>
<VBox spacing="5.0">
<children>
<Label text="职位名称">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Text fx:id="jobNameText" strokeType="OUTSIDE" strokeWidth="0.0" text="高级Java开发" wrappingWidth="250.0">
<font>
<Font size="16.0" />
</font>
</Text>
</children>
</VBox>
<VBox spacing="5.0">
<children>
<Label text="预期薪资">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Text fx:id="salaryText" strokeType="OUTSIDE" strokeWidth="0.0" text="2.5 w/月" wrappingWidth="250.0">
<font>
<Font size="16.0" />
</font>
</Text>
</children>
</VBox>
<VBox onMouseClicked="#showEmployerDetail" spacing="5.0">
<children>
<Label text="发布公司">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Text fx:id="employerText" strokeType="OUTSIDE" strokeWidth="0.0" text="asdf软件" wrappingWidth="250.0">
<font>
<Font size="16.0" />
</font>
</Text>
</children>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</VBox>
</children>
</HBox>
<HBox>
<children>
<VBox spacing="5.0">
<children>
<Label text="地点">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Text fx:id="placeText" strokeType="OUTSIDE" strokeWidth="0.0" text="武汉、上海" wrappingWidth="250.0">
<font>
<Font size="16.0" />
</font>
</Text>
</children>
</VBox>
<VBox spacing="5.0">
<children>
<Label text="计划招聘人数">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Text fx:id="targetNumberText" strokeType="OUTSIDE" strokeWidth="0.0" text="10人" wrappingWidth="250.0">
<font>
<Font size="16.0" />
</font>
</Text>
</children>
</VBox>
</children>
</HBox>
<HBox>
<children>
<VBox spacing="5.0">
<children>
<Label text="要求">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<Text fx:id="requirementText" strokeType="OUTSIDE" strokeWidth="0.0" text="1. 吃苦耐劳 2.认真负责 3. 有团队精神..." wrappingWidth="759.0">
<font>
<Font size="16.0" />
</font>
</Text>
</children>
</VBox>
</children>
</HBox>
<HBox VBox.vgrow="ALWAYS">
<children>
<VBox HBox.hgrow="ALWAYS">
<children>
<Label text="详细信息">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<JFXTextArea fx:id="detailText" editable="false" labelFloat="true" text="asdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfaasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfasasdfassasdfasasdfasasdfas&#10;asdfgfadfg&#10;segrtwsrthrswtyh&#10;assretddhsrth&#10;dfgaergaergaertgaer&#10;asaergaerger&#10;rgasaergaertaertgadf&#10;rgad&#10;rsfgaergaerg" VBox.vgrow="ALWAYS">
<font>
<Font size="14.0" />
</font>
</JFXTextArea>
</children>
</VBox>
</children>
</HBox>
</children>
</fx:root>

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXComboBox?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="60.0" prefWidth="1000.0" spacing="5.0">
<children>
<Label text="分类搜索:">
<font>
<Font size="16.0" />
</font>
</Label>
<JFXComboBox fx:id="filterType" labelFloat="true" prefHeight="23.0" prefWidth="123.0" />
<JFXTextField fx:id="filterString" prefHeight="23.0" prefWidth="378.0" />
<HBox spacing="20.0" HBox.hgrow="ALWAYS">
<children>
<JFXButton onAction="#search" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="Go !" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
<JFXButton onAction="#refresh" prefHeight="40.0" prefWidth="150.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 18;" text="再刷几条" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
</children>
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</HBox>
<ScrollPane fx:id="scrollPane" fitToWidth="true" hbarPolicy="NEVER" pannable="true" prefHeight="661.0" prefWidth="1000.0" style="-fx-background: white;">
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<content>
<FlowPane fx:id="offersPane" alignment="TOP_CENTER" columnHalignment="CENTER" hgap="20.0" vgap="20.0">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</FlowPane>
</content>
</ScrollPane>
</children>
</fx:root>

@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXRadioButton?>
<?import com.jfoenix.controls.JFXTextArea?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.shape.Line?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" type="HBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox prefHeight="740.0" prefWidth="263.0" spacing="20.0">
<children>
<StackPane style="-fx-border-color: black; -fx-border-width: 2; -fx-border-radius: 100;">
<children>
<ImageView fx:id="avatarImageView" fitHeight="200.0" fitWidth="200.0" onMouseClicked="#replaceAvatar" pickOnBounds="true">
<image>
<Image url="@../../../../../../../../../../../pixiv/pixez/61212844_p0_compress.png" />
</image>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
<clip>
<Circle centerX="100" centerY="100" fill="cyan">
<radius>100</radius>
</Circle>
</clip>
</ImageView>
</children>
</StackPane>
<VBox spacing="7.0">
<children>
<Text fx:id="usernameText" strokeType="OUTSIDE" strokeWidth="0.0" text="lensfrex" wrappingWidth="200.0">
<font>
<Font size="22.0" />
</font>
</Text>
<Text fx:id="signText" strokeType="OUTSIDE" strokeWidth="0.0" text="这个人很懒,什么都没写" wrappingWidth="200.0" />
</children>
</VBox>
</children>
<padding>
<Insets left="100.0" top="30.0" />
</padding>
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" HBox.hgrow="ALWAYS">
<padding>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</padding>
<children>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="20.0" VBox.vgrow="ALWAYS">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="60.0" prefWidth="670.0" spacing="10.0">
<children>
<VBox prefHeight="60.0" prefWidth="183.0">
<children>
<Label text="真名">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="realNameTextField" prefHeight="30.0" prefWidth="177.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="52.0" stroke="#a8a8a8">
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin></Line>
<VBox>
<children>
<Label text="年龄">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="ageTextField" prefHeight="30.0" prefWidth="147.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="52.0" stroke="#a8a8a8">
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin>
</Line>
<VBox>
<children>
<Label text="性别">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<HBox spacing="10.0">
<children>
<JFXRadioButton fx:id="maleRadioButton" text="男">
<font>
<Font size="16.0" />
</font>
</JFXRadioButton>
<JFXRadioButton fx:id="femaleRadioButton" text="女">
<font>
<Font size="16.0" />
</font>
</JFXRadioButton>
</children>
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</HBox>
</children>
</VBox>
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
<HBox alignment="CENTER_LEFT" prefHeight="55.0" prefWidth="670.0" spacing="10.0">
<children>
<VBox prefHeight="56.0" prefWidth="183.0">
<children>
<Label text="联系方式">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="contactTextField" prefHeight="29.0" prefWidth="66.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<Line endY="55.0" fill="#a4a4a4" stroke="#a8a8a8">
<HBox.margin>
<Insets left="10.0" right="10.0" />
</HBox.margin>
</Line>
<VBox>
<children>
<Label text="身份证号码">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="idNumberTextField" prefHeight="23.0" prefWidth="268.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
</HBox>
<VBox>
<children>
<Label text="个性签名">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="signEditText" prefHeight="29.0" prefWidth="614.0">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
<VBox.margin>
<Insets top="50.0" />
</VBox.margin>
</VBox>
<VBox>
<children>
<Label text="自我介绍">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextArea fx:id="describeTextArea">
<font>
<Font size="16.0" />
</font>
</JFXTextArea>
</children>
</VBox>
</children>
</VBox>
<HBox alignment="CENTER_RIGHT">
<children>
<JFXButton buttonType="RAISED" onAction="#save" prefHeight="43.0" prefWidth="127.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="保存" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
</children>
</HBox>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onMouseClicked="#showResumeDetail" type="StackPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox>
<children>
<StackPane fx:id="header" alignment="TOP_LEFT" style="-fx-background-radius: 10 10 0 0; -fx-background-color: #4A8895;" VBox.vgrow="ALWAYS">
<children>
<Label fx:id="resumeNameText" alignment="TOP_LEFT" prefHeight="90.0" prefWidth="225.0" style="-fx-font-smoothing-type: gray;" text="忽悠人用的简历&#10;第二行&#10;第三行" textFill="WHITE">
<font>
<Font size="23.0" />
</font>
</Label>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="15.0" />
</padding>
</StackPane>
<StackPane fx:id="body" style="-fx-background-radius: 0 0 10 10; -fx-background-color: rgb(255,255,255,0.87);">
<children>
<HBox prefHeight="70.0" prefWidth="275.0">
<children>
<VBox alignment="CENTER_LEFT" prefHeight="60.0" HBox.hgrow="ALWAYS">
<children>
<Text fx:id="remarkText" strokeType="OUTSIDE" strokeWidth="0.0" text="吹得特别厉害的简历,最好不要用">
<font>
<Font size="14.0" />
</font>
</Text>
</children>
<HBox.margin>
<Insets bottom="5.0" left="10.0" right="5.0" top="5.0" />
</HBox.margin>
</VBox>
<VBox alignment="CENTER" prefHeight="60.0" prefWidth="84.0">
<HBox.margin>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</HBox.margin>
<children>
<JFXButton fx:id="resumeDeleteBtn" buttonType="RAISED" minHeight="40.0" minWidth="40.0" onAction="#deleteResume" prefHeight="40.0" prefWidth="40.0" ripplerFill="#4a8895" scaleX="0.0" scaleY="0.0" style="-fx-background-radius: 40; -fx-background-color: #01A05E;" />
</children>
</VBox>
</children>
</HBox>
</children>
</StackPane>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<children>
<VBox spacing="10.0">
<children>
<Label text="简历管理">
<font>
<Font name="System Bold" size="23.0" />
</font>
</Label>
<Label text="在这里你可以已上传的的简历,也可以上传一些简历">
<font>
<Font size="15.0" />
</font>
</Label>
</children>
</VBox>
<ScrollPane fx:id="scrollPane" fitToWidth="true" hbarPolicy="NEVER" pannable="true" prefHeight="661.0" prefWidth="1000.0" style="-fx-background: white;" styleClass="edge-to-edge">
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<content>
<FlowPane fx:id="resumeContainer" columnHalignment="CENTER" hgap="20.0" vgap="20.0">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</FlowPane>
</content>
</ScrollPane>
<HBox alignment="CENTER_LEFT" prefHeight="59.0" prefWidth="1000.0" spacing="30.0">
<children>
<JFXButton buttonType="RAISED" minHeight="40.0" onAction="#addResume" prefWidth="120.0" style="-fx-background-color: #1976D2; -fx-background-radius: 25;" text="添加" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
</JFXButton>
</children>
</HBox>
</children>
<padding>
<Insets bottom="15.0" left="15.0" right="15.0" top="15.0" />
</padding>
</fx:root>

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<fx:root fx:id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="255.0" prefWidth="525.0" spacing="10.0" type="VBox" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<children>
<HBox spacing="10.0">
<children>
<VBox prefHeight="45.0" prefWidth="225.0">
<children>
<Label text="简历名称">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="resumeNameTextField">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
</children>
</HBox>
<VBox>
<children>
<Label text="备注">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<JFXTextField fx:id="remarkTextField">
<font>
<Font size="14.0" />
</font>
</JFXTextField>
</children>
</VBox>
<VBox prefWidth="623.0" spacing="15.0">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
<children>
<Label text="简历文件">
<font>
<Font name="System Bold" size="16.0" />
</font>
</Label>
<HBox alignment="CENTER_LEFT" spacing="25.0">
<children>
<JFXButton buttonType="RAISED" onAction="#addFile" prefHeight="43.0" prefWidth="103.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="上传" textFill="WHITE">
<font>
<Font size="16.0" />
</font>
</JFXButton>
<Text fx:id="fileNameText" strokeType="OUTSIDE" strokeWidth="0.0">
<font>
<Font size="16.0" />
</font>
</Text>
</children>
</HBox>
</children>
</VBox>
</children>
</fx:root>

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Rectangle2D?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.effect.DropShadow?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<StackPane fx:id="rootPane" xmlns="http://javafx.com/javafx/8.0.361" xmlns:fx="http://javafx.com/fxml/1" fx:controller="net.lensfrex.disillusion.client.controller.page.student.StudentMainController">
<children>
<HBox style="-fx-background-color: white;">
<children>
<VBox alignment="TOP_CENTER" prefHeight="740.0" prefWidth="300.0" spacing="20.0" style="-fx-background-color: #BBDEFB;">
<children>
<HBox prefHeight="135.0" prefWidth="320.0" VBox.vgrow="ALWAYS">
<children>
<ImageView fx:id="avatarImageView" fitHeight="64.0" fitWidth="64.0" pickOnBounds="true" preserveRatio="true">
<viewport>
<Rectangle2D />
</viewport>
<image>
<Image url="@../../../../../../../../../../../pixiv/pixez/93285655_p0.png" />
</image>
<clip>
<Circle centerX="32" centerY="32" fill="cyan">
<radius>32</radius>
</Circle>
</clip>
<effect>
<DropShadow>
<radius>5</radius>
<offsetY>2.0</offsetY>
</DropShadow>
</effect>
</ImageView>
<VBox prefHeight="102.0" prefWidth="186.0" spacing="2.0">
<children>
<Text fx:id="usernameText" strokeType="OUTSIDE" strokeWidth="0.0" text="lensfrex" wrappingWidth="199.0">
<font>
<Font size="28.0" />
</font>
</Text>
<Text fx:id="realNameText" strokeType="OUTSIDE" strokeWidth="0.0" text="\@lensferno" wrappingWidth="199.0">
<font>
<Font size="13.0" />
</font>
</Text>
<Text fx:id="signText" strokeType="OUTSIDE" strokeWidth="0.0" text="这个人真的很懒,什么都没写" wrappingWidth="198.240234375">
<VBox.margin>
<Insets top="2.0" />
</VBox.margin>
</Text>
</children>
<padding>
<Insets left="10.0" />
</padding>
</VBox>
</children>
<padding>
<Insets left="30.0" right="10.0" top="30.0" />
</padding>
</HBox>
<VBox alignment="TOP_CENTER" prefHeight="591.0" prefWidth="318.0" spacing="35.0" VBox.vgrow="ALWAYS">
<padding>
<Insets left="10.0" right="10.0" />
</padding>
<children>
<JFXButton onAction="#showOfferSquare" prefHeight="51.0" prefWidth="230.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="Offer广场" textFill="WHITE" VBox.vgrow="ALWAYS">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
<JFXButton onAction="#showApplications" prefHeight="51.0" prefWidth="230.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="求职申请" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
<JFXButton onAction="#showResumeManage" prefHeight="51.0" prefWidth="230.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="简历管理" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
<JFXButton onAction="#showProfile" prefHeight="51.0" prefWidth="230.0" style="-fx-background-color: #1E88E5; -fx-background-radius: 25;" text="个人信息" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</JFXButton>
</children>
</VBox>
</children>
</VBox>
<StackPane fx:id="containerPane" style="-fx-background-color: white;" HBox.hgrow="ALWAYS">
<children>
<Pane prefHeight="740.0" prefWidth="1000.0" style="-fx-background-color: white;" />
</children>
</StackPane>
</children>
</HBox>
</children>
</StackPane>

@ -0,0 +1,67 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
/pubspec.lock
**/doc/api/
.dart_tool/
.packages
build/
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
*.log
*.class
mvnw
mvnw.cmd
/database/
/delombok/
*/.mvn

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>net.lensfrex</groupId>
<artifactId>backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>3.0.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>4.15.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.lensfrex</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.lensfrex</groupId>
<artifactId>virtual-database</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.3.Final</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.lensfrex</groupId>
<artifactId>disillusion</artifactId>
<version>${revision}</version>
</parent>
<artifactId>backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>backend</name>
<description>backend</description>
<properties>
<java.version>17</java.version>
<springboot.version>3.0.2</springboot.version>
<swagger.version>3.0.0</swagger.version>
<swagger-bootstrap-ui.version>1.9.6</swagger-bootstrap-ui.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<version>${springboot.version}</version>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mindrot/jbcrypt -->
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.3.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.github.yedaxia</groupId>-->
<!-- <artifactId>japidocs</artifactId>-->
<!-- <version>1.4.3</version>-->
<!-- </dependency>-->
<!--
&lt;!&ndash; https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter &ndash;&gt;
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
&lt;!&ndash;swagger-ui&ndash;&gt;
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>${swagger-bootstrap-ui.version}</version>
</dependency>-->
<!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.12</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.webjars/swagger-ui -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>swagger-ui</artifactId>
<version>4.15.5</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>net.lensfrex</groupId>
<artifactId>common</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>net.lensfrex</groupId>
<artifactId>virtual-database</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>0.9.19</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,13 @@
package net.lensfrex.disillusion;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BackendMain {
public static void main(String[] args) {
SpringApplication.run(BackendMain.class, args);
}
}

@ -0,0 +1,24 @@
//package net.lensfrex.disillusion;
//
//import io.github.yedaxia.apidocs.Docs;
//import io.github.yedaxia.apidocs.DocsConfig;
//
//public class DocumentMain {
//
// public static void main(String[] args) {
// DocsConfig config = new DocsConfig();
// // 项目根目录
// config.setProjectPath("./");
// // 项目名称
// config.setProjectName("Assembly");
// // 声明该API的版本
// config.setApiVersion("V2.0");
// // 生成API 文档所在目录
// config.setDocsPath("./doc");
// // 配置自动生成
// config.setAutoGenerate(Boolean.TRUE);
// // 执行生成文档
// Docs.buildHtmlDocs(config);
// }
//
//}

@ -0,0 +1,10 @@
package net.lensfrex.disillusion.annotation;
import java.lang.annotation.*;
@Documented
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckAuth {
}

@ -0,0 +1,24 @@
package net.lensfrex.disillusion.configure;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ApplicationContextHelper implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHelper.applicationContext = applicationContext;
}
public static <T> T get(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
public static Object get(String name) {
return applicationContext.getBean(name);
}
}

@ -0,0 +1,24 @@
package net.lensfrex.disillusion.configure;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties("disillusion")
public class GlobalConfigure {
private String databaseDir;
private static String jwtSecret;
public static String getJwtSecret() {
return jwtSecret;
}
@Value("${disillusion.tokenSecretKey}")
public void setJwtSecret(String jwtSecret) {
GlobalConfigure.jwtSecret = jwtSecret;
}
}

@ -0,0 +1,38 @@
package net.lensfrex.disillusion.configure;
import net.lensfrex.disillusion.web.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class InterceptorConfigure extends WebMvcConfigurationSupport {
@Override
protected void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(this.getTokenInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/user/login")
.excludePathPatterns("/user/register")
.excludePathPatterns("/swagger-ui")
.order(0)
;
super.addInterceptors(registry);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
registry.
addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/")
.resourceChain(false);
}
@Bean
public TokenInterceptor getTokenInterceptor() {
return new TokenInterceptor();
}
}

@ -0,0 +1,35 @@
//package net.lensfrex.disillusion.configure;
//
//import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import springfox.documentation.builders.ApiInfoBuilder;
//import springfox.documentation.builders.PathSelectors;
//import springfox.documentation.builders.RequestHandlerSelectors;
//import springfox.documentation.service.ApiInfo;
//import springfox.documentation.spi.DocumentationType;
//import springfox.documentation.spring.web.plugins.Docket;
//import springfox.documentation.swagger2.annotations.EnableSwagger2;
//
//@Configuration
//@EnableSwagger2
//@EnableKnife4j
//public class SwaggerConfigure {
// @Bean
// public Docket createRestBmbsApi() {
// return new Docket(DocumentationType.SWAGGER_2)
// .groupName("users")
// .apiInfo(apiInfo())
// .select()
// .apis(RequestHandlerSelectors.basePackage("net.lensfrex.disillusion.web.controller"))
// .paths(PathSelectors.any())
// .build();
// }
//
// private ApiInfo apiInfo() {
// return new ApiInfoBuilder()
// .title("disillusion API")
// .version("0.0.1")
// .build();
// }
//}

@ -0,0 +1,83 @@
package net.lensfrex.disillusion.dao;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.dao.database.Table;
import net.lensfrex.disillusion.dao.database.VirtualDatabase;
import net.lensfrex.disillusion.data.Hash;
import net.lensfrex.disillusion.data.List;
import net.lensfrex.disillusion.model.StoreData;
import java.io.IOException;
public abstract class DaoBase<T extends StoreData> implements Table<T> {
// 表名,如"resume", "offer", "user_info"等
private final String tableName;
public DaoBase(GlobalConfigure globalConfigure, String tableName)
throws IOException, ClassNotFoundException {
this.tableName = tableName;
VirtualDatabase.init(globalConfigure.getDatabaseDir());
updateData();
}
// 存放实际数据Hash表,泛型T需要符合StoreData接口,即具有id字段
// 此时id作为hash表的key进行存取
private Hash<String, T> table;
@Override
public T select(String id) throws IOException, ClassNotFoundException {
updateData();
return table.get(id);
}
/**
* 获取所有数据
*/
public List<T> getAll() throws IOException, ClassNotFoundException {
updateData();
return table.allValues();
}
@Override
public void delete(T record) throws IOException, ClassNotFoundException {
updateData();
delete(record.getId());
}
/**
* 按照id删除一条数据
*/
@Override
public void delete(String id) throws IOException, ClassNotFoundException {
updateData();
table.delete(id);
VirtualDatabase.saveTable(tableName, table);
}
/**
* 插入或者更新一条数据当数据记录不存在时则新增否则更新该条数据
*/
@Override
public void insertOrUpdate(T record) throws IOException, ClassNotFoundException {
updateData();
table.put(record.getId(), record);
VirtualDatabase.saveTable(tableName, table);
}
@Override
public void update(T record) throws IOException, ClassNotFoundException {
updateData();
table.put(record.getId(), record);
VirtualDatabase.saveTable(tableName, table);
}
@SuppressWarnings("unchecked")
private void updateData() throws IOException, ClassNotFoundException {
table = (Hash<String, T>) VirtualDatabase.getTable(tableName, Hash.class);
if (table == null) {
table = new Hash<>();
VirtualDatabase.saveTable(tableName, table);
}
}
}

@ -0,0 +1,14 @@
package net.lensfrex.disillusion.dao;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.model.OfferApplication;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class OfferApplicationTable extends DaoBase<OfferApplication> {
public OfferApplicationTable(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "offer_application");
}
}

@ -0,0 +1,12 @@
package net.lensfrex.disillusion.dao;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.model.OfferStatus;
import java.io.IOException;
public class OfferStatusTable extends DaoBase<OfferStatus> {
public OfferStatusTable(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "offer_status");
}
}

@ -0,0 +1,14 @@
package net.lensfrex.disillusion.dao;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.model.employer.Offer;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class OfferTable extends DaoBase<Offer> {
public OfferTable(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "offer");
}
}

@ -0,0 +1,14 @@
package net.lensfrex.disillusion.dao;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.model.student.Resume;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class ResumeTable extends DaoBase<Resume> {
public ResumeTable(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "resume");
}
}

@ -0,0 +1,14 @@
package net.lensfrex.disillusion.dao;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.model.UserInfo;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class UserInfoTable extends DaoBase<UserInfo> {
public UserInfoTable(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "user_info");
}
}

@ -0,0 +1,14 @@
package net.lensfrex.disillusion.dao;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.model.User;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class UserTable extends DaoBase<User> {
public UserTable(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "user");
}
}

@ -0,0 +1,16 @@
package net.lensfrex.disillusion.dao.index;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.dao.DaoBase;
import net.lensfrex.disillusion.model.MultiIndex;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class EmployerOfferIndex extends DaoBase<MultiIndex> {
public EmployerOfferIndex(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "employer_offer_index");
}
}

@ -0,0 +1,15 @@
package net.lensfrex.disillusion.dao.index;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.dao.DaoBase;
import net.lensfrex.disillusion.model.MultiIndex;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class StudentResumeIndex extends DaoBase<MultiIndex> {
public StudentResumeIndex(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "student_resume_index");
}
}

@ -0,0 +1,15 @@
package net.lensfrex.disillusion.dao.index.application;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.dao.DaoBase;
import net.lensfrex.disillusion.model.MultiIndex;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class EmployerApplicationIndex extends DaoBase<MultiIndex> {
public EmployerApplicationIndex(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "employer_application_index");
}
}

@ -0,0 +1,15 @@
package net.lensfrex.disillusion.dao.index.application;
import net.lensfrex.disillusion.configure.GlobalConfigure;
import net.lensfrex.disillusion.dao.DaoBase;
import net.lensfrex.disillusion.model.MultiIndex;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class OfferApplicationIndex extends DaoBase<MultiIndex> {
public OfferApplicationIndex(GlobalConfigure globalConfigure) throws IOException, ClassNotFoundException {
super(globalConfigure, "offer_application_index");
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save