2025年3月31日18:17:15
parent
b81f2a1801
commit
f0a6466feb
|
|
@ -59,7 +59,7 @@ public class ApiUtils {
|
||||||
|
|
||||||
public static DataView getUserList() {
|
public static DataView getUserList() {
|
||||||
DataLoad dataLoad = new UserDataLoad();
|
DataLoad dataLoad = new UserDataLoad();
|
||||||
dataLoad.setForm(new UserForm());
|
dataLoad.setForm(new UserForm(true));
|
||||||
return dataLoad.loadData(PAGE_NUM,PAGE_SIZE);
|
return dataLoad.loadData(PAGE_NUM,PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import com.zhangmeng.online.exam.ui.components.DynamicTableComponent;
|
||||||
import com.zhangmeng.online.exam.ui.components.callBack.DynamicTableComponentCallBack;
|
import com.zhangmeng.online.exam.ui.components.callBack.DynamicTableComponentCallBack;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.PasswordField;
|
import javafx.scene.control.PasswordField;
|
||||||
|
|
@ -16,6 +17,7 @@ import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.stage.Window;
|
import javafx.stage.Window;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -31,6 +33,18 @@ public class UserForm extends Form {
|
||||||
private TextField phone_field;
|
private TextField phone_field;
|
||||||
private TextField email_field;
|
private TextField email_field;
|
||||||
|
|
||||||
|
private boolean isfxml = true;
|
||||||
|
|
||||||
|
public UserForm(boolean isfxml) {
|
||||||
|
this.isfxml = isfxml;
|
||||||
|
try {
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/user-edit.fxml"));
|
||||||
|
this.getChildren().add(fxmlLoader.load());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public UserForm() {
|
public UserForm() {
|
||||||
|
|
||||||
Label username_label = new Label("用户名:");
|
Label username_label = new Label("用户名:");
|
||||||
|
|
@ -144,4 +158,12 @@ public class UserForm extends Form {
|
||||||
public void setEmail_field(TextField email_field) {
|
public void setEmail_field(TextField email_field) {
|
||||||
this.email_field = email_field;
|
this.email_field = email_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isIsfxml() {
|
||||||
|
return isfxml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsfxml(boolean isfxml) {
|
||||||
|
this.isfxml = isfxml;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ public class UserDataLoad implements DataLoad {
|
||||||
@Override
|
@Override
|
||||||
public void editData(String id,Stage stage) {
|
public void editData(String id,Stage stage) {
|
||||||
|
|
||||||
UserForm userForm = new UserForm();
|
UserForm userForm = new UserForm(true);
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("id", id);
|
map.put("id", id);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.zhangmeng.online.exam.ui.api.form.UserForm;
|
||||||
import com.zhangmeng.online.exam.ui.api.form.base.Form;
|
import com.zhangmeng.online.exam.ui.api.form.base.Form;
|
||||||
import com.zhangmeng.online.exam.ui.components.DynamicTableComponent;
|
import com.zhangmeng.online.exam.ui.components.DynamicTableComponent;
|
||||||
import com.zhangmeng.online.exam.ui.utils.AlertUtils;
|
import com.zhangmeng.online.exam.ui.utils.AlertUtils;
|
||||||
|
import com.zhangmeng.online.exam.ui.utils.FxUtils;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
|
@ -42,9 +43,10 @@ public class DynamicTableComponentCallBackImpl implements DynamicTableComponentC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void Add(Parent node, Stage primaryStage, DynamicTableComponent table) {
|
public void Add(Parent node, Stage primaryStage, DynamicTableComponent table) {
|
||||||
Form form = (Form) node;
|
// Form form = (Form) node;
|
||||||
form.setTableComponent(table);
|
// form.setTableComponent(table);
|
||||||
AlertUtils.alert("设置", node, primaryStage);
|
// AlertUtils.alert("设置", node, primaryStage);
|
||||||
|
FxUtils.alert("设置",node, primaryStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,18 @@ import com.zhangmeng.online.exam.ui.admin.IndexPage;
|
||||||
import com.zhangmeng.online.exam.ui.admin.LoginPage;
|
import com.zhangmeng.online.exam.ui.admin.LoginPage;
|
||||||
import com.zhangmeng.online.exam.ui.admin.PaperPage;
|
import com.zhangmeng.online.exam.ui.admin.PaperPage;
|
||||||
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.User;
|
||||||
|
import com.zhangmeng.online.exam.ui.service.UserService;
|
||||||
import com.zhangmeng.online.exam.ui.utils.AlertUtils;
|
import com.zhangmeng.online.exam.ui.utils.AlertUtils;
|
||||||
|
import com.zhangmeng.online.exam.ui.utils.FxUtils;
|
||||||
import com.zhangmeng.online.exam.ui.utils.HttpUtils;
|
import com.zhangmeng.online.exam.ui.utils.HttpUtils;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.concurrent.ScheduledService;
|
import javafx.concurrent.ScheduledService;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
@ -21,6 +26,7 @@ import javafx.scene.image.ImageView;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -79,8 +85,15 @@ public class LoginController {
|
||||||
Map<String, Object> data = (Map<String, Object>) jsonObject.get("data");
|
Map<String, Object> data = (Map<String, Object>) jsonObject.get("data");
|
||||||
Object token = data.get("token");
|
Object token = data.get("token");
|
||||||
HttpUtils.USER_INFO.put("token", token);
|
HttpUtils.USER_INFO.put("token", token);
|
||||||
new Thread(this::user_type).start();
|
|
||||||
Alert alert = AlertUtils.alert_msg(jsonObject.getString("message"));
|
User user = new User();
|
||||||
|
user.setUsername(username.getText());
|
||||||
|
user.setPassword(password.getText());
|
||||||
|
user.setToken(token.toString());
|
||||||
|
UserService.setCurrentUser(user);
|
||||||
|
|
||||||
|
new Thread(UserService::user_type).start();
|
||||||
|
// Alert alert = AlertUtils.alert_msg(jsonObject.getString("message"));
|
||||||
|
|
||||||
LoginController.MyScheduledService myService = new LoginController.MyScheduledService();
|
LoginController.MyScheduledService myService = new LoginController.MyScheduledService();
|
||||||
//myService.setDelay(Duration.seconds(5));//延迟
|
//myService.setDelay(Duration.seconds(5));//延迟
|
||||||
|
|
@ -112,7 +125,7 @@ public class LoginController {
|
||||||
System.out.println("lastValueProperty:" + newValue.intValue());
|
System.out.println("lastValueProperty:" + newValue.intValue());
|
||||||
if (newValue.intValue() == 3) {
|
if (newValue.intValue() == 3) {
|
||||||
myService.cancel();
|
myService.cancel();
|
||||||
alert.close();
|
//alert.close();
|
||||||
success();
|
success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,21 +140,10 @@ public class LoginController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void user_type() {
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
|
||||||
params.put("token", HttpUtils.USER_INFO.get("token"));
|
|
||||||
String response = HttpUtils.GET(ApiUtils.API_URL + "/user/getUserInfo", params);
|
|
||||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
|
||||||
if (jsonObject.getIntValue("code") == 200) {
|
|
||||||
Map<String, Object> data = (Map<String, Object>) jsonObject.get("data");
|
|
||||||
String type = data.get("type").toString();
|
|
||||||
HttpUtils.USER_INFO.put("type", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void success() {
|
private void success() {
|
||||||
String type = HttpUtils.USER_INFO.get("type").toString();
|
String type = UserService.getCurrentUser().getRoleType();
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "STUDENT" -> user_page();
|
case "STUDENT" -> user_page();
|
||||||
case "ADMIN" -> admin_page();
|
case "ADMIN" -> admin_page();
|
||||||
|
|
@ -166,15 +168,15 @@ public class LoginController {
|
||||||
private void admin_page() {
|
private void admin_page() {
|
||||||
Scene scene = loginButton.getScene();
|
Scene scene = loginButton.getScene();
|
||||||
Stage window = (Stage) scene.getWindow();
|
Stage window = (Stage) scene.getWindow();
|
||||||
window.close();
|
// IndexPage indexPage = new IndexPage();
|
||||||
|
try {
|
||||||
Stage stage = new Stage();
|
Parent main = FXMLLoader.load(this.getClass().getResource("/fxml/main.fxml"));
|
||||||
IndexPage indexPage = new IndexPage();
|
scene = new Scene(main, FxUtils.DEFAULT_WIDTH, FxUtils.DEFAULT_HEIGHT);
|
||||||
|
window.setScene(scene);
|
||||||
scene = new Scene(indexPage, 1280, 720);
|
window.centerOnScreen();
|
||||||
stage.setScene(scene);
|
} catch (IOException e) {
|
||||||
stage.setTitle("在线考试系统");
|
throw new RuntimeException(e);
|
||||||
stage.show();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyScheduledService extends ScheduledService<Number> {
|
class MyScheduledService extends ScheduledService<Number> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.zhangmeng.online.exam.ui.admin.IndexPage;
|
||||||
|
import com.zhangmeng.online.exam.ui.admin.UserListPage;
|
||||||
|
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
||||||
|
import com.zhangmeng.online.exam.ui.components.DynamicTableComponent;
|
||||||
|
import com.zhangmeng.online.exam.ui.components.callBack.DynamicTableComponentCallBackImpl;
|
||||||
|
import com.zhangmeng.online.exam.ui.layouts.SideMenu;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.MenuData;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.User;
|
||||||
|
import com.zhangmeng.online.exam.ui.utils.FxUtils;
|
||||||
|
import com.zhangmeng.online.exam.ui.utils.HttpUtils;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.zhangmeng.online.exam.ui.service.UserService;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 15:17
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class MainController {
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TreeView<MenuData> menuTree;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TabPane contentTabPane;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private Label userLabel;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
initializeMenu();
|
||||||
|
// 显示当前用户
|
||||||
|
User currentUser = UserService.getCurrentUser();
|
||||||
|
if (currentUser != null) {
|
||||||
|
userLabel.setText("当前用户:" + currentUser.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加菜单点击事件
|
||||||
|
menuTree.setOnMouseClicked(event -> {
|
||||||
|
TreeItem<MenuData> selectedItem = menuTree.getSelectionModel().getSelectedItem();
|
||||||
|
if (selectedItem != null && selectedItem.isLeaf()) {
|
||||||
|
openTab(selectedItem.getValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeMenu() {
|
||||||
|
TreeItem<MenuData> root = new TreeItem<>(new MenuData("系统菜单", null, null));
|
||||||
|
root.setGraphic(new Label(root.getValue().getTitle()));
|
||||||
|
root.setExpanded(true);
|
||||||
|
|
||||||
|
menuTree.setCellFactory(new Callback<TreeView<MenuData>, TreeCell<MenuData>>() {
|
||||||
|
@Override
|
||||||
|
public TreeCell<MenuData> call(TreeView<MenuData> menuDataTreeView) {
|
||||||
|
return new TreeCell<MenuData>() {
|
||||||
|
@Override
|
||||||
|
protected void updateItem(MenuData item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (!empty) {
|
||||||
|
HBox hBox = new HBox();
|
||||||
|
hBox.setAlignment(Pos.CENTER);
|
||||||
|
Label label = new Label(item.getTitle());
|
||||||
|
hBox.getChildren().addAll(label);
|
||||||
|
hBox.setMaxWidth(50);
|
||||||
|
this.setGraphic(hBox);
|
||||||
|
} else {
|
||||||
|
this.setGraphic(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
root.getChildren().addAll(UserService.menu_tree_item());
|
||||||
|
menuTree.setRoot(root);
|
||||||
|
|
||||||
|
ContextMenu contextMenu = new ContextMenu();
|
||||||
|
MenuItem close_current_tab = new MenuItem("关闭当前标签");
|
||||||
|
|
||||||
|
close_current_tab.setOnAction(actionEvent -> {
|
||||||
|
Tab selectedItem = contentTabPane.getSelectionModel().getSelectedItem();
|
||||||
|
contentTabPane.getTabs().remove(selectedItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
MenuItem close_all_tab = new MenuItem("关闭全部标签");
|
||||||
|
close_all_tab.setOnAction(actionEvent -> {
|
||||||
|
contentTabPane.getTabs().clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
contextMenu.getItems().add(close_current_tab);
|
||||||
|
contextMenu.getItems().add(close_all_tab);
|
||||||
|
contentTabPane.setContextMenu(contextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openTab(MenuData menuData) {
|
||||||
|
// 检查是否已经存在相同的标签页
|
||||||
|
for (Tab tab : contentTabPane.getTabs()) {
|
||||||
|
MenuData userData = (MenuData) tab.getUserData();
|
||||||
|
if (userData.getUrl().equals(menuData.getUrl())) {
|
||||||
|
contentTabPane.getSelectionModel().select(tab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 创建新的标签页
|
||||||
|
Tab tab = new Tab(menuData.getTitle());
|
||||||
|
tab.setUserData(menuData);
|
||||||
|
|
||||||
|
// 根据标题加载不同的内容
|
||||||
|
Node content = switch (menuData.getUrl()) {
|
||||||
|
case "/user/list" -> init_table( ApiUtils.getUserList());
|
||||||
|
case "添加用户" -> FXMLLoader.load(getClass().getResource("/fxml/user-edit.fxml"));
|
||||||
|
case "角色列表" -> FXMLLoader.load(getClass().getResource("/fxml/role-list.fxml"));
|
||||||
|
case "权限分配" -> FXMLLoader.load(getClass().getResource("/fxml/role-permission.fxml"));
|
||||||
|
case "基本设置" -> FXMLLoader.load(getClass().getResource("/fxml/setting.fxml"));
|
||||||
|
case "日志查看" -> FXMLLoader.load(getClass().getResource("/fxml/log.fxml"));
|
||||||
|
case "公告列表" -> FXMLLoader.load(getClass().getResource("/fxml/notice-list.fxml"));
|
||||||
|
case "发布公告" -> FXMLLoader.load(getClass().getResource("/fxml/notice-edit.fxml"));
|
||||||
|
case "在线用户" -> FXMLLoader.load(getClass().getResource("/fxml/monitor-online.fxml"));
|
||||||
|
case "系统日志" -> FXMLLoader.load(getClass().getResource("/fxml/monitor-log.fxml"));
|
||||||
|
case "性能监控" -> FXMLLoader.load(getClass().getResource("/fxml/monitor-performance.fxml"));
|
||||||
|
case "数据监控" -> FXMLLoader.load(getClass().getResource("/fxml/monitor-data.fxml"));
|
||||||
|
default -> new Label("这是" + menuData.getTitle() + "的内容页面");
|
||||||
|
};
|
||||||
|
|
||||||
|
tab.setContent(content);
|
||||||
|
contentTabPane.getTabs().add(tab);
|
||||||
|
contentTabPane.getSelectionModel().select(tab);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
|
alert.setTitle("错误");
|
||||||
|
alert.setHeaderText(null);
|
||||||
|
alert.setContentText("加载页面失败:" + e.getMessage());
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DynamicTableComponent init_table(ApiUtils.DataView dataView) {
|
||||||
|
dataView.setPageNum(dataView.getPageNum());
|
||||||
|
dataView.setPageSize(dataView.getPageSize());
|
||||||
|
dataView.setTotal(dataView.getTotal());
|
||||||
|
DynamicTableComponent dynamicTableComponent = new DynamicTableComponent(dataView);
|
||||||
|
dynamicTableComponent.setCallBack(new DynamicTableComponentCallBackImpl(dataView.getDataLoad(),dataView.getDataLoad().getForm()));
|
||||||
|
dynamicTableComponent.setPadding(new Insets(15));
|
||||||
|
dynamicTableComponent.prefHeightProperty().bind(contentTabPane.heightProperty().subtract(15));
|
||||||
|
return dynamicTableComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void handleLogout() {
|
||||||
|
try {
|
||||||
|
UserService.logout();
|
||||||
|
Parent root = FXMLLoader.load(getClass().getResource("/fxml/login.fxml"));
|
||||||
|
Stage stage = (Stage) userLabel.getScene().getWindow();
|
||||||
|
stage.setScene(new Scene(root));
|
||||||
|
stage.centerOnScreen();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,183 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.controller;
|
||||||
|
|
||||||
|
import com.zhangmeng.online.exam.ui.module.Role;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.User;
|
||||||
|
import com.zhangmeng.online.exam.ui.service.LogService;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
|
import javafx.collections.transformation.SortedList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.control.cell.CheckBoxListCell;
|
||||||
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import com.zhangmeng.online.exam.ui.service.RoleService;
|
||||||
|
import com.zhangmeng.online.exam.ui.service.UserService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 16:59
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class UserEditController {
|
||||||
|
@FXML
|
||||||
|
private TextField usernameField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TextField nameField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private PasswordField passwordField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private TextField emailField;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ComboBox<String> statusComboBox;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ListView<Role> roleListView;
|
||||||
|
|
||||||
|
private User user;
|
||||||
|
private boolean saveClicked = false;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
// 初始化状态下拉框
|
||||||
|
statusComboBox.getItems().addAll("启用", "禁用");
|
||||||
|
statusComboBox.setValue("启用");
|
||||||
|
|
||||||
|
// 初始化角色列表
|
||||||
|
roleListView.setItems(FXCollections.observableArrayList(RoleService.getAllRoles()));
|
||||||
|
roleListView.setCellFactory(CheckBoxListCell.forListView(role -> {
|
||||||
|
return role.selectedProperty();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
|
||||||
|
usernameField.setText(user.getUsername());
|
||||||
|
nameField.setText(user.getName());
|
||||||
|
emailField.setText(user.getEmail());
|
||||||
|
statusComboBox.setValue(user.getStatus());
|
||||||
|
|
||||||
|
// 设置已有角色的选中状态
|
||||||
|
user.getRoles().forEach(role -> {
|
||||||
|
role.setSelected(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 编辑模式下禁用用户名修改
|
||||||
|
usernameField.setDisable(true);
|
||||||
|
// 编辑模式下密码为可选
|
||||||
|
passwordField.setPromptText("不修改请留空");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void handleSave() {
|
||||||
|
if (!validateInput()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (user == null) {
|
||||||
|
// 创建新用户
|
||||||
|
user = new User();
|
||||||
|
user.setUsername(usernameField.getText());
|
||||||
|
user.setPassword(passwordField.getText());
|
||||||
|
} else if (!passwordField.getText().isEmpty()) {
|
||||||
|
// 如果输入了新密码,则更新密码
|
||||||
|
user.setPassword(passwordField.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新基本信息
|
||||||
|
user.setName(nameField.getText());
|
||||||
|
user.setEmail(emailField.getText());
|
||||||
|
user.setStatus(statusComboBox.getValue());
|
||||||
|
|
||||||
|
// 更新角色
|
||||||
|
user.getRoles().clear();
|
||||||
|
roleListView.getItems().stream()
|
||||||
|
.filter(Role::isSelected)
|
||||||
|
.forEach(user::addRole);
|
||||||
|
|
||||||
|
// 保存用户
|
||||||
|
if (user.getId() == 0) {
|
||||||
|
UserService.createUser(user);
|
||||||
|
LogService.log("用户管理", "创建", "创建用户:" + user.getUsername());
|
||||||
|
} else {
|
||||||
|
UserService.updateUser(user);
|
||||||
|
LogService.log("用户管理", "更新", "更新用户:" + user.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
saveClicked = true;
|
||||||
|
closeDialog();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogService.log("用户管理", "保存", "保存用户失败", e);
|
||||||
|
showError("保存失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void handleCancel() {
|
||||||
|
closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateInput() {
|
||||||
|
StringBuilder errorMessage = new StringBuilder();
|
||||||
|
|
||||||
|
if (usernameField.getText() == null || usernameField.getText().trim().isEmpty()) {
|
||||||
|
errorMessage.append("用户名不能为空!\n");
|
||||||
|
}
|
||||||
|
if (nameField.getText() == null || nameField.getText().trim().isEmpty()) {
|
||||||
|
errorMessage.append("姓名不能为空!\n");
|
||||||
|
}
|
||||||
|
if (user == null && (passwordField.getText() == null || passwordField.getText().trim().isEmpty())) {
|
||||||
|
errorMessage.append("密码不能为空!\n");
|
||||||
|
}
|
||||||
|
if (emailField.getText() == null || emailField.getText().trim().isEmpty()) {
|
||||||
|
errorMessage.append("邮箱不能为空!\n");
|
||||||
|
}
|
||||||
|
if (roleListView.getItems().stream().noneMatch(Role::isSelected)) {
|
||||||
|
errorMessage.append("至少选择一个角色!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorMessage.length() == 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
showError("输入错误", errorMessage.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeDialog() {
|
||||||
|
Stage stage = (Stage) usernameField.getScene().getWindow();
|
||||||
|
stage.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSaveClicked() {
|
||||||
|
return saveClicked;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showError(String title, String message) {
|
||||||
|
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||||
|
alert.setTitle(title);
|
||||||
|
alert.setHeaderText(null);
|
||||||
|
alert.setContentText(message);
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showError(String title, Exception e) {
|
||||||
|
showError(title, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.controller;
|
||||||
|
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 16:34
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class UserListController {
|
||||||
|
public void handleSearch(ActionEvent actionEvent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleAdd(ActionEvent actionEvent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 15:58
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class MenuData {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String icon;
|
||||||
|
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
public MenuData(String title, String icon, String url) {
|
||||||
|
this.title = title;
|
||||||
|
this.icon = icon;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIcon() {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIcon(String icon) {
|
||||||
|
this.icon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.module;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class OperationLog {
|
||||||
|
private int id;
|
||||||
|
private String username; // 操作用户
|
||||||
|
private String module; // 操作模块
|
||||||
|
private String action; // 操作类型
|
||||||
|
private String content; // 操作内容
|
||||||
|
private String ip; // 操作IP
|
||||||
|
private LocalDateTime operateTime; // 操作时间
|
||||||
|
private String status; // 操作状态(成功/失败)
|
||||||
|
private String errorMsg; // 错误信息
|
||||||
|
|
||||||
|
public OperationLog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationLog(int id, String module, String action, String content,
|
||||||
|
String ip, LocalDateTime operateTime, String status, String errorMsg) {
|
||||||
|
this.id = id;
|
||||||
|
this.module = module;
|
||||||
|
this.action = action;
|
||||||
|
this.content = content;
|
||||||
|
this.ip = ip;
|
||||||
|
this.operateTime = operateTime;
|
||||||
|
this.status = status;
|
||||||
|
this.errorMsg = errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModule() {
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModule(String module) {
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAction(String action) {
|
||||||
|
this.action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(String content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIp() {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIp(String ip) {
|
||||||
|
this.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getOperateTime() {
|
||||||
|
return operateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOperateTime(LocalDateTime operateTime) {
|
||||||
|
this.operateTime = operateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMsg() {
|
||||||
|
return errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setErrorMsg(String errorMsg) {
|
||||||
|
this.errorMsg = errorMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.module;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Permission {
|
||||||
|
private int id;
|
||||||
|
private String code; // 权限代码
|
||||||
|
private String name; // 权限名称
|
||||||
|
private String type; // 权限类型(菜单、按钮等)
|
||||||
|
private int parentId; // 父权限ID
|
||||||
|
private String url; // 资源路径
|
||||||
|
private int sort; // 排序号
|
||||||
|
private List<Permission> children = new ArrayList<>();
|
||||||
|
|
||||||
|
public Permission(int id, String code, String name, String type, int parentId, String url, int sort) {
|
||||||
|
this.id = id;
|
||||||
|
this.code = code;
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.parentId = parentId;
|
||||||
|
this.url = url;
|
||||||
|
this.sort = sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getParentId() {
|
||||||
|
return parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentId(int parentId) {
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSort() {
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSort(int sort) {
|
||||||
|
this.sort = sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Permission> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildren(List<Permission> children) {
|
||||||
|
this.children = children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.module;
|
||||||
|
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 17:05
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class Role {
|
||||||
|
private int id;
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private String status;
|
||||||
|
private List<Permission> permissions;
|
||||||
|
private BooleanProperty selected;
|
||||||
|
|
||||||
|
public Role(int id, String name, String description, String status) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
this.status = status;
|
||||||
|
this.permissions = new ArrayList<>();
|
||||||
|
this.selected = new SimpleBooleanProperty(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Role() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and setters
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Permission> getPermissions() {
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPermissions(List<Permission> permissions) {
|
||||||
|
this.permissions = new ArrayList<>(permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPermission(Permission permission) {
|
||||||
|
if (!permissions.contains(permission)) {
|
||||||
|
permissions.add(permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePermission(Permission permission) {
|
||||||
|
permissions.remove(permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(String permissionCode) {
|
||||||
|
return permissions.stream()
|
||||||
|
.anyMatch(p -> p.getCode().equals(permissionCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanProperty selectedProperty() {
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSelected() {
|
||||||
|
return selected.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelected(boolean selected) {
|
||||||
|
this.selected.set(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,158 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.module;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 15:33
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
private String username;
|
||||||
|
private String name;
|
||||||
|
private String email;
|
||||||
|
private String status;
|
||||||
|
private String password; // 加密后的密码
|
||||||
|
private String salt; // 密码盐值
|
||||||
|
private List<Role> roles = new ArrayList<>();
|
||||||
|
private String phone;
|
||||||
|
private String avatarUrl;
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
private String roleType;
|
||||||
|
|
||||||
|
|
||||||
|
public User(int id, String username, String name, String email, String status) {
|
||||||
|
this.id = id;
|
||||||
|
this.username = username;
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(int id, String username, String name, String email, String status, String password, String salt) {
|
||||||
|
this(id, username, name, email, status);
|
||||||
|
this.password = password;
|
||||||
|
this.salt = salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(String status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSalt() {
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSalt(String salt) {
|
||||||
|
this.salt = salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Role> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoles(List<Role> roles) {
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRole(Role role) {
|
||||||
|
if (!roles.contains(role)) {
|
||||||
|
roles.add(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(String permissionCode) {
|
||||||
|
return roles.stream()
|
||||||
|
.anyMatch(role -> role.hasPermission(permissionCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return "启用".equals(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhone() {
|
||||||
|
return phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhone(String phone) {
|
||||||
|
this.phone = phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvatarUrl() {
|
||||||
|
return avatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAvatarUrl(String avatarUrl) {
|
||||||
|
this.avatarUrl = avatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getRoleType() {
|
||||||
|
return roleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoleType(String roleType) {
|
||||||
|
this.roleType = roleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.zhangmeng.online.exam.ui.module.OperationLog;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class LogService {
|
||||||
|
private static final List<LogEntry> logs = new ArrayList<>();
|
||||||
|
private static final int MAX_LOGS = 10000; // 最多保存10000条日志
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录日志
|
||||||
|
*/
|
||||||
|
public static void log(String module, String operation, String message) {
|
||||||
|
log(module, operation, message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录带异常的日志
|
||||||
|
*/
|
||||||
|
public static void log(String module, String operation, String message, Exception e) {
|
||||||
|
LogEntry entry = new LogEntry(
|
||||||
|
module,
|
||||||
|
operation,
|
||||||
|
message,
|
||||||
|
e != null ? e.getMessage() : null,
|
||||||
|
LocalDateTime.now()
|
||||||
|
);
|
||||||
|
|
||||||
|
synchronized (logs) {
|
||||||
|
logs.add(entry);
|
||||||
|
if (logs.size() > MAX_LOGS) {
|
||||||
|
logs.remove(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索日志
|
||||||
|
*/
|
||||||
|
public static List<OperationLog> searchLogs(String keyword) {
|
||||||
|
return logs.stream()
|
||||||
|
.filter(log -> keyword == null || keyword.isEmpty() || log.getMessage().contains(keyword))
|
||||||
|
.map(log -> new OperationLog(
|
||||||
|
0, // Assuming ID is not used or set elsewhere
|
||||||
|
log.getModule(),
|
||||||
|
log.getOperation(),
|
||||||
|
log.getMessage(),
|
||||||
|
"127.0.0.1", // Placeholder for IP
|
||||||
|
log.getTime(),
|
||||||
|
"成功", // Placeholder for status
|
||||||
|
log.getError() // Assuming error message is used as errorMsg
|
||||||
|
))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<OperationLog> searchLogs(String keyword, String type, LocalDateTime startDate, LocalDateTime endDate) {
|
||||||
|
|
||||||
|
return logs.stream()
|
||||||
|
|
||||||
|
.filter(log -> {
|
||||||
|
|
||||||
|
// 检查日期范围
|
||||||
|
|
||||||
|
if (startDate != null && log.getTime().isBefore(startDate)) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endDate != null && log.getTime().isAfter(endDate)) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 检查日志类型
|
||||||
|
|
||||||
|
if (type != null && !type.isEmpty() && !log.getModule().equals(type)) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 检查关键字
|
||||||
|
|
||||||
|
if (keyword != null && !keyword.isEmpty() && !log.getMessage().contains(keyword)) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
.map(log -> new OperationLog(
|
||||||
|
|
||||||
|
0, // Assuming ID is not used or set elsewhere
|
||||||
|
|
||||||
|
log.getModule(),
|
||||||
|
|
||||||
|
log.getOperation(),
|
||||||
|
|
||||||
|
log.getMessage(),
|
||||||
|
|
||||||
|
"127.0.0.1", // Placeholder for IP
|
||||||
|
|
||||||
|
log.getTime(),
|
||||||
|
|
||||||
|
"成功", // Placeholder for status
|
||||||
|
|
||||||
|
log.getError() // Assuming error message is used as errorMsg
|
||||||
|
|
||||||
|
))
|
||||||
|
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空日志
|
||||||
|
*/
|
||||||
|
public static void clearLogs() {
|
||||||
|
synchronized (logs) {
|
||||||
|
logs.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日志条目类
|
||||||
|
*/
|
||||||
|
private static class LogEntry {
|
||||||
|
private final String module;
|
||||||
|
private final String operation;
|
||||||
|
private final String message;
|
||||||
|
private final String error;
|
||||||
|
private final LocalDateTime time;
|
||||||
|
|
||||||
|
public LogEntry(String module, String operation, String message,
|
||||||
|
String error, LocalDateTime time) {
|
||||||
|
this.module = module;
|
||||||
|
this.operation = operation;
|
||||||
|
this.message = message;
|
||||||
|
this.error = error;
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModule() {
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOperation() {
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getError() {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getTime() {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.Role;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.User;
|
||||||
|
import com.zhangmeng.online.exam.ui.utils.HttpUtils;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.zhangmeng.online.exam.ui.api.ApiUtils.API_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 17:04
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class RoleService {
|
||||||
|
public static List<Role> getAllRoles() {
|
||||||
|
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("pageNum", ApiUtils.PAGE_NUM);
|
||||||
|
params.put("pageSize", ApiUtils.PAGE_SIZE);
|
||||||
|
|
||||||
|
String userListData = HttpUtils.GET(API_URL + "/role/list",params);
|
||||||
|
JSONObject jsonObject = JSON.parseObject(userListData);
|
||||||
|
JSONArray data = jsonObject.getJSONArray("data");
|
||||||
|
Integer total = jsonObject.getInteger("total");
|
||||||
|
List<Role> roles = new ArrayList<>();
|
||||||
|
for (Object datum : data) {
|
||||||
|
JSONObject rolemap = (JSONObject) datum;
|
||||||
|
|
||||||
|
Role role = new Role();
|
||||||
|
role.setId(rolemap.getInteger("id"));
|
||||||
|
role.setName(rolemap.getString("name"));
|
||||||
|
role.setDescription(rolemap.getString("desc")); // 角色描述
|
||||||
|
role.setStatus(rolemap.getString("status"));
|
||||||
|
role.setPermissions(new ArrayList<>()); // 角色权限
|
||||||
|
|
||||||
|
roles.add(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.service;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.zhangmeng.online.exam.ui.api.ApiUtils;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.MenuData;
|
||||||
|
import com.zhangmeng.online.exam.ui.module.User;
|
||||||
|
import com.zhangmeng.online.exam.ui.utils.HttpUtils;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TreeItem;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模块
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 15:29
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
private static User currentUser;
|
||||||
|
|
||||||
|
public static User getCurrentUser() {
|
||||||
|
|
||||||
|
if (currentUser == null){
|
||||||
|
return new User();
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCurrentUser(User user) {
|
||||||
|
currentUser = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void user_type() {
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("token", currentUser.getToken());
|
||||||
|
String response = HttpUtils.GET(ApiUtils.API_URL + "/user/getUserInfo", params);
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||||
|
if (jsonObject.getIntValue("code") == 200) {
|
||||||
|
Map<String, Object> data = (Map<String, Object>) jsonObject.get("data");
|
||||||
|
String type = data.get("type").toString();
|
||||||
|
currentUser.setRoleType(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logout() {
|
||||||
|
currentUser = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TreeItem<MenuData>> menu_tree_item() {
|
||||||
|
|
||||||
|
String sideData = HttpUtils.GET(ApiUtils.API_URL + "/user/menu");
|
||||||
|
JSONObject jsonObject = JSON.parseObject(sideData);
|
||||||
|
JSONArray data = jsonObject.getJSONArray("data");
|
||||||
|
|
||||||
|
List<TreeItem<MenuData>> menuList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < data.size(); i++) {
|
||||||
|
JSONObject menu = data.getJSONObject(i);
|
||||||
|
String name = menu.getString("name");
|
||||||
|
String url = menu.getString("url");
|
||||||
|
TreeItem<MenuData> management = new TreeItem<>(new MenuData(name, null, url));
|
||||||
|
management.setGraphic(new Label(management.getValue().getTitle()));
|
||||||
|
|
||||||
|
JSONArray children = (JSONArray) menu.get("children");
|
||||||
|
children.forEach(child -> {
|
||||||
|
JSONObject childMenu = (JSONObject) child;
|
||||||
|
String childName = childMenu.getString("name");
|
||||||
|
String childUrl = childMenu.getString("url");
|
||||||
|
TreeItem<MenuData> menuDataTreeItem = new TreeItem<>(new MenuData(childName, null, childUrl));
|
||||||
|
menuDataTreeItem.setGraphic(new Label(menuDataTreeItem.getValue().getTitle()));
|
||||||
|
management.getChildren().add(menuDataTreeItem);
|
||||||
|
});
|
||||||
|
menuList.add(management);
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createUser(User user) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateUser(User user) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,6 +45,7 @@ import java.io.IOException;
|
||||||
*/
|
*/
|
||||||
public class AlertUtils {
|
public class AlertUtils {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 警告弹窗
|
* 警告弹窗
|
||||||
*/
|
*/
|
||||||
|
|
@ -87,4 +88,18 @@ public class AlertUtils {
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void alert(String title, FXMLLoader loader, Stage primaryStage){
|
||||||
|
try {
|
||||||
|
Scene scene = new Scene(loader.load());
|
||||||
|
Stage dialogStage = new Stage();
|
||||||
|
dialogStage.setTitle(title);
|
||||||
|
dialogStage.initModality(Modality.WINDOW_MODAL);
|
||||||
|
dialogStage.initOwner(primaryStage);
|
||||||
|
dialogStage.setScene(scene);
|
||||||
|
dialogStage.showAndWait();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.zhangmeng.online.exam.ui.utils;
|
||||||
|
|
||||||
|
import com.zhangmeng.online.exam.ui.api.form.RoleForm;
|
||||||
|
import com.zhangmeng.online.exam.ui.api.form.UserForm;
|
||||||
|
import com.zhangmeng.online.exam.ui.api.form.base.Form;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zm
|
||||||
|
* @date 2025/3/31 15:48
|
||||||
|
* @version: 1.0
|
||||||
|
*/
|
||||||
|
public class FxUtils {
|
||||||
|
|
||||||
|
public final static double DEFAULT_WIDTH = 1280;
|
||||||
|
public final static double DEFAULT_HEIGHT = 720;
|
||||||
|
|
||||||
|
public static void alert(String title, Parent node, Stage primaryStage) {
|
||||||
|
Form form = (Form) node;
|
||||||
|
if (form instanceof UserForm) {
|
||||||
|
form = new UserForm(true);
|
||||||
|
}
|
||||||
|
if (form instanceof RoleForm) {
|
||||||
|
form = new RoleForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene scene = new Scene(form);
|
||||||
|
Stage dialogStage = new Stage();
|
||||||
|
dialogStage.setTitle(title);
|
||||||
|
dialogStage.setResizable(false);
|
||||||
|
dialogStage.initModality(Modality.WINDOW_MODAL);
|
||||||
|
dialogStage.initOwner(primaryStage);
|
||||||
|
dialogStage.setScene(scene);
|
||||||
|
dialogStage.showAndWait();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.CharsetUtil;
|
import cn.hutool.core.util.CharsetUtil;
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.zhangmeng.online.exam.ui.service.UserService;
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
@ -18,6 +19,7 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class HttpUtils<T> {
|
public class HttpUtils<T> {
|
||||||
|
|
||||||
|
|
||||||
public static Map<String, Object> USER_INFO = new HashMap<>();
|
public static Map<String, Object> USER_INFO = new HashMap<>();
|
||||||
|
|
||||||
public static <T> T GET(String url, Class<T> clazz) {
|
public static <T> T GET(String url, Class<T> clazz) {
|
||||||
|
|
@ -26,20 +28,20 @@ public class HttpUtils<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String GET(String url) {
|
public static String GET(String url) {
|
||||||
url = url + "?token=" + USER_INFO.get("token");
|
url = url + "?token=" + UserService.getCurrentUser().getToken();
|
||||||
return HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8);
|
return HttpUtil.get(url, CharsetUtil.CHARSET_UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String GET(String url, Map<String, Object> params) {
|
public static String GET(String url, Map<String, Object> params) {
|
||||||
|
|
||||||
Object token = USER_INFO.get("token");
|
String token = UserService.getCurrentUser().getToken();
|
||||||
params.put("token",token);
|
params.put("token",token);
|
||||||
return HttpUtil.get(url, params);
|
return HttpUtil.get(url, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String POST(String url, Map<String, Object> params) {
|
public static String POST(String url, Map<String, Object> params) {
|
||||||
HashMap<String, Object> paramMap = new HashMap<>(params);
|
HashMap<String, Object> paramMap = new HashMap<>(params);
|
||||||
Object token = USER_INFO.get("token");
|
String token = UserService.getCurrentUser().getToken();
|
||||||
paramMap.put("token",token);
|
paramMap.put("token",token);
|
||||||
return HttpUtil.post(url, paramMap);
|
return HttpUtil.post(url, paramMap);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
|
||||||
|
<BorderPane xmlns:fx="http://javafx.com/fxml"
|
||||||
|
fx:controller="com.zhangmeng.online.exam.ui.controller.MainController">
|
||||||
|
<top>
|
||||||
|
<HBox spacing="10" alignment="CENTER_RIGHT" style="-fx-padding: 5;">
|
||||||
|
<Label fx:id="userLabel"/>
|
||||||
|
<Button text="退出" onAction="#handleLogout"/>
|
||||||
|
</HBox>
|
||||||
|
</top>
|
||||||
|
|
||||||
|
<left>
|
||||||
|
<TreeView fx:id="menuTree" prefWidth="200"/>
|
||||||
|
</left>
|
||||||
|
|
||||||
|
<center>
|
||||||
|
<TabPane fx:id="contentTabPane" tabClosingPolicy="ALL_TABS"/>
|
||||||
|
</center>
|
||||||
|
</BorderPane>
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import javafx.scene.control.Button?>
|
|
||||||
<?import javafx.scene.control.ChoiceBox?>
|
|
||||||
<?import javafx.scene.control.Label?>
|
|
||||||
<?import javafx.scene.control.TextField?>
|
|
||||||
<?import javafx.scene.layout.AnchorPane?>
|
|
||||||
|
|
||||||
|
|
||||||
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fmxl.RoleForm">
|
|
||||||
<children>
|
|
||||||
<Label layoutX="135.0" layoutY="84.0" text="类型:" />
|
|
||||||
<Label layoutX="130.0" layoutY="145.0" text="角色名称:" />
|
|
||||||
<Label layoutX="123.0" layoutY="209.0" text="角色描述:" />
|
|
||||||
<ChoiceBox layoutX="234.0" layoutY="80.0" prefHeight="23.0" prefWidth="229.0" />
|
|
||||||
<TextField layoutX="234.0" layoutY="141.0" prefHeight="23.0" prefWidth="229.0" />
|
|
||||||
<TextField layoutX="234.0" layoutY="205.0" prefHeight="23.0" prefWidth="229.0" />
|
|
||||||
<Button layoutX="267.0" layoutY="289.0" mnemonicParsing="false" text="保存" />
|
|
||||||
</children>
|
|
||||||
</AnchorPane>
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
|
||||||
|
<VBox spacing="10" xmlns:fx="http://javafx.com/fxml"
|
||||||
|
fx:controller="com.zhangmeng.online.exam.ui.controller.UserEditController">
|
||||||
|
<padding>
|
||||||
|
<Insets top="10" right="10" bottom="10" left="10"/>
|
||||||
|
</padding>
|
||||||
|
|
||||||
|
<GridPane hgap="10" vgap="10">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints minWidth="80" prefWidth="100"/>
|
||||||
|
<ColumnConstraints hgrow="ALWAYS"/>
|
||||||
|
</columnConstraints>
|
||||||
|
|
||||||
|
<!-- 用户名 -->
|
||||||
|
<Label text="用户名:" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
|
||||||
|
<TextField fx:id="usernameField" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
|
||||||
|
|
||||||
|
<!-- 姓名 -->
|
||||||
|
<Label text="姓名:" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
|
||||||
|
<TextField fx:id="nameField" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
|
||||||
|
|
||||||
|
<!-- 密码 -->
|
||||||
|
<Label text="密码:" GridPane.rowIndex="2" GridPane.columnIndex="0"/>
|
||||||
|
<PasswordField fx:id="passwordField" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
|
||||||
|
|
||||||
|
<!-- 邮箱 -->
|
||||||
|
<Label text="邮箱:" GridPane.rowIndex="3" GridPane.columnIndex="0"/>
|
||||||
|
<TextField fx:id="emailField" GridPane.rowIndex="3" GridPane.columnIndex="1"/>
|
||||||
|
|
||||||
|
<!-- 状态 -->
|
||||||
|
<Label text="状态:" GridPane.rowIndex="4" GridPane.columnIndex="0"/>
|
||||||
|
<ComboBox fx:id="statusComboBox" GridPane.rowIndex="4" GridPane.columnIndex="1"/>
|
||||||
|
|
||||||
|
<!-- 角色 -->
|
||||||
|
<Label text="角色:" GridPane.rowIndex="5" GridPane.columnIndex="0"/>
|
||||||
|
<ListView fx:id="roleListView" prefHeight="100" GridPane.rowIndex="5" GridPane.columnIndex="1"/>
|
||||||
|
</GridPane>
|
||||||
|
|
||||||
|
<HBox spacing="10" alignment="CENTER_RIGHT">
|
||||||
|
<Button text="保存" onAction="#handleSave" defaultButton="true"/>
|
||||||
|
<Button text="取消" onAction="#handleCancel" cancelButton="true"/>
|
||||||
|
</HBox>
|
||||||
|
</VBox>
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.scene.control.*?>
|
||||||
|
<?import javafx.scene.layout.*?>
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
|
||||||
|
<VBox spacing="10" xmlns:fx="http://javafx.com/fxml"
|
||||||
|
fx:controller="com.zhangmeng.online.exam.ui.controller.UserListController">
|
||||||
|
<padding>
|
||||||
|
<Insets top="10" right="10" bottom="10" left="10"/>
|
||||||
|
</padding>
|
||||||
|
<children>
|
||||||
|
<HBox spacing="10" alignment="CENTER_LEFT">
|
||||||
|
<TextField fx:id="searchField" promptText="输入关键字搜索..." HBox.hgrow="ALWAYS"/>
|
||||||
|
<Button text="搜索" onAction="#handleSearch"/>
|
||||||
|
<Region HBox.hgrow="ALWAYS"/>
|
||||||
|
<Button fx:id="addButton" text="添加用户" onAction="#handleAdd"/>
|
||||||
|
</HBox>
|
||||||
|
<TableView fx:id="userTable" VBox.vgrow="ALWAYS">
|
||||||
|
<columns>
|
||||||
|
<TableColumn fx:id="idColumn" text="ID" prefWidth="50"/>
|
||||||
|
<TableColumn fx:id="usernameColumn" text="用户名" prefWidth="100"/>
|
||||||
|
<TableColumn fx:id="nameColumn" text="姓名" prefWidth="100"/>
|
||||||
|
<TableColumn fx:id="emailColumn" text="邮箱" prefWidth="150"/>
|
||||||
|
<TableColumn fx:id="statusColumn" text="状态" prefWidth="80"/>
|
||||||
|
<TableColumn fx:id="actionColumn" text="操作" prefWidth="150"/>
|
||||||
|
</columns>
|
||||||
|
</TableView>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
||||||
Loading…
Reference in New Issue