5.30测试源代码

`package com.example.test.controller;

import com.example.test.entity.;
import com.example.test.service.AdminService;
import com.example.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.
;

import jakarta.servlet.http.HttpSession;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**

  • 管理员控制器,提供对所有表的增删改查操作
    */
    @RestController
    @RequestMapping("/api/admin")
    public class AdminController {

    private final UserService userService;
    private final AdminService adminService;

    @Autowired
    public AdminController(UserService userService, AdminService adminService) {
    this.userService = userService;
    this.adminService = adminService;
    }

    /**

    • 检查管理员权限
      */
      private boolean checkAdminPermission(HttpSession session) {
      User currentUser = (User) session.getAttribute("currentUser");
      return currentUser != null && currentUser.isAdmin();
      }

    /**

    • 获取未授权响应
      */
      private ResponseEntity<?> getUnauthorizedResponse() {
      Map<String, String> response = new HashMap<>();
      response.put("message", "未授权的操作,需要管理员权限");
      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
      }

    /**

    • 获取指定实体的所有记录
      */
      @GetMapping("/{entityName}")
      public ResponseEntity<?> getAllEntities(
      @PathVariable String entityName,
      HttpSession session) {

      // 检查管理员权限
      if (!checkAdminPermission(session)) {
      return getUnauthorizedResponse();
      }

      try {
      // 根据实体名称获取对应的类
      Class<?> entityClass = adminService.getEntityClassByName(entityName);
      if (entityClass == null) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "实体不存在: " + entityName);
      return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
      }

       // 查询所有记录
       List<?> entities = adminService.findAll(entityClass);
       return ResponseEntity.ok(entities);
      

      } catch (Exception e) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "查询失败: " + e.getMessage());
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
      }
      }

    /**

    • 根据ID获取指定实体的记录
      */
      @GetMapping("/{entityName}/{id}")
      public ResponseEntity<?> getEntityById(
      @PathVariable String entityName,
      @PathVariable Long id,
      HttpSession session) {

      // 检查管理员权限
      if (!checkAdminPermission(session)) {
      return getUnauthorizedResponse();
      }

      try {
      // 根据实体名称获取对应的类
      Class<?> entityClass = adminService.getEntityClassByName(entityName);
      if (entityClass == null) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "实体不存在: " + entityName);
      return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
      }

       // 查询指定ID的记录
       Object entity = adminService.findById(entityClass, id);
       if (entity == null) {
           Map<String, String> response = new HashMap<>();
           response.put("message", "未找到ID为: " + id + " 的记录");
           return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
       }
       
       return ResponseEntity.ok(entity);
      

      } catch (Exception e) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "查询失败: " + e.getMessage());
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
      }
      }

    /**

    • 创建实体记录
      */
      @PostMapping("/{entityName}")
      public ResponseEntity<?> createEntity(
      @PathVariable String entityName,
      @RequestBody Object entityData,
      HttpSession session) {

      // 检查管理员权限
      if (!checkAdminPermission(session)) {
      return getUnauthorizedResponse();
      }

      try {
      // 保存实体
      Object savedEntity = adminService.save(entityData);
      return ResponseEntity.status(HttpStatus.CREATED).body(savedEntity);

      } catch (Exception e) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "创建失败: " + e.getMessage());
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
      }
      }

    /**

    • 更新实体记录
      */
      @PutMapping("/{entityName}/{id}")
      public ResponseEntity<?> updateEntity(
      @PathVariable String entityName,
      @PathVariable Long id,
      @RequestBody Object entityData,
      HttpSession session) {

      // 检查管理员权限
      if (!checkAdminPermission(session)) {
      return getUnauthorizedResponse();
      }

      try {
      // 根据实体名称获取对应的类
      Class<?> entityClass = adminService.getEntityClassByName(entityName);
      if (entityClass == null) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "实体不存在: " + entityName);
      return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
      }

       // 查询指定ID的记录
       Object entity = adminService.findById(entityClass, id);
       if (entity == null) {
           Map<String, String> response = new HashMap<>();
           response.put("message", "未找到ID为: " + id + " 的记录");
           return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
       }
       
       // 更新实体
       Object updatedEntity = adminService.save(entityData);
       return ResponseEntity.ok(updatedEntity);
      

      } catch (Exception e) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "更新失败: " + e.getMessage());
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
      }
      }

    /**

    • 删除实体记录
      */
      @DeleteMapping("/{entityName}/{id}")
      public ResponseEntity<?> deleteEntity(
      @PathVariable String entityName,
      @PathVariable Long id,
      HttpSession session) {

      // 检查管理员权限
      if (!checkAdminPermission(session)) {
      return getUnauthorizedResponse();
      }

      try {
      // 根据实体名称获取对应的类
      Class<?> entityClass = adminService.getEntityClassByName(entityName);
      if (entityClass == null) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "实体不存在: " + entityName);
      return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
      }

       // 查询指定ID的记录
       Object entity = adminService.findById(entityClass, id);
       if (entity == null) {
           Map<String, String> response = new HashMap<>();
           response.put("message", "未找到ID为: " + id + " 的记录");
           return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
       }
       
       // 删除实体
       adminService.delete(entityClass, id);
       
       Map<String, String> response = new HashMap<>();
       response.put("message", "记录已成功删除");
       return ResponseEntity.ok(response);
      

      } catch (Exception e) {
      Map<String, String> response = new HashMap<>();
      response.put("message", "删除失败: " + e.getMessage());
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
      }
      }
      }package com.example.test.controller;

import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;

import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;

/**

  • 自定义错误控制器

  • 处理应用程序中的错误,提供友好的错误页面
    */
    @Controller
    public class CustomErrorController implements ErrorController {

    private final ErrorAttributes errorAttributes;

    public CustomErrorController(ErrorAttributes errorAttributes) {
    this.errorAttributes = errorAttributes;
    }

    /**

    • 处理HTML请求的错误页面
      */
      @RequestMapping(value = "/error", produces = "text/html")
      public String errorHtml(HttpServletRequest request, Model model) {
      // 获取错误属性
      WebRequest webRequest = new ServletWebRequest(request);
      Map<String, Object> errorAttributes = this.errorAttributes.getErrorAttributes(
      webRequest, ErrorAttributeOptions.defaults());

      // 将错误属性添加到模型中
      model.addAllAttributes(errorAttributes);

      // 获取HTTP状态码
      HttpStatus status = getStatus(request);
      model.addAttribute("status", status.value());
      model.addAttribute("error", status.getReasonPhrase());

      // 返回错误视图
      return "error";
      }

    /**

    • 处理API请求的错误响应
      */
      @RequestMapping(value = "/error")
      @ResponseBody
      public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
      // 获取错误属性
      WebRequest webRequest = new ServletWebRequest(request);
      Map<String, Object> body = this.errorAttributes.getErrorAttributes(
      webRequest, ErrorAttributeOptions.defaults());

      // 获取HTTP状态码
      HttpStatus status = getStatus(request);

      // 返回错误响应
      return new ResponseEntity<>(body, status);
      }

    /**

    • 获取HTTP状态码
      */
      private HttpStatus getStatus(HttpServletRequest request) {
      Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
      if (statusCode == null) {
      return HttpStatus.INTERNAL_SERVER_ERROR;
      }
      try {
      return HttpStatus.valueOf(statusCode);
      } catch (Exception ex) {
      return HttpStatus.INTERNAL_SERVER_ERROR;
      }
      }

    // 在Spring Boot 3.x中,ErrorController接口不再要求实现getErrorPath方法
    }package com.example.test.controller;

import com.example.test.entity.User;
import com.example.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserService userService;

@Autowired
public UserController(UserService userService) {
    this.userService = userService;
}

// 创建用户
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
    User createdUser = userService.createUser(user);
    return new ResponseEntity<>(createdUser, HttpStatus.CREATED);
}

// 用户登录
@PostMapping("/login")
public ResponseEntity<?> login(@RequestParam String username, @RequestParam String password) {
    User user = userService.login(username, password);
    if (user != null) {
        return ResponseEntity.ok(user);
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "用户名或密码错误");
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response);
    }
}

// 获取所有用户
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
    List<User> users = userService.findAllUsers();
    return ResponseEntity.ok(users);
}

// 根据用户名查询用户
@GetMapping("/username/{username}")
public ResponseEntity<?> getUserByUsername(@PathVariable String username) {
    User user = userService.findUserByUsername(username);
    if (user != null) {
        return ResponseEntity.ok(user);
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "未找到用户名为: " + username + " 的用户");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

// 根据邮箱查询用户
@GetMapping("/email/{email}")
public ResponseEntity<?> getUserByEmail(@PathVariable String email) {
    User user = userService.findUserByEmail(email);
    if (user != null) {
        return ResponseEntity.ok(user);
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "未找到邮箱为: " + email + " 的用户");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

// 根据电话查询用户
@GetMapping("/phone/{phone}")
public ResponseEntity<?> getUserByPhone(@PathVariable String phone) {
    User user = userService.findUserByPhone(phone);
    if (user != null) {
        return ResponseEntity.ok(user);
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "未找到电话为: " + phone + " 的用户");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

// 根据ID获取用户
@GetMapping("/{id}")
public ResponseEntity<?> getUserById(@PathVariable Long id) {
    Optional<User> userOptional = userService.findUserById(id);
    if (userOptional.isPresent()) {
        return ResponseEntity.ok(userOptional.get());
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "未找到ID为: " + id + " 的用户");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

// 根据部门查询用户列表
@GetMapping("/department/{department}")
public ResponseEntity<List<User>> getUsersByDepartment(@PathVariable String department) {
    List<User> users = userService.findUsersByDepartment(department);
    return ResponseEntity.ok(users);
}

// 根据职位查询用户列表
@GetMapping("/position/{position}")
public ResponseEntity<List<User>> getUsersByPosition(@PathVariable String position) {
    List<User> users = userService.findUsersByPosition(position);
    return ResponseEntity.ok(users);
}

// 根据部门和职位查询用户列表
@GetMapping("/department/{department}/position/{position}")
public ResponseEntity<List<User>> getUsersByDepartmentAndPosition(
        @PathVariable String department, 
        @PathVariable String position) {
    List<User> users = userService.findUsersByDepartmentAndPosition(department, position);
    return ResponseEntity.ok(users);
}

// 根据状态查询用户列表
@GetMapping("/status/{status}")
public ResponseEntity<List<User>> getUsersByStatus(@PathVariable Boolean status) {
    List<User> users = userService.findUsersByStatus(status);
    return ResponseEntity.ok(users);
}

// 根据真实姓名模糊查询
@GetMapping("/search/realname")
public ResponseEntity<List<User>> searchUsersByRealName(@RequestParam String keyword) {
    List<User> users = userService.findUsersByRealNameContaining(keyword);
    return ResponseEntity.ok(users);
}

// 查询指定时间之后创建的用户
@GetMapping("/created-after")
public ResponseEntity<List<User>> getUsersCreatedAfter(
        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateTime) {
    List<User> users = userService.findUsersByCreateTimeAfter(dateTime);
    return ResponseEntity.ok(users);
}

// 查询指定时间之后登录的用户
@GetMapping("/login-after")
public ResponseEntity<List<User>> getUsersLoggedInAfter(
        @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateTime) {
    List<User> users = userService.findUsersByLastLoginTimeAfter(dateTime);
    return ResponseEntity.ok(users);
}

// 更新用户
@PutMapping("/{id}")
public ResponseEntity<?> updateUser(@PathVariable Long id, @RequestBody User userDetails) {
    Optional<User> userOptional = userService.findUserById(id);
    if (userOptional.isPresent()) {
        User user = userOptional.get();
        // 保存原始用户名,确保不被修改
        String originalUsername = user.getUsername();
        
        // 更新用户信息
        if (userDetails.getPassword() != null) {
            user.setPassword(userDetails.getPassword());
        }
        if (userDetails.getRealName() != null) {
            user.setRealName(userDetails.getRealName());
        }
        if (userDetails.getEmail() != null) {
            user.setEmail(userDetails.getEmail());
        }
        if (userDetails.getPhone() != null) {
            user.setPhone(userDetails.getPhone());
        }
        if (userDetails.getDepartment() != null) {
            user.setDepartment(userDetails.getDepartment());
        }
        if (userDetails.getPosition() != null) {
            user.setPosition(userDetails.getPosition());
        }
        if (userDetails.getStatus() != null) {
            user.setStatus(userDetails.getStatus());
        }
        
        // 确保用户名不变
        user.setUsername(originalUsername);
        
        User updatedUser = userService.updateUser(user);
        return ResponseEntity.ok(updatedUser);
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "未找到ID为: " + id + " 的用户");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

// 启用用户
@PatchMapping("/{id}/enable")
public ResponseEntity<?> enableUser(@PathVariable Long id) {
    User user = userService.enableUser(id);
    if (user != null) {
        return ResponseEntity.ok(user);
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "未找到ID为: " + id + " 的用户");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

// 禁用用户
@PatchMapping("/{id}/disable")
public ResponseEntity<?> disableUser(@PathVariable Long id) {
    User user = userService.disableUser(id);
    if (user != null) {
        return ResponseEntity.ok(user);
    } else {
        Map<String, String> response = new HashMap<>();
        response.put("message", "未找到ID为: " + id + " 的用户");
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

// 删除用户
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteUser(@PathVariable Long id) {
    return userService.findUserById(id)
            .map(user -> {
                userService.deleteUser(id);
                Map<String, String> response = new HashMap<>();
                response.put("message", "用户已成功删除");
                return ResponseEntity.ok(response);
            })
            .orElseGet(() -> {
                Map<String, String> response = new HashMap<>();
                response.put("message", "未找到ID为: " + id + " 的用户");
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
            });
}

}package com.example.test.controller;

import com.example.test.entity.User;
import com.example.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import jakarta.servlet.http.HttpSession;
import java.util.List;

/**

  • Web页面控制器,处理HTML页面的请求
    */
    @Controller
    public class WebController {

    private final UserService userService;

    @Autowired
    public WebController(UserService userService) {
    this.userService = userService;
    }

    /**

    • 首页重定向到登录页
      */
      @GetMapping("/")
      public String index() {
      return "redirect:/login";
      }

    /**

    • 显示登录页面
      */
      @GetMapping("/login")
      public String showLoginPage() {
      return "login";
      }

    /**

    • 处理登录请求
      */
      @PostMapping("/login")
      public String processLogin(@RequestParam String username,
      @RequestParam String password,
      RedirectAttributes redirectAttributes,
      HttpSession session) {
      User user = userService.login(username, password);
      if (user != null) {
      // 登录成功,将用户信息存储在session中
      session.setAttribute("currentUser", user);

       // 根据用户角色跳转到不同页面
       if (user.isAdmin()) {
           return "redirect:/admin/dashboard";
       } else {
           return "redirect:/dashboard";
       }
      

      } else {
      // 登录失败,添加错误消息并返回登录页
      redirectAttributes.addFlashAttribute("errorMessage", "用户名或密码错误");
      return "redirect:/login";
      }
      }

    /**

    • 显示注册页面
      */
      @GetMapping("/register")
      public String showRegisterPage() {
      return "redirect:/login?register";
      }

    /**

    • 处理注册请求
      */
      @PostMapping("/register")
      public String processRegistration(@ModelAttribute User user,
      RedirectAttributes redirectAttributes) {
      // 检查用户名是否已存在
      if (userService.findUserByUsername(user.getUsername()) != null) {
      redirectAttributes.addFlashAttribute("errorMessage", "用户名已存在");
      return "redirect:/login?register";
      }

      // 检查邮箱是否已存在
      if (userService.findUserByEmail(user.getEmail()) != null) {
      redirectAttributes.addFlashAttribute("errorMessage", "邮箱已被注册");
      return "redirect:/login?register";
      }

      // 检查手机号是否已存在
      if (user.getPhone() != null && userService.findUserByPhone(user.getPhone()) != null) {
      redirectAttributes.addFlashAttribute("errorMessage", "手机号已被注册");
      return "redirect:/login?register";
      }

      // 设置用户状态为启用
      user.setStatus(true);

      // 保存用户
      try {
      userService.createUser(user);
      redirectAttributes.addFlashAttribute("success", "注册成功,请登录");
      return "redirect:/login";
      } catch (Exception e) {
      redirectAttributes.addFlashAttribute("errorMessage", "注册失败: " + e.getMessage());
      return "redirect:/login?register";
      }
      }

    /**

    • 用户仪表盘页面
      */
      @GetMapping("/dashboard")
      public String dashboard(HttpSession session, Model model) {
      // 验证用户是否已登录
      User currentUser = (User) session.getAttribute("currentUser");
      if (currentUser == null) {
      // 用户未登录,重定向到登录页
      return "redirect:/login";
      }
      // 将用户信息添加到模型中,供模板使用
      model.addAttribute("currentUser", currentUser);
      return "dashboard";
      }

    /**

    • 管理员仪表盘页面
      */
      @GetMapping("/admin/dashboard")
      public String adminDashboard(HttpSession session, Model model) {
      // 验证用户是否已登录且是管理员
      User currentUser = (User) session.getAttribute("currentUser");
      if (currentUser == null) {
      // 用户未登录,重定向到登录页
      return "redirect:/login";
      }

      if (!currentUser.isAdmin()) {
      // 用户不是管理员,重定向到普通用户仪表盘
      return "redirect:/dashboard";
      }

      // 将用户信息添加到模型中,供模板使用
      model.addAttribute("currentUser", currentUser);
      return "admin/dashboard";
      }

    /**

    • 管理员用户管理页面
      */
      @GetMapping("/admin/users")
      public String adminUserManagement(HttpSession session, Model model) {
      // 验证用户是否已登录且是管理员
      User currentUser = (User) session.getAttribute("currentUser");
      if (currentUser == null) {
      // 用户未登录,重定向到登录页
      return "redirect:/login";
      }

      if (!currentUser.isAdmin()) {
      // 用户不是管理员,重定向到普通用户仪表盘
      return "redirect:/dashboard";
      }

      // 获取所有用户列表
      List users = userService.findAllUsers();

      // 将用户信息添加到模型中,供模板使用
      model.addAttribute("currentUser", currentUser);
      model.addAttribute("users", users);
      return "admin/users";
      }

    /**

    • 退出登录
      */
      @GetMapping("/logout")
      public String logout(HttpSession session) {
      // 清除session
      session.invalidate();
      return "redirect:/login";
      }
      }package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;

@Entity
@Table(name = "contact_form")
public class ContactForm {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "form_number", nullable = false, unique = true, length = 50)
private String formNumber;

@ManyToOne
@JoinColumn(name = "order_id")
private SalesOrder order;

@Column(name = "order_number", length = 50)
private String orderNumber;

@ManyToOne
@JoinColumn(name = "customer_id")
private User customer;

@Column(name = "customer_name", length = 100)
private String customerName;

@Column(name = "contact_type", length = 20)
private String contactType; // 订单咨询、产品咨询、投诉、建议、其他

@Column(name = "contact_content", nullable = false, length = 1000)
private String contactContent;

@Column(name = "contact_status", length = 20)
private String contactStatus; // 待处理、处理中、已完成

@Column(name = "priority", length = 10)
private String priority; // 高、中、低

@ManyToOne
@JoinColumn(name = "handler_id")
private User handler;

@Column(name = "handler_name", length = 50)
private String handlerName;

@Column(name = "handling_result", length = 1000)
private String handlingResult;

@Column(name = "handling_time")
private LocalDateTime handlingTime;

@Column(name = "create_time")
private LocalDateTime createTime;

@Column(name = "update_time")
private LocalDateTime updateTime;

@Column(name = "created_by")
private Long createdBy;

@Column(name = "updated_by")
private Long updatedBy;

// 默认构造函数
public ContactForm() {
}

// 带基本参数的构造函数
public ContactForm(String formNumber, String contactType, String contactContent) {
    this.formNumber = formNumber;
    this.contactType = contactType;
    this.contactContent = contactContent;
    this.contactStatus = "待处理";
    this.priority = "中";
    this.createTime = LocalDateTime.now();
    this.updateTime = LocalDateTime.now();
}

// 带订单和客户的构造函数
public ContactForm(String formNumber, SalesOrder order, User customer, String contactType, String contactContent) {
    this(formNumber, contactType, contactContent);
    this.order = order;
    if (order != null) {
        this.orderNumber = order.getOrderNumber();
    }
    this.customer = customer;
    this.customerName = customer != null ? customer.getRealName() : null;
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getFormNumber() {
    return formNumber;
}

public void setFormNumber(String formNumber) {
    this.formNumber = formNumber;
}

public SalesOrder getOrder() {
    return order;
}

public void setOrder(SalesOrder order) {
    this.order = order;
    if (order != null) {
        this.orderNumber = order.getOrderNumber();
    }
}

public String getOrderNumber() {
    return orderNumber;
}

public void setOrderNumber(String orderNumber) {
    this.orderNumber = orderNumber;
}

public User getCustomer() {
    return customer;
}

public void setCustomer(User customer) {
    this.customer = customer;
    this.customerName = customer != null ? customer.getRealName() : null;
}

public String getCustomerName() {
    return customerName;
}

public void setCustomerName(String customerName) {
    this.customerName = customerName;
}

public String getContactType() {
    return contactType;
}

public void setContactType(String contactType) {
    this.contactType = contactType;
}

public String getContactContent() {
    return contactContent;
}

public void setContactContent(String contactContent) {
    this.contactContent = contactContent;
}

public String getContactStatus() {
    return contactStatus;
}

public void setContactStatus(String contactStatus) {
    this.contactStatus = contactStatus;
}

public String getPriority() {
    return priority;
}

public void setPriority(String priority) {
    this.priority = priority;
}

public User getHandler() {
    return handler;
}

public void setHandler(User handler) {
    this.handler = handler;
    this.handlerName = handler != null ? handler.getRealName() : null;
}

public String getHandlerName() {
    return handlerName;
}

public void setHandlerName(String handlerName) {
    this.handlerName = handlerName;
}

public String getHandlingResult() {
    return handlingResult;
}

public void setHandlingResult(String handlingResult) {
    this.handlingResult = handlingResult;
}

public LocalDateTime getHandlingTime() {
    return handlingTime;
}

public void setHandlingTime(LocalDateTime handlingTime) {
    this.handlingTime = handlingTime;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

public LocalDateTime getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(LocalDateTime updateTime) {
    this.updateTime = updateTime;
}

public Long getCreatedBy() {
    return createdBy;
}

public void setCreatedBy(Long createdBy) {
    this.createdBy = createdBy;
}

public Long getUpdatedBy() {
    return updatedBy;
}

public void setUpdatedBy(Long updatedBy) {
    this.updatedBy = updatedBy;
}

@Override
public String toString() {
    return "ContactForm{" +
            "id=" + id +
            ", formNumber='" + formNumber + '\'' +
            ", orderNumber='" + orderNumber + '\'' +
            ", customerName='" + customerName + '\'' +
            ", contactType='" + contactType + '\'' +
            ", contactStatus='" + contactStatus + '\'' +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Entity
@Table(name = "delivery_order")
public class DeliveryOrder {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "delivery_number", nullable = false, unique = true, length = 50)
private String deliveryNumber;

@ManyToOne
@JoinColumn(name = "order_id")
private SalesOrder order;

@Column(name = "order_number", length = 50)
private String orderNumber;

@ManyToOne
@JoinColumn(name = "customer_id")
private User customer;

@Column(name = "customer_name", length = 100)
private String customerName;

@Column(name = "contact_address", length = 255)
private String contactAddress;

@Column(name = "delivery_date")
private LocalDateTime deliveryDate;

@Column(name = "shipping_method", length = 50)
private String shippingMethod;

@Column(name = "tracking_number", length = 50)
private String trackingNumber;

@Column(name = "delivery_status", length = 20)
private String deliveryStatus; // 待发货、已发货、已签收

@Column(name = "total_quantity")
private Integer totalQuantity;

@Column(name = "total_amount", precision = 10, scale = 2)
private BigDecimal totalAmount;

@Column(name = "remarks", length = 500)
private String remarks;

@ManyToOne
@JoinColumn(name = "handler_id")
private User handler;

@Column(name = "handler_name", length = 50)
private String handlerName;

@Column(name = "create_time")
private LocalDateTime createTime;

@Column(name = "update_time")
private LocalDateTime updateTime;

@Column(name = "created_by")
private Long createdBy;

@Column(name = "updated_by")
private Long updatedBy;

// 默认构造函数
public DeliveryOrder() {
}

// 带基本参数的构造函数
public DeliveryOrder(String deliveryNumber, SalesOrder order) {
    this.deliveryNumber = deliveryNumber;
    this.order = order;
    if (order != null) {
        this.orderNumber = order.getOrderNumber();
        this.customer = order.getCustomer();
        this.customerName = order.getCustomerName();
        this.contactAddress = order.getContactAddress();
        this.shippingMethod = order.getShippingMethod();
    }
    this.deliveryStatus = "待发货";
    this.createTime = LocalDateTime.now();
    this.updateTime = LocalDateTime.now();
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getDeliveryNumber() {
    return deliveryNumber;
}

public void setDeliveryNumber(String deliveryNumber) {
    this.deliveryNumber = deliveryNumber;
}

public SalesOrder getOrder() {
    return order;
}

public void setOrder(SalesOrder order) {
    this.order = order;
    if (order != null) {
        this.orderNumber = order.getOrderNumber();
        this.customer = order.getCustomer();
        this.customerName = order.getCustomerName();
        this.contactAddress = order.getContactAddress();
        this.shippingMethod = order.getShippingMethod();
    }
}

public String getOrderNumber() {
    return orderNumber;
}

public void setOrderNumber(String orderNumber) {
    this.orderNumber = orderNumber;
}

public User getCustomer() {
    return customer;
}

public void setCustomer(User customer) {
    this.customer = customer;
    this.customerName = customer != null ? customer.getRealName() : null;
}

public String getCustomerName() {
    return customerName;
}

public void setCustomerName(String customerName) {
    this.customerName = customerName;
}

public String getContactAddress() {
    return contactAddress;
}

public void setContactAddress(String contactAddress) {
    this.contactAddress = contactAddress;
}

public LocalDateTime getDeliveryDate() {
    return deliveryDate;
}

public void setDeliveryDate(LocalDateTime deliveryDate) {
    this.deliveryDate = deliveryDate;
}

public String getShippingMethod() {
    return shippingMethod;
}

public void setShippingMethod(String shippingMethod) {
    this.shippingMethod = shippingMethod;
}

public String getTrackingNumber() {
    return trackingNumber;
}

public void setTrackingNumber(String trackingNumber) {
    this.trackingNumber = trackingNumber;
}

public String getDeliveryStatus() {
    return deliveryStatus;
}

public void setDeliveryStatus(String deliveryStatus) {
    this.deliveryStatus = deliveryStatus;
}

public Integer getTotalQuantity() {
    return totalQuantity;
}

public void setTotalQuantity(Integer totalQuantity) {
    this.totalQuantity = totalQuantity;
}

public BigDecimal getTotalAmount() {
    return totalAmount;
}

public void setTotalAmount(BigDecimal totalAmount) {
    this.totalAmount = totalAmount;
}

public String getRemarks() {
    return remarks;
}

public void setRemarks(String remarks) {
    this.remarks = remarks;
}

public User getHandler() {
    return handler;
}

public void setHandler(User handler) {
    this.handler = handler;
    this.handlerName = handler != null ? handler.getRealName() : null;
}

public String getHandlerName() {
    return handlerName;
}

public void setHandlerName(String handlerName) {
    this.handlerName = handlerName;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

public LocalDateTime getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(LocalDateTime updateTime) {
    this.updateTime = updateTime;
}

public Long getCreatedBy() {
    return createdBy;
}

public void setCreatedBy(Long createdBy) {
    this.createdBy = createdBy;
}

public Long getUpdatedBy() {
    return updatedBy;
}

public void setUpdatedBy(Long updatedBy) {
    this.updatedBy = updatedBy;
}

@Override
public String toString() {
    return "DeliveryOrder{" +
            "id=" + id +
            ", deliveryNumber='" + deliveryNumber + '\'' +
            ", orderNumber='" + orderNumber + '\'' +
            ", customerName='" + customerName + '\'' +
            ", deliveryDate=" + deliveryDate +
            ", deliveryStatus='" + deliveryStatus + '\'' +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Entity
@Table(name = "delivery_statistics")
public class DeliveryStatistics {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "statistics_year")
private Integer statisticsYear;

@Column(name = "statistics_month")
private Integer statisticsMonth;

@Column(name = "statistics_quarter")
private Integer statisticsQuarter;

@Column(name = "customer_name", length = 100)
private String customerName;

@Column(name = "product_code", length = 50)
private String productCode;

@Column(name = "product_name", length = 100)
private String productName;

@Column(name = "product_model", length = 50)
private String productModel;

@Column(name = "delivery_quantity")
private Integer deliveryQuantity;

@Column(name = "delivery_amount", precision = 10, scale = 2)
private BigDecimal deliveryAmount;

@Column(name = "on_time_delivery_rate", precision = 5, scale = 2)
private BigDecimal onTimeDeliveryRate; // 准时交付率

@Column(name = "customer_satisfaction_rate", precision = 5, scale = 2)
private BigDecimal customerSatisfactionRate; // 客户满意度

@Column(name = "create_time")
private LocalDateTime createTime;

@Column(name = "update_time")
private LocalDateTime updateTime;

// 默认构造函数
public DeliveryStatistics() {
}

// 带基本参数的构造函数
public DeliveryStatistics(Integer statisticsYear, Integer statisticsMonth) {
    this.statisticsYear = statisticsYear;
    this.statisticsMonth = statisticsMonth;
    if (statisticsMonth != null) {
        this.statisticsQuarter = (statisticsMonth - 1) / 3 + 1;
    }
    this.createTime = LocalDateTime.now();
    this.updateTime = LocalDateTime.now();
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public Integer getStatisticsYear() {
    return statisticsYear;
}

public void setStatisticsYear(Integer statisticsYear) {
    this.statisticsYear = statisticsYear;
}

public Integer getStatisticsMonth() {
    return statisticsMonth;
}

public void setStatisticsMonth(Integer statisticsMonth) {
    this.statisticsMonth = statisticsMonth;
    if (statisticsMonth != null) {
        this.statisticsQuarter = (statisticsMonth - 1) / 3 + 1;
    }
}

public Integer getStatisticsQuarter() {
    return statisticsQuarter;
}

public void setStatisticsQuarter(Integer statisticsQuarter) {
    this.statisticsQuarter = statisticsQuarter;
}

public String getCustomerName() {
    return customerName;
}

public void setCustomerName(String customerName) {
    this.customerName = customerName;
}

public String getProductCode() {
    return productCode;
}

public void setProductCode(String productCode) {
    this.productCode = productCode;
}

public String getProductName() {
    return productName;
}

public void setProductName(String productName) {
    this.productName = productName;
}

public String getProductModel() {
    return productModel;
}

public void setProductModel(String productModel) {
    this.productModel = productModel;
}

public Integer getDeliveryQuantity() {
    return deliveryQuantity;
}

public void setDeliveryQuantity(Integer deliveryQuantity) {
    this.deliveryQuantity = deliveryQuantity;
}

public BigDecimal getDeliveryAmount() {
    return deliveryAmount;
}

public void setDeliveryAmount(BigDecimal deliveryAmount) {
    this.deliveryAmount = deliveryAmount;
}

public BigDecimal getOnTimeDeliveryRate() {
    return onTimeDeliveryRate;
}

public void setOnTimeDeliveryRate(BigDecimal onTimeDeliveryRate) {
    this.onTimeDeliveryRate = onTimeDeliveryRate;
}

public BigDecimal getCustomerSatisfactionRate() {
    return customerSatisfactionRate;
}

public void setCustomerSatisfactionRate(BigDecimal customerSatisfactionRate) {
    this.customerSatisfactionRate = customerSatisfactionRate;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

public LocalDateTime getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(LocalDateTime updateTime) {
    this.updateTime = updateTime;
}

@Override
public String toString() {
    return "DeliveryStatistics{" +
            "id=" + id +
            ", statisticsYear=" + statisticsYear +
            ", statisticsMonth=" + statisticsMonth +
            ", customerName='" + customerName + '\'' +
            ", productName='" + productName + '\'' +
            ", deliveryQuantity=" + deliveryQuantity +
            ", deliveryAmount=" + deliveryAmount +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Entity
@Table(name = "forecast_plan")
public class ForecastPlan {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "plan_number", nullable = false, unique = true, length = 50)
private String planNumber;

@Column(name = "plan_name", length = 100)
private String planName;

@Column(name = "plan_year")
private Integer planYear;

@Column(name = "plan_month")
private Integer planMonth;

@Column(name = "plan_quarter")
private Integer planQuarter;

@ManyToOne
@JoinColumn(name = "customer_id")
private User customer;

@Column(name = "customer_name", length = 100)
private String customerName;

@Column(name = "product_code", length = 50)
private String productCode;

@Column(name = "product_name", length = 100)
private String productName;

@Column(name = "forecast_quantity")
private Integer forecastQuantity;

@Column(name = "actual_quantity")
private Integer actualQuantity;

@Column(name = "forecast_amount", precision = 10, scale = 2)
private BigDecimal forecastAmount;

@Column(name = "actual_amount", precision = 10, scale = 2)
private BigDecimal actualAmount;

@Column(name = "plan_status", length = 20)
private String planStatus; // 草稿、已提交、已审核、已完成

@Column(name = "remarks", length = 500)
private String remarks;

@Column(name = "create_time")
private LocalDateTime createTime;

@Column(name = "update_time")
private LocalDateTime updateTime;

@Column(name = "created_by")
private Long createdBy;

@Column(name = "updated_by")
private Long updatedBy;

// 默认构造函数
public ForecastPlan() {
}

// 带基本参数的构造函数
public ForecastPlan(String planNumber, String planName, Integer planYear, Integer planMonth) {
    this.planNumber = planNumber;
    this.planName = planName;
    this.planYear = planYear;
    this.planMonth = planMonth;
    if (planMonth != null) {
        this.planQuarter = (planMonth - 1) / 3 + 1;
    }
    this.planStatus = "草稿";
    this.createTime = LocalDateTime.now();
    this.updateTime = LocalDateTime.now();
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getPlanNumber() {
    return planNumber;
}

public void setPlanNumber(String planNumber) {
    this.planNumber = planNumber;
}

public String getPlanName() {
    return planName;
}

public void setPlanName(String planName) {
    this.planName = planName;
}

public Integer getPlanYear() {
    return planYear;
}

public void setPlanYear(Integer planYear) {
    this.planYear = planYear;
}

public Integer getPlanMonth() {
    return planMonth;
}

public void setPlanMonth(Integer planMonth) {
    this.planMonth = planMonth;
    if (planMonth != null) {
        this.planQuarter = (planMonth - 1) / 3 + 1;
    }
}

public Integer getPlanQuarter() {
    return planQuarter;
}

public void setPlanQuarter(Integer planQuarter) {
    this.planQuarter = planQuarter;
}

public User getCustomer() {
    return customer;
}

public void setCustomer(User customer) {
    this.customer = customer;
    this.customerName = customer != null ? customer.getRealName() : null;
}

public String getCustomerName() {
    return customerName;
}

public void setCustomerName(String customerName) {
    this.customerName = customerName;
}

public String getProductCode() {
    return productCode;
}

public void setProductCode(String productCode) {
    this.productCode = productCode;
}

public String getProductName() {
    return productName;
}

public void setProductName(String productName) {
    this.productName = productName;
}

public Integer getForecastQuantity() {
    return forecastQuantity;
}

public void setForecastQuantity(Integer forecastQuantity) {
    this.forecastQuantity = forecastQuantity;
}

public Integer getActualQuantity() {
    return actualQuantity;
}

public void setActualQuantity(Integer actualQuantity) {
    this.actualQuantity = actualQuantity;
}

public BigDecimal getForecastAmount() {
    return forecastAmount;
}

public void setForecastAmount(BigDecimal forecastAmount) {
    this.forecastAmount = forecastAmount;
}

public BigDecimal getActualAmount() {
    return actualAmount;
}

public void setActualAmount(BigDecimal actualAmount) {
    this.actualAmount = actualAmount;
}

public String getPlanStatus() {
    return planStatus;
}

public void setPlanStatus(String planStatus) {
    this.planStatus = planStatus;
}

public String getRemarks() {
    return remarks;
}

public void setRemarks(String remarks) {
    this.remarks = remarks;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

public LocalDateTime getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(LocalDateTime updateTime) {
    this.updateTime = updateTime;
}

public Long getCreatedBy() {
    return createdBy;
}

public void setCreatedBy(Long createdBy) {
    this.createdBy = createdBy;
}

public Long getUpdatedBy() {
    return updatedBy;
}

public void setUpdatedBy(Long updatedBy) {
    this.updatedBy = updatedBy;
}

@Override
public String toString() {
    return "ForecastPlan{" +
            "id=" + id +
            ", planNumber='" + planNumber + '\'' +
            ", planName='" + planName + '\'' +
            ", planYear=" + planYear +
            ", planMonth=" + planMonth +
            ", customerName='" + customerName + '\'' +
            ", forecastQuantity=" + forecastQuantity +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;

@Entity
@Table(name = "missing_product")
public class MissingProduct {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "order_id")
private SalesOrder order;

@ManyToOne
@JoinColumn(name = "order_product_id")
private OrderProduct orderProduct;

@Column(name = "product_code", nullable = false, length = 50)
private String productCode;

@Column(name = "product_name", length = 100)
private String productName;

@Column(name = "product_model", length = 50)
private String productModel;

@Column(name = "unit", length = 20)
private String unit;

@Column(name = "missing_quantity", nullable = false)
private Integer missingQuantity;

@Column(name = "expected_arrival_date")
private LocalDateTime expectedArrivalDate;

@Column(name = "actual_arrival_date")
private LocalDateTime actualArrivalDate;

@Column(name = "status", length = 20)
private String status; // 缺货中、已到货、已取消

@Column(name = "remarks", length = 255)
private String remarks;

@Column(name = "create_time")
private LocalDateTime createTime;

@Column(name = "update_time")
private LocalDateTime updateTime;

// 默认构造函数
public MissingProduct() {
}

// 带基本参数的构造函数
public MissingProduct(SalesOrder order, OrderProduct orderProduct, Integer missingQuantity) {
    this.order = order;
    this.orderProduct = orderProduct;
    this.productCode = orderProduct != null ? orderProduct.getProductCode() : null;
    this.productName = orderProduct != null ? orderProduct.getProductName() : null;
    this.productModel = orderProduct != null ? orderProduct.getProductModel() : null;
    this.unit = orderProduct != null ? orderProduct.getUnit() : null;
    this.missingQuantity = missingQuantity;
    this.status = "缺货中";
    this.createTime = LocalDateTime.now();
    this.updateTime = LocalDateTime.now();
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public SalesOrder getOrder() {
    return order;
}

public void setOrder(SalesOrder order) {
    this.order = order;
}

public OrderProduct getOrderProduct() {
    return orderProduct;
}

public void setOrderProduct(OrderProduct orderProduct) {
    this.orderProduct = orderProduct;
    if (orderProduct != null) {
        this.productCode = orderProduct.getProductCode();
        this.productName = orderProduct.getProductName();
        this.productModel = orderProduct.getProductModel();
        this.unit = orderProduct.getUnit();
    }
}

public String getProductCode() {
    return productCode;
}

public void setProductCode(String productCode) {
    this.productCode = productCode;
}

public String getProductName() {
    return productName;
}

public void setProductName(String productName) {
    this.productName = productName;
}

public String getProductModel() {
    return productModel;
}

public void setProductModel(String productModel) {
    this.productModel = productModel;
}

public String getUnit() {
    return unit;
}

public void setUnit(String unit) {
    this.unit = unit;
}

public Integer getMissingQuantity() {
    return missingQuantity;
}

public void setMissingQuantity(Integer missingQuantity) {
    this.missingQuantity = missingQuantity;
}

public LocalDateTime getExpectedArrivalDate() {
    return expectedArrivalDate;
}

public void setExpectedArrivalDate(LocalDateTime expectedArrivalDate) {
    this.expectedArrivalDate = expectedArrivalDate;
}

public LocalDateTime getActualArrivalDate() {
    return actualArrivalDate;
}

public void setActualArrivalDate(LocalDateTime actualArrivalDate) {
    this.actualArrivalDate = actualArrivalDate;
}

public String getStatus() {
    return status;
}

public void setStatus(String status) {
    this.status = status;
}

public String getRemarks() {
    return remarks;
}

public void setRemarks(String remarks) {
    this.remarks = remarks;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

public LocalDateTime getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(LocalDateTime updateTime) {
    this.updateTime = updateTime;
}

@Override
public String toString() {
    return "MissingProduct{" +
            "id=" + id +
            ", productCode='" + productCode + '\'' +
            ", productName='" + productName + '\'' +
            ", missingQuantity=" + missingQuantity +
            ", status='" + status + '\'' +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;

@Entity
@Table(name = "order_change")
public class OrderChange {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "order_id", nullable = false)
private SalesOrder order;

@Column(name = "change_type", nullable = false, length = 20)
private String changeType; // 订单信息变更、产品变更、交期变更、取消订单

@Column(name = "change_content", nullable = false, length = 500)
private String changeContent;

@Column(name = "change_reason", length = 500)
private String changeReason;

@Column(name = "change_status", nullable = false, length = 20)
private String changeStatus; // 待审核、已通过、已拒绝

@ManyToOne
@JoinColumn(name = "applicant_id")
private User applicant;

@Column(name = "applicant_name", length = 50)
private String applicantName;

@Column(name = "apply_time")
private LocalDateTime applyTime;

@ManyToOne
@JoinColumn(name = "reviewer_id")
private User reviewer;

@Column(name = "reviewer_name", length = 50)
private String reviewerName;

@Column(name = "review_time")
private LocalDateTime reviewTime;

@Column(name = "review_comments", length = 500)
private String reviewComments;

// 默认构造函数
public OrderChange() {
}

// 带基本参数的构造函数
public OrderChange(SalesOrder order, String changeType, String changeContent, User applicant) {
    this.order = order;
    this.changeType = changeType;
    this.changeContent = changeContent;
    this.changeStatus = "待审核";
    this.applicant = applicant;
    this.applicantName = applicant != null ? applicant.getRealName() : null;
    this.applyTime = LocalDateTime.now();
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public SalesOrder getOrder() {
    return order;
}

public void setOrder(SalesOrder order) {
    this.order = order;
}

public String getChangeType() {
    return changeType;
}

public void setChangeType(String changeType) {
    this.changeType = changeType;
}

public String getChangeContent() {
    return changeContent;
}

public void setChangeContent(String changeContent) {
    this.changeContent = changeContent;
}

public String getChangeReason() {
    return changeReason;
}

public void setChangeReason(String changeReason) {
    this.changeReason = changeReason;
}

public String getChangeStatus() {
    return changeStatus;
}

public void setChangeStatus(String changeStatus) {
    this.changeStatus = changeStatus;
}

public User getApplicant() {
    return applicant;
}

public void setApplicant(User applicant) {
    this.applicant = applicant;
    this.applicantName = applicant != null ? applicant.getRealName() : null;
}

public String getApplicantName() {
    return applicantName;
}

public void setApplicantName(String applicantName) {
    this.applicantName = applicantName;
}

public LocalDateTime getApplyTime() {
    return applyTime;
}

public void setApplyTime(LocalDateTime applyTime) {
    this.applyTime = applyTime;
}

public User getReviewer() {
    return reviewer;
}

public void setReviewer(User reviewer) {
    this.reviewer = reviewer;
    this.reviewerName = reviewer != null ? reviewer.getRealName() : null;
}

public String getReviewerName() {
    return reviewerName;
}

public void setReviewerName(String reviewerName) {
    this.reviewerName = reviewerName;
}

public LocalDateTime getReviewTime() {
    return reviewTime;
}

public void setReviewTime(LocalDateTime reviewTime) {
    this.reviewTime = reviewTime;
}

public String getReviewComments() {
    return reviewComments;
}

public void setReviewComments(String reviewComments) {
    this.reviewComments = reviewComments;
}

// 审核通过方法
public void approve(User reviewer, String comments) {
    this.reviewer = reviewer;
    this.reviewerName = reviewer != null ? reviewer.getRealName() : null;
    this.changeStatus = "已通过";
    this.reviewComments = comments;
    this.reviewTime = LocalDateTime.now();
}

// 审核拒绝方法
public void reject(User reviewer, String comments) {
    this.reviewer = reviewer;
    this.reviewerName = reviewer != null ? reviewer.getRealName() : null;
    this.changeStatus = "已拒绝";
    this.reviewComments = comments;
    this.reviewTime = LocalDateTime.now();
}

@Override
public String toString() {
    return "OrderChange{" +
            "id=" + id +
            ", changeType='" + changeType + '\'' +
            ", changeStatus='" + changeStatus + '\'' +
            ", applicantName='" + applicantName + '\'' +
            ", applyTime=" + applyTime +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;

@Entity
@Table(name = "order_product")
public class OrderProduct {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "order_id", nullable = false)
private SalesOrder order;

@Column(name = "product_code", nullable = false, length = 50)
private String productCode;

@Column(name = "product_name", length = 100)
private String productName;

@Column(name = "product_model", length = 50)
private String productModel;

@Column(name = "unit", length = 20)
private String unit;

@Column(name = "quantity", nullable = false)
private Integer quantity;

@Column(name = "unit_price", precision = 10, scale = 2)
private BigDecimal unitPrice;

@Column(name = "total_price", precision = 10, scale = 2)
private BigDecimal totalPrice;

@Column(name = "remarks", length = 255)
private String remarks;

@Column(name = "production_status", length = 20)
private String productionStatus; // 未生产、生产中、已完成

// 默认构造函数
public OrderProduct() {
}

// 带基本参数的构造函数
public OrderProduct(SalesOrder order, String productCode, String productName, String productModel, String unit, Integer quantity) {
    this.order = order;
    this.productCode = productCode;
    this.productName = productName;
    this.productModel = productModel;
    this.unit = unit;
    this.quantity = quantity;
    this.productionStatus = "未生产";
}

// 带价格的构造函数
public OrderProduct(SalesOrder order, String productCode, String productName, String productModel, String unit, Integer quantity, BigDecimal unitPrice) {
    this(order, productCode, productName, productModel, unit, quantity);
    this.unitPrice = unitPrice;
    this.totalPrice = unitPrice != null && quantity != null ? unitPrice.multiply(new BigDecimal(quantity)) : null;
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public SalesOrder getOrder() {
    return order;
}

public void setOrder(SalesOrder order) {
    this.order = order;
}

public String getProductCode() {
    return productCode;
}

public void setProductCode(String productCode) {
    this.productCode = productCode;
}

public String getProductName() {
    return productName;
}

public void setProductName(String productName) {
    this.productName = productName;
}

public String getProductModel() {
    return productModel;
}

public void setProductModel(String productModel) {
    this.productModel = productModel;
}

public String getUnit() {
    return unit;
}

public void setUnit(String unit) {
    this.unit = unit;
}

public Integer getQuantity() {
    return quantity;
}

public void setQuantity(Integer quantity) {
    this.quantity = quantity;
    // 更新总价
    if (this.unitPrice != null && quantity != null) {
        this.totalPrice = this.unitPrice.multiply(new BigDecimal(quantity));
    }
}

public BigDecimal getUnitPrice() {
    return unitPrice;
}

public void setUnitPrice(BigDecimal unitPrice) {
    this.unitPrice = unitPrice;
    // 更新总价
    if (unitPrice != null && this.quantity != null) {
        this.totalPrice = unitPrice.multiply(new BigDecimal(this.quantity));
    }
}

public BigDecimal getTotalPrice() {
    return totalPrice;
}

public void setTotalPrice(BigDecimal totalPrice) {
    this.totalPrice = totalPrice;
}

public String getRemarks() {
    return remarks;
}

public void setRemarks(String remarks) {
    this.remarks = remarks;
}

public String getProductionStatus() {
    return productionStatus;
}

public void setProductionStatus(String productionStatus) {
    this.productionStatus = productionStatus;
}

@Override
public String toString() {
    return "OrderProduct{" +
            "id=" + id +
            ", productCode='" + productCode + '\'' +
            ", productName='" + productName + '\'' +
            ", productModel='" + productModel + '\'' +
            ", quantity=" + quantity +
            ", unitPrice=" + unitPrice +
            ", totalPrice=" + totalPrice +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.time.LocalDateTime;

@Entity
@Table(name = "order_review")
public class OrderReview {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "order_id", nullable = false)
private SalesOrder order;

@Column(name = "review_type", nullable = false, length = 20)
private String reviewType; // 销售审核、生产审核、财务审核

@Column(name = "review_status", nullable = false, length = 20)
private String reviewStatus; // 待审核、已通过、已拒绝

@Column(name = "review_comments", length = 500)
private String reviewComments;

@ManyToOne
@JoinColumn(name = "reviewer_id")
private User reviewer;

@Column(name = "reviewer_name", length = 50)
private String reviewerName;

@Column(name = "review_time")
private LocalDateTime reviewTime;

@Column(name = "create_time")
private LocalDateTime createTime;

// 默认构造函数
public OrderReview() {
}

// 带基本参数的构造函数
public OrderReview(SalesOrder order, String reviewType) {
    this.order = order;
    this.reviewType = reviewType;
    this.reviewStatus = "待审核";
    this.createTime = LocalDateTime.now();
}

// 带审核人的构造函数
public OrderReview(SalesOrder order, String reviewType, User reviewer) {
    this(order, reviewType);
    this.reviewer = reviewer;
    this.reviewerName = reviewer != null ? reviewer.getRealName() : null;
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public SalesOrder getOrder() {
    return order;
}

public void setOrder(SalesOrder order) {
    this.order = order;
}

public String getReviewType() {
    return reviewType;
}

public void setReviewType(String reviewType) {
    this.reviewType = reviewType;
}

public String getReviewStatus() {
    return reviewStatus;
}

public void setReviewStatus(String reviewStatus) {
    this.reviewStatus = reviewStatus;
}

public String getReviewComments() {
    return reviewComments;
}

public void setReviewComments(String reviewComments) {
    this.reviewComments = reviewComments;
}

public User getReviewer() {
    return reviewer;
}

public void setReviewer(User reviewer) {
    this.reviewer = reviewer;
    this.reviewerName = reviewer != null ? reviewer.getRealName() : null;
}

public String getReviewerName() {
    return reviewerName;
}

public void setReviewerName(String reviewerName) {
    this.reviewerName = reviewerName;
}

public LocalDateTime getReviewTime() {
    return reviewTime;
}

public void setReviewTime(LocalDateTime reviewTime) {
    this.reviewTime = reviewTime;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

// 审核通过方法
public void approve(User reviewer, String comments) {
    this.reviewer = reviewer;
    this.reviewerName = reviewer != null ? reviewer.getRealName() : null;
    this.reviewStatus = "已通过";
    this.reviewComments = comments;
    this.reviewTime = LocalDateTime.now();
}

// 审核拒绝方法
public void reject(User reviewer, String comments) {
    this.reviewer = reviewer;
    this.reviewerName = reviewer != null ? reviewer.getRealName() : null;
    this.reviewStatus = "已拒绝";
    this.reviewComments = comments;
    this.reviewTime = LocalDateTime.now();
}

@Override
public String toString() {
    return "OrderReview{" +
            "id=" + id +
            ", reviewType='" + reviewType + '\'' +
            ", reviewStatus='" + reviewStatus + '\'' +
            ", reviewerName='" + reviewerName + '\'' +
            ", reviewTime=" + reviewTime +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDateTime;

@Entity
@Table(name = "product")
public class Product {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "product_code", nullable = false, unique = true, length = 50)
private String productCode;

@Column(name = "product_name", nullable = false, length = 100)
private String productName;

@Column(name = "product_model", length = 50)
private String productModel;

@Column(name = "product_type", length = 50)
private String productType;

@Column(name = "product_category", length = 50)
private String productCategory;

@Column(name = "unit", length = 20)
private String unit;

@Column(name = "standard_price", precision = 10, scale = 2)
private BigDecimal standardPrice;

@Column(name = "cost_price", precision = 10, scale = 2)
private BigDecimal costPrice;

@Column(name = "inventory_quantity")
private Integer inventoryQuantity;

@Column(name = "min_inventory")
private Integer minInventory;

@Column(name = "max_inventory")
private Integer maxInventory;

@Column(name = "production_cycle")
private Integer productionCycle; // 生产周期(天)

@Column(name = "product_status", length = 20)
private String productStatus; // 正常、停产、缺货

@Column(name = "description", length = 500)
private String description;

@Column(name = "create_time")
private LocalDateTime createTime;

@Column(name = "update_time")
private LocalDateTime updateTime;

@Column(name = "created_by")
private Long createdBy;

@Column(name = "updated_by")
private Long updatedBy;

// 默认构造函数
public Product() {
}

// 带基本参数的构造函数
public Product(String productCode, String productName, String productModel, String unit) {
    this.productCode = productCode;
    this.productName = productName;
    this.productModel = productModel;
    this.unit = unit;
    this.inventoryQuantity = 0;
    this.productStatus = "正常";
    this.createTime = LocalDateTime.now();
    this.updateTime = LocalDateTime.now();
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getProductCode() {
    return productCode;
}

public void setProductCode(String productCode) {
    this.productCode = productCode;
}

public String getProductName() {
    return productName;
}

public void setProductName(String productName) {
    this.productName = productName;
}

public String getProductModel() {
    return productModel;
}

public void setProductModel(String productModel) {
    this.productModel = productModel;
}

public String getProductType() {
    return productType;
}

public void setProductType(String productType) {
    this.productType = productType;
}

public String getProductCategory() {
    return productCategory;
}

public void setProductCategory(String productCategory) {
    this.productCategory = productCategory;
}

public String getUnit() {
    return unit;
}

public void setUnit(String unit) {
    this.unit = unit;
}

public BigDecimal getStandardPrice() {
    return standardPrice;
}

public void setStandardPrice(BigDecimal standardPrice) {
    this.standardPrice = standardPrice;
}

public BigDecimal getCostPrice() {
    return costPrice;
}

public void setCostPrice(BigDecimal costPrice) {
    this.costPrice = costPrice;
}

public Integer getInventoryQuantity() {
    return inventoryQuantity;
}

public void setInventoryQuantity(Integer inventoryQuantity) {
    this.inventoryQuantity = inventoryQuantity;
}

public Integer getMinInventory() {
    return minInventory;
}

public void setMinInventory(Integer minInventory) {
    this.minInventory = minInventory;
}

public Integer getMaxInventory() {
    return maxInventory;
}

public void setMaxInventory(Integer maxInventory) {
    this.maxInventory = maxInventory;
}

public Integer getProductionCycle() {
    return productionCycle;
}

public void setProductionCycle(Integer productionCycle) {
    this.productionCycle = productionCycle;
}

public String getProductStatus() {
    return productStatus;
}

public void setProductStatus(String productStatus) {
    this.productStatus = productStatus;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

public LocalDateTime getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(LocalDateTime updateTime) {
    this.updateTime = updateTime;
}

public Long getCreatedBy() {
    return createdBy;
}

public void setCreatedBy(Long createdBy) {
    this.createdBy = createdBy;
}

public Long getUpdatedBy() {
    return updatedBy;
}

public void setUpdatedBy(Long updatedBy) {
    this.updatedBy = updatedBy;
}

@Override
public String toString() {
    return "Product{" +
            "id=" + id +
            ", productCode='" + productCode + '\'' +
            ", productName='" + productName + '\'' +
            ", productModel='" + productModel + '\'' +
            ", inventoryQuantity=" + inventoryQuantity +
            ", productStatus='" + productStatus + '\'' +
            '}';
}

}package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;

@Entity
@Table(name = "product_cycle")
public class ProductCycle {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne
@JoinColumn(name = "product_id")
private Product product;

@Column(name = "product_code", nullable = false, length = 50)
private String productCode;

@Column(name = "product_name", length = 100)
private String productName;

@Column(name = "product_type", length = 50)
private String productType; // 产品类型:A、B、C等

@Column(name = "design_cycle")
private Integer designCycle; // 设计周期(天)

@Column(name = "material_preparation_cycle")
private Integer materialPreparationCycle; // 原材料准备周期(天)

@Column(name = "production_cycle")
private Integer productionCycle; // 生产周期(天)

@Column(name = "quality_inspection_cycle")
private Integer qualityInspectionCycle; // 质量检验周期(天)

@Column(name = "packaging_cycle")
private Integer packagingCycle; // 包装周期(天)

@Column(name = "total_cycle")
private Integer totalCycle; // 总周期(天)

// 默认构造函数
public ProductCycle() {
}

// 带基本参数的构造函数
public ProductCycle(Product product, String productType) {
    this.product = product;
    if (product != null) {
        this.productCode = product.getProductCode();
        this.productName = product.getProductName();
    }
    this.productType = productType;
}

// 带完整周期参数的构造函数
public ProductCycle(Product product, String productType, Integer designCycle, Integer materialPreparationCycle, 
                    Integer productionCycle, Integer qualityInspectionCycle, Integer packagingCycle) {
    this(product, productType);
    this.designCycle = designCycle;
    this.materialPreparationCycle = materialPreparationCycle;
    this.productionCycle = productionCycle;
    this.qualityInspectionCycle = qualityInspectionCycle;
    this.packagingCycle = packagingCycle;
    calculateTotalCycle();
}

// 计算总周期
private void calculateTotalCycle() {
    this.totalCycle = (this.designCycle != null ? this.designCycle : 0) +
                     (this.materialPreparationCycle != null ? this.materialPreparationCycle : 0) +
                     (this.productionCycle != null ? this.productionCycle : 0) +
                     (this.qualityInspectionCycle != null ? this.qualityInspectionCycle : 0) +
                     (this.packagingCycle != null ? this.packagingCycle : 0);
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public Product getProduct() {
    return product;
}

public void setProduct(Product product) {
    this.product = product;
    if (product != null) {
        this.productCode = product.getProductCode();
        this.productName = product.getProductName();
    }
}

public String getProductCode() {
    return productCode;
}

public void setProductCode(String productCode) {
    this.productCode = productCode;
}

public String getProductName() {
    return productName;
}

public void setProductName(String productName) {
    this.productName = productName;
}

public String getProductType() {
    return productType;
}

public void setProductType(String productType) {
    this.productType = productType;
}

public Integer getDesignCycle() {
    return designCycle;
}

public void setDesignCycle(Integer designCycle) {
    this.designCycle = designCycle;
    calculateTotalCycle();
}

public Integer getMaterialPreparationCycle() {
    return materialPreparationCycle;
}

public void setMaterialPreparationCycle(Integer materialPreparationCycle) {
    this.materialPreparationCycle = materialPreparationCycle;
    calculateTotalCycle();
}

public Integer getProductionCycle() {
    return productionCycle;
}

public void setProductionCycle(Integer productionCycle) {
    this.productionCycle = productionCycle;
    calculateTotalCycle();
}

public Integer getQualityInspectionCycle() {
    return qualityInspectionCycle;
}

public void setQualityInspectionCycle(Integer qualityInspectionCycle) {
    this.qualityInspectionCycle = qualityInspectionCycle;
    calculateTotalCycle();
}

public Integer getPackagingCycle() {
    return packagingCycle;
}

public void setPackagingCycle(Integer packagingCycle) {
    this.packagingCycle = packagingCycle;
    calculateTotalCycle();
}

public Integer getTotalCycle() {
    return totalCycle;
}

public void setTotalCycle(Integer totalCycle) {
    this.totalCycle = totalCycle;
}

@Override
public String toString() {
    return "ProductCycle{" +
            "id=" + id +
            ", productCode='" + productCode + '\'' +
            ", productName='" + productName + '\'' +
            ", productType='" + productType + '\'' +
            ", totalCycle=" + totalCycle +
            '}';
}

}/*

  • Copyright (c) 2008, 2020 Oracle and/or its affiliates. All rights reserved.
  • This program and the accompanying materials are made available under the
  • terms of the Eclipse Public License v. 2.0 which is available at
  • http://www.eclipse.org/legal/epl-2.0,
  • or the Eclipse Distribution License v. 1.0 which is available at
  • http://www.eclipse.org/org/documents/edl-v10.php.
  • SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
    */

// Contributors:
// Linda DeMichiel - 2.1
// Linda DeMichiel - 2.0

package jakarta.persistence;

import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**

  • Specifies the mapped column for a persistent property or field.

  • If no Column annotation is specified, the default values apply.

  • Example 1:

  • @Column(name="DESC", nullable=false, length=512)

  • public String getDescription()

  • Example 2:

  • @Column(name="DESC",

  •        columnDefinition="CLOB NOT NULL",
    
  •        table="EMP_DETAIL")
    
  • @Lob

  • public String getDescription()

  • Example 3:

  • @Column(name="ORDER_COST", updatable=false, precision=12, scale=2)

  • public BigDecimal getCost()

  • @since 1.0
    */
    @Target({METHOD, FIELD})
    @Retention(RUNTIME)
    public @interface Column {

    /**

    • (Optional) The name of the column. Defaults to
    • the property or field name.
      */
      String name() default "";

    /**

    • (Optional) Whether the column is a unique key. This is a
    • shortcut for the UniqueConstraint annotation at the table
    • level and is useful for when the unique key constraint
    • corresponds to only a single column. This constraint applies
    • in addition to any constraint entailed by primary key mapping and
    • to constraints specified at the table level.
      */
      boolean unique() default false;

    /**

    • (Optional) Whether the database column is nullable.
      */
      boolean nullable() default true;

    /**

    • (Optional) Whether the column is included in SQL INSERT
    • statements generated by the persistence provider.
      */
      boolean insertable() default true;

    /**

    • (Optional) Whether the column is included in SQL UPDATE
    • statements generated by the persistence provider.
      */
      boolean updatable() default true;

    /**

    • (Optional) The SQL fragment that is used when
    • generating the DDL for the column.
    • Defaults to the generated SQL to create a

    • column of the inferred type.
      */
      String columnDefinition() default "";

    /**

    • (Optional) The name of the table that contains the column.
    • If absent the column is assumed to be in the primary table.
      */
      String table() default "";

    /**

    • (Optional) The column length. (Applies only if a
    • string-valued column is used.)
      */
      int length() default 255;

    /**

    • (Optional) The precision for a decimal (exact numeric)
    • column. (Applies only if a decimal column is used.)
    • Value must be set by developer if used when generating
    • the DDL for the column.
      */
      int precision() default 0;

    /**

    • (Optional) The scale for a decimal (exact numeric) column.
    • (Applies only if a decimal column is used.)
      */
      int scale() default 0;
      }
      package com.example.test.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.time.LocalDateTime;

@Entity
@Table(name = "user")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, length = 50, unique = true)
private String username;

@Column(nullable = false, length = 100)
private String password;

@Column(name = "real_name", length = 50)
private String realName;

@Column(length = 100)
private String email;

@Column(length = 20)
private String phone;

@Column(length = 50)
private String department;

@Column(length = 50)
private String position;

@Column(columnDefinition = "tinyint(1) default 1")
private Boolean status;

@Column(name = "create_time")
private LocalDateTime createTime;

@Column(name = "update_time")
private LocalDateTime updateTime;

@Column(name = "last_login_time")
private LocalDateTime lastLoginTime;

@Column(length = 20, columnDefinition = "varchar(20) default 'USER'")
private String role;

// 默认构造函数
public User() {
    this.role = "USER";
}

// 带参数的构造函数
public User(String username, String password) {
    this.username = username;
    this.password = password;
    this.status = true;
    this.createTime = LocalDateTime.now();
    this.updateTime = LocalDateTime.now();
    this.role = "USER";
}

// 完整参数的构造函数
public User(String username, String password, String realName, String email, String phone, 
            String department, String position, Boolean status, 
            LocalDateTime createTime, LocalDateTime updateTime, LocalDateTime lastLoginTime) {
    this.username = username;
    this.password = password;
    this.realName = realName;
    this.email = email;
    this.phone = phone;
    this.department = department;
    this.position = position;
    this.status = status;
    this.createTime = createTime;
    this.updateTime = updateTime;
    this.lastLoginTime = lastLoginTime;
    this.role = "USER";
}

// 完整参数的构造函数(包含角色)
public User(String username, String password, String realName, String email, String phone, 
            String department, String position, Boolean status, 
            LocalDateTime createTime, LocalDateTime updateTime, LocalDateTime lastLoginTime,
            String role) {
    this.username = username;
    this.password = password;
    this.realName = realName;
    this.email = email;
    this.phone = phone;
    this.department = department;
    this.position = position;
    this.status = status;
    this.createTime = createTime;
    this.updateTime = updateTime;
    this.lastLoginTime = lastLoginTime;
    this.role = role;
}

// Getters and Setters
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public String getRealName() {
    return realName;
}

public void setRealName(String realName) {
    this.realName = realName;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getPhone() {
    return phone;
}

public void setPhone(String phone) {
    this.phone = phone;
}

public String getDepartment() {
    return department;
}

public void setDepartment(String department) {
    this.department = department;
}

public String getPosition() {
    return position;
}

public void setPosition(String position) {
    this.position = position;
}

public Boolean getStatus() {
    return status;
}

public void setStatus(Boolean status) {
    this.status = status;
}

public LocalDateTime getCreateTime() {
    return createTime;
}

public void setCreateTime(LocalDateTime createTime) {
    this.createTime = createTime;
}

public LocalDateTime getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(LocalDateTime updateTime) {
    this.updateTime = updateTime;
}

public LocalDateTime getLastLoginTime() {
    return lastLoginTime;
}

public void setLastLoginTime(LocalDateTime lastLoginTime) {
    this.lastLoginTime = lastLoginTime;
}

public String getRole() {
    return role;
}

public void setRole(String role) {
    this.role = role;
}

// 判断是否为管理员
public boolean isAdmin() {
    return "ADMIN".equals(this.role);
}

@Override
public String toString() {
    return "User{" +
            "id=" + id +
            ", username='" + username + '\'' +
            ", password='" + password + '\'' +
            ", realName='" + realName + '\'' +
            ", email='" + email + '\'' +
            ", phone='" + phone + '\'' +
            ", department='" + department + '\'' +
            ", position='" + position + '\'' +
            ", status=" + status +
            ", createTime=" + createTime +
            ", updateTime=" + updateTime +
            ", lastLoginTime=" + lastLoginTime +
            ", role='" + role + '\'' +
            '}';
}

}package com.example.test.repository;

import com.example.test.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
// 可以添加自定义查询方法
}package com.example.test.repository;

import com.example.test.entity.SalesOrder;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface SalesOrderRepository extends JpaRepository<SalesOrder, Long> {
// 可以添加自定义查询方法
}package com.example.test.repository;

import com.example.test.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 根据用户名查找用户
User findByUsername(String username);

// 根据邮箱查找用户
User findByEmail(String email);

// 根据电话查找用户
User findByPhone(String phone);

// 根据部门查找用户列表
List<User> findByDepartment(String department);

// 根据职位查找用户列表
List<User> findByPosition(String position);

// 根据状态查找用户列表
List<User> findByStatus(Boolean status);

// 根据真实姓名模糊查询
List<User> findByRealNameContaining(String realName);

// 查找指定时间之后创建的用户
List<User> findByCreateTimeAfter(LocalDateTime createTime);

// 查找指定时间之后登录的用户
List<User> findByLastLoginTimeAfter(LocalDateTime lastLoginTime);

// 自定义查询 - 根据部门和职位查找用户
@Query("SELECT u FROM User u WHERE u.department = :department AND u.position = :position")
List<User> findByDepartmentAndPosition(@Param("department") String department, @Param("position") String position);

// 根据角色查找用户列表
List<User> findByRole(String role);

// 查找所有管理员
@Query("SELECT u FROM User u WHERE u.role = 'ADMIN'")
List<User> findAllAdmins();

}package com.example.test.service;

import com.example.test.entity.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;

import java.util.List;

/**

  • 管理员服务类,提供对所有实体的通用操作
    */
    @Service
    public class AdminService {

    @PersistenceContext
    private EntityManager entityManager;

    /**

    • 获取所有实体记录
      */
      public List findAll(Class entityClass) {
      return entityManager.createQuery("FROM " + entityClass.getSimpleName(), entityClass).getResultList();
      }

    /**

    • 根据ID查找实体
      */
      public T findById(Class entityClass, Long id) {
      return entityManager.find(entityClass, id);
      }

    /**

    • 保存实体
      */
      @Transactional
      public T save(T entity) {
      if (entity == null) {
      return null;
      }
      return entityManager.merge(entity);
      }

    /**

    • 删除实体
      */
      @Transactional
      public void delete(Class entityClass, Long id) {
      T entity = findById(entityClass, id);
      if (entity != null) {
      entityManager.remove(entity);
      }
      }

    /**

    • 执行自定义查询
      */
      public List executeQuery(String jpql, Class resultClass) {
      return entityManager.createQuery(jpql, resultClass).getResultList();
      }

    /**

    • 执行自定义更新操作
      */
      @Transactional
      public int executeUpdate(String jpql) {
      Query query = entityManager.createQuery(jpql);
      return query.executeUpdate();
      }

    /**

    • 根据实体名称获取对应的类
      */
      public Class<?> getEntityClassByName(String entityName) {
      try {
      switch (entityName.toLowerCase()) {
      case "user":
      return User.class;
      case "salesorder":
      return SalesOrder.class;
      case "orderproduct":
      return OrderProduct.class;
      case "missingproduct":
      return MissingProduct.class;
      case "product":
      return Product.class;
      case "productcycle":
      return ProductCycle.class;
      case "orderreview":
      return OrderReview.class;
      case "orderchange":
      return OrderChange.class;
      case "forecastplan":
      return ForecastPlan.class;
      case "deliveryorder":
      return DeliveryOrder.class;
      case "contactform":
      return ContactForm.class;
      case "deliverystatistics":
      return DeliveryStatistics.class;
      default:
      return null;
      }
      } catch (Exception e) {
      return null;
      }
      }
      }package com.example.test.service;

import com.example.test.entity.User;
import com.example.test.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
public class UserService {

private final UserRepository userRepository;

@Autowired
public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
}

// 创建用户
@Transactional
public User createUser(User user) {
    // 设置默认值
    if (user.getStatus() == null) {
        user.setStatus(true);
    }
    if (user.getCreateTime() == null) {
        user.setCreateTime(LocalDateTime.now());
    }
    if (user.getUpdateTime() == null) {
        user.setUpdateTime(LocalDateTime.now());
    }
    if (user.getRole() == null) {
        user.setRole("USER");
    }
    return userRepository.save(user);
}

// 创建管理员
@Transactional
public User createAdmin(User user) {
    user.setRole("ADMIN");
    return createUser(user);
}

// 更新用户
@Transactional
public User updateUser(User user) {
    user.setUpdateTime(LocalDateTime.now());
    return userRepository.save(user);
}

// 保存用户(创建或更新)
@Transactional
public User saveUser(User user) {
    if (user.getId() == null) {
        return createUser(user);
    } else {
        return updateUser(user);
    }
}

// 根据ID查找用户
public Optional<User> findUserById(Long id) {
    return userRepository.findById(id);
}

// 查找所有用户
public List<User> findAllUsers() {
    return userRepository.findAll();
}

// 根据用户名查找用户
public User findUserByUsername(String username) {
    return userRepository.findByUsername(username);
}

// 根据邮箱查找用户
public User findUserByEmail(String email) {
    return userRepository.findByEmail(email);
}

// 根据电话查找用户
public User findUserByPhone(String phone) {
    return userRepository.findByPhone(phone);
}

// 根据部门查找用户列表
public List<User> findUsersByDepartment(String department) {
    return userRepository.findByDepartment(department);
}

// 根据职位查找用户列表
public List<User> findUsersByPosition(String position) {
    return userRepository.findByPosition(position);
}

// 根据部门和职位查找用户列表
public List<User> findUsersByDepartmentAndPosition(String department, String position) {
    return userRepository.findByDepartmentAndPosition(department, position);
}

// 根据状态查找用户列表
public List<User> findUsersByStatus(Boolean status) {
    return userRepository.findByStatus(status);
}

// 根据角色查找用户列表
public List<User> findUsersByRole(String role) {
    return userRepository.findByRole(role);
}

// 查找所有管理员
public List<User> findAllAdmins() {
    return userRepository.findAllAdmins();
}

// 根据真实姓名模糊查询
public List<User> findUsersByRealNameContaining(String realName) {
    return userRepository.findByRealNameContaining(realName);
}

// 查找指定时间之后创建的用户
public List<User> findUsersByCreateTimeAfter(LocalDateTime createTime) {
    return userRepository.findByCreateTimeAfter(createTime);
}

// 查找指定时间之后登录的用户
public List<User> findUsersByLastLoginTimeAfter(LocalDateTime lastLoginTime) {
    return userRepository.findByLastLoginTimeAfter(lastLoginTime);
}

// 用户登录
@Transactional
public User login(String username, String password) {
    User user = userRepository.findByUsername(username);
    if (user != null && password.equals(user.getPassword())) {
        // 更新最后登录时间
        user.setLastLoginTime(LocalDateTime.now());
        return userRepository.save(user);
    }
    return null;
}

// 启用用户
@Transactional
public User enableUser(Long id) {
    Optional<User> optionalUser = userRepository.findById(id);
    if (optionalUser.isPresent()) {
        User user = optionalUser.get();
        user.setStatus(true);
        user.setUpdateTime(LocalDateTime.now());
        return userRepository.save(user);
    }
    return null;
}

// 禁用用户
@Transactional
public User disableUser(Long id) {
    Optional<User> optionalUser = userRepository.findById(id);
    if (optionalUser.isPresent()) {
        User user = optionalUser.get();
        user.setStatus(false);
        user.setUpdateTime(LocalDateTime.now());
        return userRepository.save(user);
    }
    return null;
}

// 设置用户为管理员
@Transactional
public User setUserAsAdmin(Long id) {
    Optional<User> optionalUser = userRepository.findById(id);
    if (optionalUser.isPresent()) {
        User user = optionalUser.get();
        user.setRole("ADMIN");
        user.setUpdateTime(LocalDateTime.now());
        return userRepository.save(user);
    }
    return null;
}

// 取消用户的管理员权限
@Transactional
public User removeAdminRole(Long id) {
    Optional<User> optionalUser = userRepository.findById(id);
    if (optionalUser.isPresent()) {
        User user = optionalUser.get();
        user.setRole("USER");
        user.setUpdateTime(LocalDateTime.now());
        return userRepository.save(user);
    }
    return null;
}

// 删除用户
@Transactional
public void deleteUser(Long id) {
    userRepository.deleteById(id);
}

}
package com.example.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TestApplication {

public static void main(String[] args) {
    SpringApplication.run(TestApplication.class, args);
}

}

管理员仪表盘
<div class="container-fluid">
    <div class="row">
        <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block sidebar collapse">
            <div class="position-sticky pt-3 sidebar-sticky">
                <ul class="nav flex-column">
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="/admin/dashboard">
                            <span data-feather="home"></span>
                            仪表盘
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="/admin/users">
                            <span data-feather="users"></span>
                            用户管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('salesorder')">
                            <span data-feather="file"></span>
                            销售订单管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('product')">
                            <span data-feather="shopping-cart"></span>
                            产品管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('productcycle')">
                            <span data-feather="clock"></span>
                            产品周期管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('orderreview')">
                            <span data-feather="check-square"></span>
                            订单审核管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('orderchange')">
                            <span data-feather="edit"></span>
                            订单变更管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('forecastplan')">
                            <span data-feather="trending-up"></span>
                            预测计划管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('deliveryorder')">
                            <span data-feather="truck"></span>
                            发货单管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('contactform')">
                            <span data-feather="mail"></span>
                            联系单管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('deliverystatistics')">
                            <span data-feather="bar-chart-2"></span>
                            发货统计管理
                        </a>
                    </li>
                </ul>
            </div>
        </nav>

        <main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
            <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
                <h1 class="h2">管理员仪表盘</h1>
                <div class="btn-toolbar mb-2 mb-md-0">
                    <div class="btn-group me-2">
                        <button type="button" class="btn btn-sm btn-outline-secondary" id="refreshBtn">刷新</button>
                        <button type="button" class="btn btn-sm btn-outline-primary" id="addBtn" style="display:none;">添加</button>
                    </div>
                </div>
            </div>

            <div class="row mb-4">
                <div class="col-md-3 mb-4">
                    <div class="card text-white bg-primary">
                        <div class="card-body">
                            <h5 class="card-title">用户总数</h5>
                            <p class="card-text" id="userCount">加载中...</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3 mb-4">
                    <div class="card text-white bg-success">
                        <div class="card-body">
                            <h5 class="card-title">订单总数</h5>
                            <p class="card-text" id="orderCount">加载中...</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3 mb-4">
                    <div class="card text-white bg-info">
                        <div class="card-body">
                            <h5 class="card-title">产品总数</h5>
                            <p class="card-text" id="productCount">加载中...</p>
                        </div>
                    </div>
                </div>
                <div class="col-md-3 mb-4">
                    <div class="card text-white bg-warning">
                        <div class="card-body">
                            <h5 class="card-title">待审核订单</h5>
                            <p class="card-text" id="pendingReviewCount">加载中...</p>
                        </div>
                    </div>
                </div>
            </div>

            <div id="entityTableContainer" style="display:none;">
                <h2 id="entityTitle"></h2>
                <div class="table-responsive">
                    <table class="table table-striped table-sm" id="entityTable">
                        <thead>
                            <tr id="tableHeader">
                                <!-- 表头将动态生成 -->
                            </tr>
                        </thead>
                        <tbody id="tableBody">
                            <!-- 表内容将动态生成 -->
                        </tbody>
                    </table>
                </div>
            </div>

            <div id="welcomeMessage">
                <div class="jumbotron">
                    <h1 class="display-4">欢迎,<span th:text="${currentUser.realName}">管理员</span>!</h1>
                    <p class="lead">这是销售订单管理系统的管理员控制面板。您可以在这里管理系统中的所有数据。</p>
                    <hr class="my-4">
                    <p>请从左侧菜单选择要管理的数据类型。</p>
                </div>
            </div>

            <!-- 添加/编辑实体的模态框 -->
            <div class="modal fade" id="entityModal" tabindex="-1" aria-labelledby="entityModalLabel" aria-hidden="true">
                <div class="modal-dialog modal-lg">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title" id="entityModalLabel">添加/编辑</h5>
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                        </div>
                        <div class="modal-body">
                            <form id="entityForm">
                                <!-- 表单内容将动态生成 -->
                            </form>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                            <button type="button" class="btn btn-primary" id="saveEntityBtn">保存</button>
                        </div>
                    </div>
                </div>
            </div>
        </main>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js"></script>
<script>
    // 初始化Feather图标
    document.addEventListener('DOMContentLoaded', function() {
        feather.replace();
        loadDashboardData();
    });

    // 添加一个获取认证令牌的函数
    function getAuthToken() {
        // 从localStorage或sessionStorage获取令牌
        return localStorage.getItem('authToken') || sessionStorage.getItem('authToken');
    }
    
    // 创建一个通用的fetch函数,自动添加认证头
    function authenticatedFetch(url, options = {}) {
        const token = getAuthToken();
        const headers = {
            'Content-Type': 'application/json',
            'Authorization': token ? `Bearer ${token}` : ''
        };
        
        return fetch(url, {
            ...options,
            headers: {
                ...headers,
                ...(options.headers || {})
            }
        });
    }
    
    // 修改loadDashboardData函数
    function loadDashboardData() {
        // 获取用户总数
        authenticatedFetch('/api/admin/user')
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP错误 ${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                document.getElementById('userCount').textContent = data.length;
            })
            .catch(error => {
                document.getElementById('userCount').textContent = '获取失败';
                console.error('获取用户数据失败:', error);
            });
    
        // 其他fetch调用也需要类似修改
        // 获取订单总数
        fetch('/api/admin/salesorder')
            .then(response => response.json())
            .then(data => {
                document.getElementById('orderCount').textContent = data.length;
            })
            .catch(error => {
                document.getElementById('orderCount').textContent = '获取失败';
                console.error('获取订单数据失败:', error);
            });

        // 获取产品总数
        fetch('/api/admin/product')
            .then(response => response.json())
            .then(data => {
                document.getElementById('productCount').textContent = data.length;
            })
            .catch(error => {
                document.getElementById('productCount').textContent = '获取失败';
                console.error('获取产品数据失败:', error);
            });

        // 获取待审核订单数
        fetch('/api/admin/orderreview')
            .then(response => response.json())
            .then(data => {
                const pendingReviews = data.filter(review => review.status === 'PENDING');
                document.getElementById('pendingReviewCount').textContent = pendingReviews.length;
            })
            .catch(error => {
                document.getElementById('pendingReviewCount').textContent = '获取失败';
                console.error('获取审核数据失败:', error);
            });
    }

    // 当前实体类型
    let currentEntityType = '';

    // 加载实体数据
    function loadEntityData(entityType) {
        currentEntityType = entityType;
        document.getElementById('welcomeMessage').style.display = 'none';
        document.getElementById('entityTableContainer').style.display = 'block';
        
        // 确保addBtn元素存在并设置其样式
        const addBtn = document.getElementById('addBtn');
        if (addBtn) {
            addBtn.style.display = 'block';
            console.log('设置addBtn显示');
        } else {
            console.error('未找到addBtn元素');
        }
        
        // 设置实体标题
        const entityTitles = {
            'user': '用户管理',
            'salesorder': '销售订单管理',
            'orderproduct': '订单产品管理',
            'missingproduct': '缺货产品管理',
            'product': '产品管理',
            'productcycle': '产品周期管理',
            'orderreview': '订单审核管理',
            'orderchange': '订单变更管理',
            'forecastplan': '预测计划管理',
            'deliveryorder': '发货单管理',
            'contactform': '联系单管理',
            'deliverystatistics': '发货统计管理'
        };
        document.getElementById('entityTitle').textContent = entityTitles[entityType] || entityType;

        // 获取实体数据
        authenticatedFetch(`/api/admin/${entityType}`)
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP错误 ${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                renderEntityTable(data, entityType);
            })
            .catch(error => {
                console.error(`获取${entityType}数据失败:`, error);
                alert(`获取数据失败: ${error.message}`);
            });
    }

    // 渲染实体表格
    function renderEntityTable(data, entityType) {
        const tableHeader = document.getElementById('tableHeader');
        const tableBody = document.getElementById('tableBody');
        
        // 清空表头和表内容
        tableHeader.innerHTML = '';
        tableBody.innerHTML = '';
        
        // 如果没有数据,显示提示信息
        if (!data || data.length === 0) {
            tableBody.innerHTML = `<tr><td colspan="3">暂无${entityType}数据</td></tr>`;
            return;
        }
        
        // 获取第一条数据的所有属性作为表头
        const firstItem = data[0];
        const headers = Object.keys(firstItem);
        
        // 添加ID列
        const idCell = document.createElement('th');
        idCell.textContent = 'ID';
        tableHeader.appendChild(idCell);
        
        // 添加其他属性列(最多显示5个关键属性)
        const keyProperties = getKeyProperties(entityType, headers);
        keyProperties.forEach(prop => {
            const headerCell = document.createElement('th');
            headerCell.textContent = getPropertyDisplayName(prop);
            tableHeader.appendChild(headerCell);
        });
        
        // 添加操作列
        const actionCell = document.createElement('th');
        actionCell.textContent = '操作';
        tableHeader.appendChild(actionCell);
        
        // 添加表内容
        data.forEach(item => {
            const row = document.createElement('tr');
            
            // 添加ID列
            const idCell = document.createElement('td');
            idCell.textContent = item.id;
            row.appendChild(idCell);
            
            // 添加其他属性列
            keyProperties.forEach(prop => {
                const cell = document.createElement('td');
                cell.textContent = formatPropertyValue(item[prop]);
                row.appendChild(cell);
            });
            
            // 添加操作列
            const actionCell = document.createElement('td');
            actionCell.innerHTML = `
                <button class="btn btn-sm btn-outline-primary me-1" onclick="editEntity('${entityType}', ${item.id})">编辑</button>
                <button class="btn btn-sm btn-outline-danger" onclick="deleteEntity('${entityType}', ${item.id})">删除</button>
            `;
            row.appendChild(actionCell);
            
            tableBody.appendChild(row);
        });
    }

    // 获取实体的关键属性(最多5个)
    function getKeyProperties(entityType, allProperties) {
        // 排除id和一些不重要的属性
        const excludeProps = ['id', 'createTime', 'updateTime', 'lastLoginTime'];
        const filteredProps = allProperties.filter(prop => !excludeProps.includes(prop));
        
        // 根据实体类型返回特定的关键属性
        switch(entityType) {
            case 'user':
                return ['username', 'realName', 'department', 'position', 'role'];
            case 'salesorder':
                return ['orderNumber', 'customerName', 'orderDate', 'deliveryDate', 'status'];
            case 'product':
                return ['productCode', 'productName', 'specification', 'unit', 'price'];
            default:
                // 如果没有特定配置,返回前5个属性
                return filteredProps.slice(0, 5);
        }
    }

    // 获取属性的显示名称
    function getPropertyDisplayName(propertyName) {
        const displayNames = {
            'username': '用户名',
            'realName': '姓名',
            'department': '部门',
            'position': '职位',
            'role': '角色',
            'orderNumber': '订单编号',
            'customerName': '客户名称',
            'orderDate': '订单日期',
            'deliveryDate': '交付日期',
            'status': '状态',
            'productCode': '产品编码',
            'productName': '产品名称',
            'specification': '规格',
            'unit': '单位',
            'price': '价格'
        };
        return displayNames[propertyName] || propertyName;
    }

    // 格式化属性值
    function formatPropertyValue(value) {
        if (value === null || value === undefined) {
            return '';
        }
        if (value instanceof Date || (typeof value === 'string' && value.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/))) {
            const date = new Date(value);
            return date.toLocaleString();
        }
        if (typeof value === 'object') {
            return JSON.stringify(value);
        }
        return value.toString();
    }

    // 编辑实体
    function editEntity(entityType, id) {
        // 获取实体数据
        authenticatedFetch(`/api/admin/${entityType}/${id}`)
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP错误 ${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                showEntityModal(entityType, data);
            })
            .catch(error => {
                console.error(`获取${entityType}数据失败:`, error);
                alert(`获取数据失败: ${error.message}`);
            });
    }

    // 删除实体
    function deleteEntity(entityType, id) {
        if (confirm(`确定要删除ID为${id}的${entityType}记录吗?`)) {
            authenticatedFetch(`/api/admin/${entityType}/${id}`, {
                method: 'DELETE'
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`HTTP错误 ${response.status}`);
                }
                return response.json();
            })
            .then(data => {
                alert(data.message || '删除成功');
                loadEntityData(entityType);
            })
            .catch(error => {
                console.error(`删除${entityType}数据失败:`, error);
                alert(`删除失败: ${error.message}`);
            });
        }
    }

    // 显示实体模态框
    function showEntityModal(entityType, data = null) {
        const modal = new bootstrap.Modal(document.getElementById('entityModal'));
        const form = document.getElementById('entityForm');
        const modalTitle = document.getElementById('entityModalLabel');
        
        // 设置模态框标题
        modalTitle.textContent = data ? `编辑${entityType}` : `添加${entityType}`;
        
        // 清空表单
        form.innerHTML = '';
        
        // 如果是编辑模式,添加隐藏的ID字段
        if (data) {
            const idField = document.createElement('input');
            idField.type = 'hidden';
            idField.name = 'id';
            idField.value = data.id;
            form.appendChild(idField);
        }
        
        // 根据实体类型创建表单字段
        if (data) {
            // 编辑模式:使用现有数据的所有字段
            Object.keys(data).forEach(key => {
                // 排除id字段(已经作为隐藏字段添加)
                if (key !== 'id') {
                    createFormField(form, key, data[key]);
                }
            });
        } else {
            // 添加模式:根据实体类型创建必要的字段
            const requiredFields = getRequiredFields(entityType);
            requiredFields.forEach(field => {
                createFormField(form, field.name, field.defaultValue);
            });
        }
        
        // 设置保存按钮的点击事件
        document.getElementById('saveEntityBtn').onclick = function() {
            saveEntity(entityType, data ? data.id : null);
        };
        
        // 显示模态框
        modal.show();
    }

    // 创建表单字段
    function createFormField(form, fieldName, fieldValue) {
        const formGroup = document.createElement('div');
        formGroup.className = 'mb-3';
        
        const label = document.createElement('label');
        label.htmlFor = fieldName;
        label.className = 'form-label';
        label.textContent = getPropertyDisplayName(fieldName);
        
        let input;
        
        // 根据字段类型创建不同的输入控件
        if (fieldName.toLowerCase().includes('date') || fieldName.toLowerCase().includes('time')) {
            // 日期时间字段
            input = document.createElement('input');
            input.type = 'datetime-local';
            if (fieldValue) {
                const date = new Date(fieldValue);
                input.value = date.toISOString().slice(0, 16);
            }
        } else if (typeof fieldValue === 'boolean') {
            // 布尔字段
            input = document.createElement('select');
            const trueOption = document.createElement('option');
            trueOption.value = 'true';
            trueOption.textContent = '是';
            const falseOption = document.createElement('option');
            falseOption.value = 'false';
            falseOption.textContent = '否';
            input.appendChild(trueOption);
            input.appendChild(falseOption);
            input.value = fieldValue.toString();
        } else if (fieldName === 'status' && typeof fieldValue === 'string') {
            // 状态字段
            input = document.createElement('select');
            const statuses = ['PENDING', 'APPROVED', 'REJECTED', 'COMPLETED', 'CANCELLED'];
            statuses.forEach(status => {
                const option = document.createElement('option');
                option.value = status;
                option.textContent = status;
                input.appendChild(option);
            });
            input.value = fieldValue;
        } else if (fieldName === 'role') {
            // 角色字段
            input = document.createElement('select');
            const roles = ['USER', 'ADMIN'];
            roles.forEach(role => {
                const option = document.createElement('option');
                option.value = role;
                option.textContent = role;
                input.appendChild(option);
            });
            input.value = fieldValue || 'USER';
        } else if (typeof fieldValue === 'number') {
            // 数字字段
            input = document.createElement('input');
            input.type = 'number';
            input.step = '0.01';
            input.value = fieldValue;
        } else if (typeof fieldValue === 'object' && fieldValue !== null) {
            // 对象字段(如外键关联)
            input = document.createElement('input');
            input.type = 'text';
            input.value = JSON.stringify(fieldValue);
        } else {
            // 文本字段
            input = document.createElement('input');
            input.type = 'text';
            input.value = fieldValue || '';
        }
        
        input.id = fieldName;
        input.name = fieldName;
        input.className = 'form-control';
        
        formGroup.appendChild(label);
        formGroup.appendChild(input);
        form.appendChild(formGroup);
    }

    // 获取实体的必要字段
    function getRequiredFields(entityType) {
        switch(entityType) {
            case 'user':
                return [
                    { name: 'username', defaultValue: '' },
                    { name: 'password', defaultValue: '' },
                    { name: 'realName', defaultValue: '' },
                    { name: 'email', defaultValue: '' },
                    { name: 'phone', defaultValue: '' },
                    { name: 'department', defaultValue: '' },
                    { name: 'position', defaultValue: '' },
                    { name: 'role', defaultValue: 'USER' },
                    { name: 'status', defaultValue: true }
                ];
            case 'product':
                return [
                    { name: 'productCode', defaultValue: '' },
                    { name: 'productName', defaultValue: '' },
                    { name: 'specification', defaultValue: '' },
                    { name: 'unit', defaultValue: '' },
                    { name: 'price', defaultValue: 0 }
                ];
            // 可以根据需要添加其他实体类型的必要字段
            default:
                return [];
        }
    }

    // 保存实体
    // 保存实体
    function saveEntity(entityType, id) {
        const form = document.getElementById('entityForm');
        const formData = new FormData(form);
        const data = {};
        
        // 将表单数据转换为JSON对象
        formData.forEach((value, key) => {
            // 处理特殊类型的值
            if (key.toLowerCase().includes('date') || key.toLowerCase().includes('time')) {
                // 日期时间字段
                data[key] = value ? new Date(value).toISOString() : null;
            } else if (value === 'true' || value === 'false') {
                // 布尔字段
                data[key] = value === 'true';
            } else if (!isNaN(value) && value !== '' && !key.toLowerCase().includes('phone')) {
                // 数字字段(排除电话号码)
                data[key] = Number(value);
            } else {
                // 其他字段
                data[key] = value;
            }
        });
        
        // 确定请求方法和URL
        const method = id ? 'PUT' : 'POST';
        const url = id ? `/api/admin/${entityType}/${id}` : `/api/admin/${entityType}`;
        
        // 发送请求
        authenticatedFetch(url, {
            method: method,
            body: JSON.stringify(data)
        })
        .then(response => {
            if (!response.ok) {
                throw new Error(`HTTP错误 ${response.status}`);
            }
            return response.json();
        })
        .then(result => {
            // 关闭模态框
            const modal = bootstrap.Modal.getInstance(document.getElementById('entityModal'));
            modal.hide();
            
            // 重新加载数据
            loadEntityData(entityType);
            
            // 显示成功消息
            alert(id ? '更新成功' : '添加成功');
        })
        .catch(error => {
            console.error(`保存${entityType}数据失败:`, error);
            alert(`保存失败: ${error.message}`);
        });
    }

    // 添加按钮点击事件
    document.getElementById('addBtn').addEventListener('click', function() {
        showEntityModal(currentEntityType);
    });

    // 刷新按钮点击事件
    document.getElementById('refreshBtn').addEventListener('click', function() {
        if (currentEntityType) {
            loadEntityData(currentEntityType);
        } else {
            loadDashboardData();
        }
    });
</script>
用户管理
<div class="container-fluid">
    <div class="row">
        <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block sidebar collapse">
            <div class="position-sticky pt-3 sidebar-sticky">
                <ul class="nav flex-column">
                    <li class="nav-item">
                        <a class="nav-link" href="/admin/dashboard">
                            <span data-feather="home"></span>
                            仪表盘
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link active" aria-current="page" href="/admin/users">
                            <span data-feather="users"></span>
                            用户管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('salesorder')">
                            <span data-feather="file"></span>
                            销售订单管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('product')">
                            <span data-feather="shopping-cart"></span>
                            产品管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('productcycle')">
                            <span data-feather="clock"></span>
                            产品周期管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('orderreview')">
                            <span data-feather="check-square"></span>
                            订单审核管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('orderchange')">
                            <span data-feather="edit"></span>
                            订单变更管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('forecastplan')">
                            <span data-feather="trending-up"></span>
                            预测计划管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('deliveryorder')">
                            <span data-feather="truck"></span>
                            发货单管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('contactform')">
                            <span data-feather="mail"></span>
                            联系单管理
                        </a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="#" onclick="loadEntityData('deliverystatistics')">
                            <span data-feather="bar-chart-2"></span>
                            发货统计管理
                        </a>
                    </li>
                </ul>
            </div>
        </nav>

        <main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
            <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
                <h1 class="h2">用户管理</h1>
                <div class="btn-toolbar mb-2 mb-md-0">
                    <div class="btn-group me-2">
                        <button type="button" class="btn btn-sm btn-outline-secondary" id="refreshBtn">刷新</button>
                        <button type="button" class="btn btn-sm btn-outline-primary" id="addUserBtn">添加用户</button>
                    </div>
                </div>
            </div>

            <!-- 搜索表单 -->
            <div class="row mb-3">
                <div class="col-md-12">
                    <div class="card">
                        <div class="card-body">
                            <form id="searchForm" class="row g-3">
                                <div class="col-md-3">
                                    <label for="searchUsername" class="form-label">用户名</label>
                                    <input type="text" class="form-control" id="searchUsername" name="username">
                                </div>
                                <div class="col-md-3">
                                    <label for="searchRealName" class="form-label">姓名</label>
                                    <input type="text" class="form-control" id="searchRealName" name="realName">
                                </div>
                                <div class="col-md-3">
                                    <label for="searchDepartment" class="form-label">部门</label>
                                    <input type="text" class="form-control" id="searchDepartment" name="department">
                                </div>
                                <div class="col-md-3">
                                    <label for="searchPosition" class="form-label">职位</label>
                                    <input type="text" class="form-control" id="searchPosition" name="position">
                                </div>
                                <div class="col-md-3">
                                    <label for="searchRole" class="form-label">角色</label>
                                    <select class="form-select" id="searchRole" name="role">
                                        <option value="">全部</option>
                                        <option value="USER">普通用户</option>
                                        <option value="ADMIN">管理员</option>
                                    </select>
                                </div>
                                <div class="col-md-3">
                                    <label for="searchStatus" class="form-label">状态</label>
                                    <select class="form-select" id="searchStatus" name="status">
                                        <option value="">全部</option>
                                        <option value="true">启用</option>
                                        <option value="false">禁用</option>
                                    </select>
                                </div>
                                <div class="col-md-3 d-flex align-items-end">
                                    <button type="button" class="btn btn-primary" id="searchBtn">搜索</button>
                                    <button type="button" class="btn btn-secondary ms-2" id="resetBtn">重置</button>
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 用户表格 -->
            <div class="table-responsive">
                <table class="table table-striped table-sm">
                    <thead>
                        <tr>
                            <th>ID</th>
                            <th>用户名</th>
                            <th>姓名</th>
                            <th>邮箱</th>
                            <th>电话</th>
                            <th>部门</th>
                            <th>职位</th>
                            <th>角色</th>
                            <th>状态</th>
                            <th>创建时间</th>
                            <th>最后登录</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody id="userTableBody">
                        <!-- 用户数据将动态加载 -->
                    </tbody>
                </table>
            </div>

            <!-- 分页控件 -->
            <nav aria-label="Page navigation">
                <ul class="pagination justify-content-center" id="pagination">
                    <!-- 分页将动态生成 -->
                </ul>
            </nav>

            <!-- 添加/编辑用户模态框 -->
            <div class="modal fade" id="userModal" tabindex="-1" aria-labelledby="userModalLabel" aria-hidden="true">
                <div class="modal-dialog">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title" id="userModalLabel">添加用户</h5>
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                        </div>
                        <div class="modal-body">
                            <form id="userForm">
                                <input type="hidden" id="userId" name="id">
                                <div class="mb-3">
                                    <label for="username" class="form-label">用户名</label>
                                    <input type="text" class="form-control" id="username" name="username" required>
                                </div>
                                <div class="mb-3" id="passwordGroup">
                                    <label for="password" class="form-label">密码</label>
                                    <input type="password" class="form-control" id="password" name="password" required>
                                </div>
                                <div class="mb-3">
                                    <label for="realName" class="form-label">姓名</label>
                                    <input type="text" class="form-control" id="realName" name="realName" required>
                                </div>
                                <div class="mb-3">
                                    <label for="email" class="form-label">邮箱</label>
                                    <input type="email" class="form-control" id="email" name="email" required>
                                </div>
                                <div class="mb-3">
                                    <label for="phone" class="form-label">电话</label>
                                    <input type="text" class="form-control" id="phone" name="phone" required>
                                </div>
                                <div class="mb-3">
                                    <label for="department" class="form-label">部门</label>
                                    <input type="text" class="form-control" id="department" name="department" required>
                                </div>
                                <div class="mb-3">
                                    <label for="position" class="form-label">职位</label>
                                    <input type="text" class="form-control" id="position" name="position" required>
                                </div>
                                <div class="mb-3">
                                    <label for="role" class="form-label">角色</label>
                                    <select class="form-select" id="role" name="role" required>
                                        <option value="USER">普通用户</option>
                                        <option value="ADMIN">管理员</option>
                                    </select>
                                </div>
                                <div class="mb-3">
                                    <label for="status" class="form-label">状态</label>
                                    <select class="form-select" id="status" name="status" required>
                                        <option value="true">启用</option>
                                        <option value="false">禁用</option>
                                    </select>
                                </div>
                            </form>
                        </div>
                        <div class="modal-footer">
                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                            <button type="button" class="btn btn-primary" id="saveUserBtn">保存</button>
                        </div>
                    </div>
                </div>
            </div>
        </main>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js"></script>
<script>
    // 初始化Feather图标
    document.addEventListener('DOMContentLoaded', function() {
        feather.replace();
        loadUsers();
    });

    // 当前页码和每页数量
    let currentPage = 0;
    let pageSize = 10;
    let totalPages = 0;

    // 加载用户数据
    function loadUsers(page = 0, size = 10) {
        currentPage = page;
        pageSize = size;

        // 获取搜索参数
        const searchParams = new URLSearchParams();
        searchParams.append('page', page);
        searchParams.append('size', size);

        // 添加搜索条件
        const username = document.getElementById('searchUsername').value;
        const realName = document.getElementById('searchRealName').value;
        const department = document.getElementById('searchDepartment').value;
        const position = document.getElementById('searchPosition').value;
        const role = document.getElementById('searchRole').value;
        const status = document.getElementById('searchStatus').value;

        if (username) searchParams.append('username', username);
        if (realName) searchParams.append('realName', realName);
        if (department) searchParams.append('department', department);
        if (position) searchParams.append('position', position);
        if (role) searchParams.append('role', role);
        if (status) searchParams.append('status', status);

        // 发送请求获取用户数据
        fetch(`/api/admin/users?${searchParams.toString()}`)
            .then(response => response.json())
            .then(data => {
                renderUsers(data.content);
                renderPagination(data.totalPages);
            })
            .catch(error => {
                console.error('获取用户数据失败:', error);
                alert('获取用户数据失败: ' + error.message);
            });
    }

    // 渲染用户表格
    function renderUsers(users) {
        const tableBody = document.getElementById('userTableBody');
        tableBody.innerHTML = '';

        if (!users || users.length === 0) {
            const row = document.createElement('tr');
            row.innerHTML = '<td colspan="12" class="text-center">暂无用户数据</td>';
            tableBody.appendChild(row);
            return;
        }

        users.forEach(user => {
            const row = document.createElement('tr');
            row.innerHTML = `
                <td>${user.id}</td>
                <td>${user.username}</td>
                <td>${user.realName || ''}</td>
                <td>${user.email || ''}</td>
                <td>${user.phone || ''}</td>
                <td>${user.department || ''}</td>
                <td>${user.position || ''}</td>
                <td>${user.role === 'ADMIN' ? '<span class="badge bg-danger">管理员</span>' : '<span class="badge bg-secondary">普通用户</span>'}</td>
                <td>${user.status ? '<span class="badge bg-success">启用</span>' : '<span class="badge bg-danger">禁用</span>'}</td>
                <td>${formatDateTime(user.createTime)}</td>
                <td>${formatDateTime(user.lastLoginTime)}</td>
                <td>
                    <button class="btn btn-sm btn-outline-primary me-1" onclick="editUser(${user.id})">编辑</button>
                    <button class="btn btn-sm btn-outline-${user.status ? 'warning' : 'success'}" onclick="toggleUserStatus(${user.id}, ${!user.status})">${user.status ? '禁用' : '启用'}</button>
                    <button class="btn btn-sm btn-outline-danger" onclick="deleteUser(${user.id})">删除</button>
                </td>
            `;
            tableBody.appendChild(row);
        });
    }

    // 渲染分页控件
    function renderPagination(totalPages) {
        const pagination = document.getElementById('pagination');
        pagination.innerHTML = '';

        // 如果总页数小于等于1,不显示分页
        if (totalPages <= 1) {
            return;
        }

        // 上一页按钮
        const prevItem = document.createElement('li');
        prevItem.className = `page-item ${currentPage === 0 ? 'disabled' : ''}`;
        prevItem.innerHTML = `<a class="page-link" href="#" onclick="${currentPage > 0 ? 'loadUsers(' + (currentPage - 1) + ')' : ''}">上一页</a>`;
        pagination.appendChild(prevItem);

        // 页码按钮
        const maxVisiblePages = 5;
        let startPage = Math.max(0, currentPage - Math.floor(maxVisiblePages / 2));
        let endPage = Math.min(totalPages - 1, startPage + maxVisiblePages - 1);

        // 调整startPage,确保显示maxVisiblePages个页码
        if (endPage - startPage + 1 < maxVisiblePages) {
            startPage = Math.max(0, endPage - maxVisiblePages + 1);
        }

        for (let i = startPage; i <= endPage; i++) {
            const pageItem = document.createElement('li');
            pageItem.className = `page-item ${i === currentPage ? 'active' : ''}`;
            pageItem.innerHTML = `<a class="page-link" href="#" onclick="loadUsers(${i})">${i + 1}</a>`;
            pagination.appendChild(pageItem);
        }

        // 下一页按钮
        const nextItem = document.createElement('li');
        nextItem.className = `page-item ${currentPage >= totalPages - 1 ? 'disabled' : ''}`;
        nextItem.innerHTML = `<a class="page-link" href="#" onclick="${currentPage < totalPages - 1 ? 'loadUsers(' + (currentPage + 1) + ')' : ''}">下一页</a>`;
        pagination.appendChild(nextItem);
    }

    // 格式化日期时间
    function formatDateTime(dateTimeStr) {
        if (!dateTimeStr) return '';
        const date = new Date(dateTimeStr);
        return date.toLocaleString();
    }

    // 添加用户按钮点击事件
    document.getElementById('addUserBtn').addEventListener('click', function() {
        // 重置表单
        document.getElementById('userForm').reset();
        document.getElementById('userId').value = '';
        document.getElementById('passwordGroup').style.display = 'block';
        document.getElementById('password').required = true;
        document.getElementById('userModalLabel').textContent = '添加用户';

        // 显示模态框
        const modal = new bootstrap.Modal(document.getElementById('userModal'));
        modal.show();
    });

    // 编辑用户
    function editUser(userId) {
        // 获取用户数据
        fetch(`/api/admin/user/${userId}`)
            .then(response => response.json())
            .then(user => {
                // 填充表单
                document.getElementById('userId').value = user.id;
                document.getElementById('username').value = user.username;
                document.getElementById('passwordGroup').style.display = 'none';
                document.getElementById('password').required = false;
                document.getElementById('realName').value = user.realName || '';
                document.getElementById('email').value = user.email || '';
                document.getElementById('phone').value = user.phone || '';
                document.getElementById('department').value = user.department || '';
                document.getElementById('position').value = user.position || '';
                document.getElementById('role').value = user.role || 'USER';
                document.getElementById('status').value = user.status.toString();
                document.getElementById('userModalLabel').textContent = '编辑用户';

                // 显示模态框
                const modal = new bootstrap.Modal(document.getElementById('userModal'));
                modal.show();
            })
            .catch(error => {
                console.error('获取用户数据失败:', error);
                alert('获取用户数据失败: ' + error.message);
            });
    }

    // 保存用户
    document.getElementById('saveUserBtn').addEventListener('click', function() {
        const form = document.getElementById('userForm');
        if (!form.checkValidity()) {
            form.reportValidity();
            return;
        }

        const userId = document.getElementById('userId').value;
        const isEdit = userId !== '';

        // 构建用户数据
        const userData = {
            username: document.getElementById('username').value,
            realName: document.getElementById('realName').value,
            email: document.getElementById('email').value,
            phone: document.getElementById('phone').value,
            department: document.getElementById('department').value,
            position: document.getElementById('position').value,
            role: document.getElementById('role').value,
            status: document.getElementById('status').value === 'true'
        };

        // 如果是添加用户,需要包含密码
        if (!isEdit) {
            userData.password = document.getElementById('password').value;
        }

        // 如果是编辑用户,需要包含ID
        if (isEdit) {
            userData.id = parseInt(userId);
        }

        // 发送请求
        const url = isEdit ? `/api/admin/user/${userId}` : '/api/admin/user';
        const method = isEdit ? 'PUT' : 'POST';

        fetch(url, {
            method: method,
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(userData)
        })
        .then(response => response.json())
        .then(data => {
            // 关闭模态框
            const modal = bootstrap.Modal.getInstance(document.getElementById('userModal'));
            modal.hide();

            // 重新加载用户数据
            loadUsers(currentPage, pageSize);

            // 显示成功消息
            alert(isEdit ? '用户更新成功' : '用户添加成功');
        })
        .catch(error => {
            console.error('保存用户失败:', error);
            alert('保存用户失败: ' + error.message);
        });
    });

    // 切换用户状态
    function toggleUserStatus(userId, newStatus) {
        if (confirm(`确定要${newStatus ? '启用' : '禁用'}该用户吗?`)) {
            fetch(`/api/admin/user/${userId}/status`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ status: newStatus })
            })
            .then(response => response.json())
            .then(data => {
                // 重新加载用户数据
                loadUsers(currentPage, pageSize);

                // 显示成功消息
                alert(newStatus ? '用户已启用' : '用户已禁用');
            })
            .catch(error => {
                console.error('更新用户状态失败:', error);
                alert('更新用户状态失败: ' + error.message);
            });
        }
    }

    // 删除用户
    function deleteUser(userId) {
        if (confirm('确定要删除该用户吗?此操作不可恢复!')) {
            fetch(`/api/admin/user/${userId}`, {
                method: 'DELETE'
            })
            .then(response => response.json())
            .then(data => {
                // 重新加载用户数据
                loadUsers(currentPage, pageSize);

                // 显示成功消息
                alert('用户已删除');
            })
            .catch(error => {
                console.error('删除用户失败:', error);
                alert('删除用户失败: ' + error.message);
            });
        }
    }

    // 搜索按钮点击事件
    document.getElementById('searchBtn').addEventListener('click', function() {
        loadUsers(0, pageSize); // 重置为第一页
    });

    // 重置按钮点击事件
    document.getElementById('resetBtn').addEventListener('click', function() {
        document.getElementById('searchForm').reset();
        loadUsers(0, pageSize); // 重置为第一页
    });

    // 刷新按钮点击事件
    document.getElementById('refreshBtn').addEventListener('click', function() {
        loadUsers(currentPage, pageSize);
    });
</script>
页面未找到

404

页面未找到

    <div class="error-image">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
            <path fill="#6c757d" d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"/>
        </svg>
    </div>
    
    <p class="error-message">抱歉,您请求的页面不存在或已被移除。</p>
    
    <div class="error-actions">
        <a href="/" class="btn">返回首页</a>
    </div>
</div>
服务器错误

500

服务器内部错误

    <div class="error-image">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
            <path fill="#dc3545" d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/>
        </svg>
    </div>
    
    <p class="error-message">抱歉,服务器遇到了一个错误,无法完成您的请求。</p>
    
    <div class="error-details" th:if="${message}">
        <p><strong>错误信息:</strong> <span th:text="${message}">错误详情</span></p>
        <p th:if="${timestamp}"><strong>时间:</strong> <span th:text="${timestamp}">2023-01-01 00:00:00</span></p>
        <p th:if="${path}"><strong>路径:</strong> <span th:text="${path}">/error</span></p>
    </div>
    
    <div class="error-actions">
        <a href="/" class="btn">返回首页</a>
    </div>
</div>
用户仪表盘

用户管理系统

<div class="sidebar">
    <div class="sidebar-heading">数据管理</div>
    <ul class="sidebar-menu">
        <li data-entity="user" class="active"><i class="bi bi-people"></i>用户管理</li>
        <li data-entity="salesorder"><i class="bi bi-cart"></i>销售订单</li>
        <li data-entity="product"><i class="bi bi-box"></i>产品管理</li>
        <li data-entity="orderproduct"><i class="bi bi-list-check"></i>订单产品</li>
        <li data-entity="missingproduct"><i class="bi bi-exclamation-triangle"></i>缺货产品</li>
        <li data-entity="productcycle"><i class="bi bi-arrow-repeat"></i>产品周期</li>
        <li data-entity="orderreview"><i class="bi bi-star"></i>订单评审</li>
        <li data-entity="orderchange"><i class="bi bi-pencil"></i>订单变更</li>
        <li data-entity="forecastplan"><i class="bi bi-graph-up"></i>预测计划</li>
        <li data-entity="deliveryorder"><i class="bi bi-truck"></i>交付订单</li>
        <li data-entity="contactform"><i class="bi bi-envelope"></i>联系表单</li>
        <li data-entity="deliverystatistics"><i class="bi bi-bar-chart"></i>交付统计</li>
    </ul>
</div>

<div class="main-content">
    <div class="welcome-message">
        欢迎回来,<span th:text="${currentUser != null ? currentUser.username : '游客'}">用户</span>!
    </div>
    
    <div class="stats-container">
        <div class="stat-card">
            <h3>用户总数</h3>
            <div class="value" id="userCount">0</div>
        </div>
        <div class="stat-card">
            <h3>订单总数</h3>
            <div class="value" id="orderCount">0</div>
        </div>
        <div class="stat-card">
            <h3>产品总数</h3>
            <div class="value" id="productCount">0</div>
        </div>
        <div class="stat-card">
            <h3>评审总数</h3>
            <div class="value" id="reviewCount">0</div>
        </div>
    </div>
    
    <div class="entity-container">
        <div class="entity-header">
            <h2 id="entityTitle">用户管理</h2>
            <div class="entity-actions">
                <button id="refreshBtn" class="btn btn-secondary"><i class="bi bi-arrow-clockwise"></i> 刷新</button>
                <button id="addBtn" class="btn btn-primary" th:if="${currentUser != null && currentUser.role == 'ADMIN'}"><i class="bi bi-plus"></i> 添加</button>
            </div>
        </div>
        <div class="table-responsive">
            <table class="entity-table" id="entityTable">
                <thead>
                    <!-- 表头将通过JavaScript动态生成 -->
                </thead>
                <tbody>
                    <!-- 数据将通过JavaScript动态加载 -->
                </tbody>
            </table>
        </div>
    </div>
</div>

<!-- 添加/编辑实体的模态框 -->
<div class="modal fade" id="entityModal" tabindex="-1" aria-labelledby="entityModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="entityModalLabel">添加/编辑</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form id="entityForm">
                    <input type="hidden" id="entityId">
                    <div id="formFields">
                        <!-- 表单字段将通过JavaScript动态生成 -->
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
                <button type="button" class="btn btn-primary" id="saveEntityBtn">保存</button>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<script>
    // 当前选中的实体类型
    let currentEntityType = 'user';
    // 模态框实例
    let entityModal;
    
    // 页面加载完成后执行
    document.addEventListener('DOMContentLoaded', function() {
        // 初始化模态框
        entityModal = new bootstrap.Modal(document.getElementById('entityModal'));
        
        // 加载仪表盘统计数据
        loadDashboardStats();
        
        // 加载默认实体数据(用户)
        loadEntityData('user');
        
        // 侧边栏菜单点击事件
        document.querySelectorAll('.sidebar-menu li').forEach(item => {
            item.addEventListener('click', function() {
                // 移除所有活动状态
                document.querySelectorAll('.sidebar-menu li').forEach(li => {
                    li.classList.remove('active');
                });
                
                // 添加当前项的活动状态
                this.classList.add('active');
                
                // 获取实体类型
                const entityType = this.getAttribute('data-entity');
                currentEntityType = entityType;
                
                // 更新标题
                document.getElementById('entityTitle').textContent = this.textContent.trim();
                
                // 加载对应实体数据
                loadEntityData(entityType);
            });
        });
        
        // 刷新按钮点击事件
        document.getElementById('refreshBtn').addEventListener('click', function() {
            loadEntityData(currentEntityType);
        });
        
        // 添加按钮点击事件
        document.getElementById('addBtn').addEventListener('click', function() {
            showEntityModal();
        });
        
        // 保存实体按钮点击事件
        document.getElementById('saveEntityBtn').addEventListener('click', function() {
            saveEntity();
        });
    });
    
    // 加载仪表盘统计数据
    function loadDashboardStats() {
        // 获取用户总数
        fetch('/api/admin/user')
            .then(response => response.json())
            .then(data => {
                document.getElementById('userCount').textContent = data.length;
            })
            .catch(error => console.error('获取用户数据失败:', error));
        
        // 获取订单总数
        fetch('/api/admin/salesorder')
            .then(response => response.json())
            .then(data => {
                document.getElementById('orderCount').textContent = data.length;
            })
            .catch(error => console.error('获取订单数据失败:', error));
        
        // 获取产品总数
        fetch('/api/admin/product')
            .then(response => response.json())
            .then(data => {
                document.getElementById('productCount').textContent = data.length;
            })
            .catch(error => console.error('获取产品数据失败:', error));
        
        // 获取评审总数
        fetch('/api/admin/orderreview')
            .then(response => response.json())
            .then(data => {
                document.getElementById('reviewCount').textContent = data.length;
            })
            .catch(error => console.error('获取评审数据失败:', error));
    }
    
    // 加载实体数据
    function loadEntityData(entityType) {
        fetch(`/api/admin/${entityType}`)
            .then(response => {
                if (!response.ok) {
                    // 如果响应不成功,但状态码是404,可能是没有数据
                    if (response.status === 404) {
                        return [];
                    }
                    throw new Error('获取数据失败');
                }
                return response.json();
            })
            .then(data => {
                renderEntityTable(entityType, data);
            })
            .catch(error => {
                console.error(`获取${entityType}数据失败:`, error);
                // 不再弹出错误提示,而是显示暂无数据
                renderEntityTable(entityType, []);
            });
    }
    
    // 渲染实体表格
    function renderEntityTable(entityType, data) {
        const table = document.getElementById('entityTable');
        const thead = table.querySelector('thead');
        const tbody = table.querySelector('tbody');
        
        // 清空表格内容
        tbody.innerHTML = '';
        
        // 如果没有数据
        if (!data || data.length === 0) {
            tbody.innerHTML = `<tr><td colspan="7" class="text-center">暂无数据</td></tr>`;
            return;
        }
        
        // 获取要显示的属性
        const keyProperties = getKeyProperties(entityType);
        
        // 创建表头
        let headerRow = '<tr><th>ID</th>';
        keyProperties.forEach(prop => {
            headerRow += `<th>${getPropertyDisplayName(prop)}</th>`;
        });
        headerRow += '<th>操作</th></tr>';
        thead.innerHTML = headerRow;
        
        // 创建表格行
        data.forEach(item => {
            let row = document.createElement('tr');
            
            // ID列
            let idCell = document.createElement('td');
            idCell.textContent = item.id;
            row.appendChild(idCell);
            
            // 属性列
            keyProperties.forEach(prop => {
                let cell = document.createElement('td');
                cell.innerHTML = formatPropertyValue(item[prop], prop);
                row.appendChild(cell);
            });
            
            // 操作列
            let actionCell = document.createElement('td');
            
            // 编辑按钮
            let editBtn = document.createElement('button');
            editBtn.className = 'action-btn edit-btn';
            editBtn.innerHTML = '<i class="bi bi-pencil"></i>';
            editBtn.addEventListener('click', function() {
                editEntity(entityType, item.id);
            });
            actionCell.appendChild(editBtn);
            
            // 删除按钮
            let deleteBtn = document.createElement('button');
            deleteBtn.className = 'action-btn delete-btn';
            deleteBtn.innerHTML = '<i class="bi bi-trash"></i>';
            deleteBtn.addEventListener('click', function() {
                if (confirm('确定要删除这条记录吗?')) {
                    deleteEntity(entityType, item.id);
                }
            });
            actionCell.appendChild(deleteBtn);
            
            row.appendChild(actionCell);
            tbody.appendChild(row);
        });
    }
    
    // 获取要显示的属性
    function getKeyProperties(entityType) {
        switch (entityType) {
            case 'user':
                return ['username', 'realName', 'email', 'department', 'role'];
            case 'salesorder':
                return ['orderNumber', 'customerName', 'orderDate', 'totalAmount', 'orderStatus'];
            case 'product':
                return ['productName', 'productCode', 'productCategory', 'standardPrice', 'inventoryQuantity'];
            case 'orderproduct':
                return ['salesOrder', 'product', 'quantity', 'unitPrice', 'subtotal'];
            case 'missingproduct':
                return ['product', 'requiredQuantity', 'availableQuantity', 'reportDate', 'status'];
            case 'productcycle':
                return ['product', 'cycleStart', 'cycleEnd', 'phase', 'description'];
            case 'orderreview':
                return ['salesOrder', 'reviewer', 'reviewDate', 'status', 'comments'];
            case 'orderchange':
                return ['salesOrder', 'changeDate', 'changeType', 'description', 'status'];
            case 'forecastplan':
                return ['product', 'planDate', 'forecastQuantity', 'actualQuantity', 'accuracy'];
            case 'deliveryorder':
                return ['deliveryNumber', 'orderNumber', 'customerName', 'deliveryDate', 'deliveryStatus'];
            case 'contactform':
                return ['formNumber', 'customerName', 'contactType', 'contactStatus', 'priority'];
            case 'deliverystatistics':
                return ['period', 'totalDeliveries', 'onTimeDeliveries', 'delayedDeliveries', 'onTimeRate'];
            default:
                return ['name', 'description', 'createdAt', 'updatedAt'];
        }
    }
    
    // 获取属性显示名称
    function getPropertyDisplayName(prop) {
        const displayNames = {
            'username': '用户名',
            'realName': '真实姓名',
            'email': '邮箱',
            'phone': '电话',
            'department': '部门',
            'position': '职位',
            'role': '角色',
            'status': '状态',
            'createTime': '创建时间',
            'updateTime': '更新时间',
            'lastLoginTime': '最后登录时间',
            'orderNumber': '订单编号',
            'customerName': '客户名称',
            'orderDate': '订单日期',
            'totalAmount': '总金额',
            'orderStatus': '订单状态',
            'paymentStatus': '付款状态',
            'paymentMethod': '付款方式',
            'shippingMethod': '配送方式',
            'expectedDeliveryDate': '预计交付日期',
            'actualDeliveryDate': '实际交付日期',
            'contactAddress': '联系地址',
            'remarks': '备注',
            'productName': '产品名称',
            'productCode': '产品编码',
            'productModel': '产品型号',
            'productType': '产品类型',
            'productCategory': '产品类别',
            'productStatus': '产品状态',
            'standardPrice': '标准价格',
            'costPrice': '成本价格',
            'inventoryQuantity': '库存数量',
            'minInventory': '最小库存',
            'maxInventory': '最大库存',
            'productionCycle': '生产周期',
            'unit': '单位',
            'name': '名称',
            'code': '编码',
            'category': '类别',
            'price': '价格',
            'stock': '库存',
            'quantity': '数量',
            'unitPrice': '单价',
            'subtotal': '小计',
            'salesOrder': '销售订单',
            'product': '产品',
            'requiredQuantity': '需求数量',
            'availableQuantity': '可用数量',
            'reportDate': '报告日期',
            'cycleStart': '周期开始',
            'cycleEnd': '周期结束',
            'phase': '阶段',
            'description': '描述',
            'reviewer': '评审人',
            'reviewDate': '评审日期',
            'comments': '评论',
            'changeDate': '变更日期',
            'changeType': '变更类型',
            'planDate': '计划日期',
            'forecastQuantity': '预测数量',
            'actualQuantity': '实际数量',
            'accuracy': '准确率',
            'deliveryDate': '交付日期',
            'carrier': '承运人',
            'trackingNumber': '跟踪号',
            'subject': '主题',
            'message': '消息',
            'submitDate': '提交日期',
            'period': '周期',
            'totalDeliveries': '总交付数',
            'onTimeDeliveries': '按时交付数',
            'delayedDeliveries': '延迟交付数',
            'onTimeRate': '按时率',
            'createdAt': '创建时间',
            'updatedAt': '更新时间',
            'deliveryNumber': '发货单号',
            'deliveryStatus': '发货状态',
            'formNumber': '表单编号',
            'contactType': '联系类型',
            'contactStatus': '处理状态',
            'priority': '优先级',
            'handlerName': '处理人',
            'handlingResult': '处理结果',
            'handlingTime': '处理时间',
            'contactContent': '联系内容'
        };
        
        return displayNames[prop] || prop;
    }
    
    // 格式化属性值
    function formatPropertyValue(value, prop) {
        if (value === null || value === undefined) {
            return '<span class="text-muted">未设置</span>';
        }
        
        // 日期类型属性
        if (prop.includes('Date') || prop.includes('Time') || prop === 'createdAt' || prop === 'updatedAt') {
            if (typeof value === 'string') {
                // 尝试解析日期字符串
                try {
                    const date = new Date(value);
                    return date.toLocaleString('zh-CN');
                } catch (e) {
                    return value;
                }
            }
            return value;
        }
        
        // 布尔类型属性
        if (typeof value === 'boolean') {
            return value ? '<span class="badge bg-success">是</span>' : '<span class="badge bg-danger">否</span>';
        }
        
        // 对象类型属性(如外键引用)
        if (typeof value === 'object' && value !== null) {
            if (value.id) {
                if (value.name) {
                    return `${value.name} (ID: ${value.id})`;
                } else if (value.orderNumber) {
                    return `订单 ${value.orderNumber} (ID: ${value.id})`;
                } else if (value.username) {
                    return `${value.username} (ID: ${value.id})`;
                } else if (value.productName) {
                    return `${value.productName} (ID: ${value.id})`;
                } else {
                    return `ID: ${value.id}`;
                }
            }
            return JSON.stringify(value);
        }
        
        // 角色属性特殊处理
        if (prop === 'role') {
            if (value === 'ADMIN') {
                return '<span class="badge bg-danger">管理员</span>';
            } else if (value === 'USER') {
                return '<span class="badge bg-primary">普通用户</span>';
            } else {
                return value;
            }
        }
        
        // 订单状态特殊处理
        if (prop === 'orderStatus') {
            if (value === 'PENDING') {
                return '<span class="badge bg-warning">待处理</span>';
            } else if (value === 'PROCESSING') {
                return '<span class="badge bg-info">处理中</span>';
            } else if (value === 'SHIPPED') {
                return '<span class="badge bg-primary">已发货</span>';
            } else if (value === 'DELIVERED') {
                return '<span class="badge bg-success">已交付</span>';
            } else if (value === 'CANCELLED') {
                return '<span class="badge bg-danger">已取消</span>';
            } else if (value === 'COMPLETED') {
                return '<span class="badge bg-success">已完成</span>';
            } else {
                return value;
            }
        }
        
        // 付款状态特殊处理
        if (prop === 'paymentStatus') {
            if (value === 'UNPAID') {
                return '<span class="badge bg-warning">未付款</span>';
            } else if (value === 'PARTIAL') {
                return '<span class="badge bg-info">部分付款</span>';
            } else if (value === 'PAID') {
                return '<span class="badge bg-success">已付款</span>';
            } else if (value === 'REFUNDED') {
                return '<span class="badge bg-danger">已退款</span>';
            } else {
                return value;
            }
        }
        
        // 产品状态特殊处理
        if (prop === 'productStatus') {
            if (value === 'ACTIVE') {
                return '<span class="badge bg-success">在售</span>';
            } else if (value === 'INACTIVE') {
                return '<span class="badge bg-secondary">停售</span>';
            } else if (value === 'DISCONTINUED') {
                return '<span class="badge bg-danger">已停产</span>';
            } else if (value === 'COMING_SOON') {
                return '<span class="badge bg-info">即将上市</span>';
            } else {
                return value;
            }
        }
        
        // 发货状态特殊处理
        if (prop === 'deliveryStatus') {
            if (value === '待发货' || value === 'PENDING') {
                return '<span class="badge bg-warning">待发货</span>';
            } else if (value === '已发货' || value === 'SHIPPED') {
                return '<span class="badge bg-primary">已发货</span>';
            } else if (value === '已签收' || value === 'DELIVERED') {
                return '<span class="badge bg-success">已签收</span>';
            } else if (value === '已取消' || value === 'CANCELLED') {
                return '<span class="badge bg-danger">已取消</span>';
            } else {
                return value;
            }
        }
        
        // 联系表单状态特殊处理
        if (prop === 'contactStatus') {
            if (value === '待处理' || value === 'PENDING') {
                return '<span class="badge bg-warning">待处理</span>';
            } else if (value === '处理中' || value === 'PROCESSING') {
                return '<span class="badge bg-info">处理中</span>';
            } else if (value === '已完成' || value === 'COMPLETED') {
                return '<span class="badge bg-success">已完成</span>';
            } else {
                return value;
            }
        }
        
        // 联系表单优先级特殊处理
        if (prop === 'priority') {
            if (value === '高' || value === 'HIGH') {
                return '<span class="badge bg-danger">高</span>';
            } else if (value === '中' || value === 'MEDIUM') {
                return '<span class="badge bg-warning">中</span>';
            } else if (value === '低' || value === 'LOW') {
                return '<span class="badge bg-info">低</span>';
            } else {
                return value;
            }
        }
        
        // 通用状态属性特殊处理
        if (prop === 'status') {
            if (value === true || value === 'ACTIVE' || value === 'COMPLETED' || value === 'APPROVED') {
                return '<span class="badge bg-success">正常</span>';
            } else if (value === false || value === 'INACTIVE' || value === 'PENDING' || value === 'REJECTED') {
                return '<span class="badge bg-warning">待处理</span>';
            } else if (value === 'CANCELLED' || value === 'FAILED') {
                return '<span class="badge bg-danger">取消</span>';
            } else {
                return value;
            }
        }
        
        // 金额类型特殊处理
        if (prop === 'totalAmount' || prop === 'standardPrice' || prop === 'costPrice' || prop.includes('Price')) {
            if (typeof value === 'number') {
                return `¥${value.toFixed(2)}`;
            }
            return value;
        }
        
        // 数量类型特殊处理
        if (prop === 'inventoryQuantity' || prop === 'minInventory' || prop === 'maxInventory' || prop.includes('Quantity')) {
            if (typeof value === 'number') {
                return value.toString();
            }
            return value;
        }
        
        return value;
    }
    
    // 编辑实体
    function editEntity(entityType, id) {
        fetch(`/api/admin/${entityType}/${id}`)
            .then(response => {
                if (!response.ok) {
                    throw new Error('获取数据失败');
                }
                return response.json();
            })
            .then(data => {
                showEntityModal(entityType, data);
            })
            .catch(error => {
                console.error(`获取${entityType}数据失败:`, error);
                alert(`获取${entityType}数据失败: ${error.message}`);
            });
    }
    
    // 删除实体
    function deleteEntity(entityType, id) {
        fetch(`/api/admin/${entityType}/${id}`, {
            method: 'DELETE',
            headers: {
                'Content-Type': 'application/json'
            }
        })
        .then(response => {
            if (!response.ok) {
                return response.json().then(data => {
                    throw new Error(data.message || '删除失败');
                });
            }
            return response.json();
        })
        .then(data => {
            alert(data.message || '删除成功');
            loadEntityData(entityType);
        })
        .catch(error => {
            console.error(`删除${entityType}失败:`, error);
            alert(`删除失败: ${error.message}`);
        });
    }
    
    // 显示实体模态框
    function showEntityModal(entityType = currentEntityType, data = null) {
        // 设置模态框标题
        const modalTitle = data ? '编辑' : '添加';
        document.getElementById('entityModalLabel').textContent = `${modalTitle} ${document.getElementById('entityTitle').textContent}`;
        
        // 清空表单字段
        const formFields = document.getElementById('formFields');
        formFields.innerHTML = '';
        
        // 设置实体ID
        const entityIdInput = document.getElementById('entityId');
        entityIdInput.value = data ? data.id : '';
        
        // 获取要显示的属性
        const keyProperties = getKeyProperties(entityType);
        
        // 创建表单字段
        for (const prop of keyProperties) {
            // 跳过ID字段
            if (prop === 'id') continue;
            
            // 跳过只读字段
            if (prop === 'createdAt' || prop === 'updatedAt' || prop === 'createTime' || prop === 'updateTime' || prop === 'lastLoginTime') continue;
            
            // 获取字段值
            const value = data ? data[prop] : '';
            
            // 创建表单字段
            const fieldHtml = createFormField(entityType, prop, value);
            formFields.innerHTML += fieldHtml;
        }
        
        // 显示模态框
        entityModal.show();
    }
    
    // 创建表单字段
    function createFormField(entityType, prop, value) {
        const displayName = getPropertyDisplayName(prop);
        const isRequired = getRequiredFields(entityType).includes(prop);
        const requiredAttr = isRequired ? 'required' : '';
        
        // 处理不同类型的字段
        if (prop === 'password') {
            // 密码字段
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <input type="password" class="form-control" id="${prop}" name="${prop}" ${requiredAttr}>
                    <small class="form-text text-muted">留空表示不修改密码</small>
                </div>
            `;
        } else if (prop === 'role') {
            // 角色字段
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <select class="form-control" id="${prop}" name="${prop}" ${requiredAttr}>
                        <option value="USER" ${value === 'USER' ? 'selected' : ''}>普通用户</option>
                        <option value="ADMIN" ${value === 'ADMIN' ? 'selected' : ''}>管理员</option>
                    </select>
                </div>
            `;
        } else if (prop === 'status' && typeof value === 'boolean') {
            // 布尔状态字段
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <select class="form-control" id="${prop}" name="${prop}" ${requiredAttr}>
                        <option value="true" ${value === true ? 'selected' : ''}>启用</option>
                        <option value="false" ${value === false ? 'selected' : ''}>禁用</option>
                    </select>
                </div>
            `;
        } else if (prop === 'status' && typeof value === 'string') {
            // 字符串状态字段
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <select class="form-control" id="${prop}" name="${prop}" ${requiredAttr}>
                        <option value="ACTIVE" ${value === 'ACTIVE' ? 'selected' : ''}>正常</option>
                        <option value="PENDING" ${value === 'PENDING' ? 'selected' : ''}>待处理</option>
                        <option value="COMPLETED" ${value === 'COMPLETED' ? 'selected' : ''}>已完成</option>
                        <option value="CANCELLED" ${value === 'CANCELLED' ? 'selected' : ''}>已取消</option>
                    </select>
                </div>
            `;
        } else if (prop.includes('Date') || prop.includes('Time')) {
            // 日期时间字段
            let dateValue = '';
            if (value) {
                try {
                    const date = new Date(value);
                    dateValue = date.toISOString().slice(0, 16);
                } catch (e) {
                    dateValue = value;
                }
            }
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <input type="datetime-local" class="form-control" id="${prop}" name="${prop}" value="${dateValue}" ${requiredAttr}>
                </div>
            `;
        } else if (typeof value === 'object' && value !== null) {
            // 对象类型字段(如外键引用)
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <input type="text" class="form-control" id="${prop}Id" name="${prop}Id" value="${value.id || ''}" ${requiredAttr} placeholder="输入${displayName}ID">
                </div>
            `;
        } else if (prop === 'description' || prop === 'comments' || prop === 'message') {
            // 文本区域字段
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <textarea class="form-control" id="${prop}" name="${prop}" rows="3" ${requiredAttr}>${value || ''}</textarea>
                </div>
            `;
        } else {
            // 默认文本字段
            return `
                <div class="form-group">
                    <label for="${prop}">${displayName}${isRequired ? ' *' : ''}</label>
                    <input type="text" class="form-control" id="${prop}" name="${prop}" value="${value || ''}" ${requiredAttr}>
                </div>
            `;
        }
    }
    
    // 获取必填字段
    function getRequiredFields(entityType) {
        switch (entityType) {
            case 'user':
                return ['username', 'role'];
            default:
                return [];
        }
    }
    
    // 保存实体
    function saveEntity() {
        const entityId = document.getElementById('entityId').value;
        const isUpdate = entityId !== '';
        
        // 构建表单数据
        const formData = {};
        const form = document.getElementById('entityForm');
        const formElements = form.elements;
        
        // 如果是更新,添加ID
        if (isUpdate) {
            formData.id = entityId;
        }
        
        // 收集表单字段值
        for (let i = 0; i < formElements.length; i++) {
            const element = formElements[i];
            if (element.name && element.name !== '') {
                // 处理特殊字段
                if (element.name.endsWith('Id')) {
                    // 处理外键引用
                    const propName = element.name.replace('Id', '');
                    formData[propName] = { id: element.value };
                } else if (element.type === 'checkbox') {
                    formData[element.name] = element.checked;
                } else if (element.name === 'status' && (element.value === 'true' || element.value === 'false')) {
                    formData[element.name] = element.value === 'true';
                } else if (element.value === '') {
                    // 跳过空值,除非是密码字段(允许为空表示不修改)
                    if (element.name !== 'password') {
                        continue;
                    }
                    formData[element.name] = element.value;
                } else {
                    formData[element.name] = element.value;
                }
            }
        }
        
        // 发送请求
        const url = isUpdate ? `/api/admin/${currentEntityType}/${entityId}` : `/api/admin/${currentEntityType}`;
        const method = isUpdate ? 'PUT' : 'POST';
        
        fetch(url, {
            method: method,
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(formData)
        })
        .then(response => {
            if (!response.ok) {
                return response.json().then(data => {
                    throw new Error(data.message || '保存失败');
                });
            }
            return response.json();
        })
        .then(data => {
            // 关闭模态框
            entityModal.hide();
            
            // 显示成功消息
            alert(isUpdate ? '更新成功' : '添加成功');
            
            // 重新加载数据
            loadEntityData(currentEntityType);
        })
        .catch(error => {
            console.error(`保存${currentEntityType}失败:`, error);
            alert(`保存失败: ${error.message}`);
        });
    }
</script>
错误页面

500

Internal Server Error

    <div class="error-message">
        <p th:text="${message}">抱歉,服务器遇到了一个错误,无法完成您的请求。</p>
    </div>
    
    <div class="error-details">
        <h3>错误详情</h3>
        <p><strong>时间:</strong> <span th:text="${timestamp}">2023-01-01 00:00:00</span></p>
        <p><strong>路径:</strong> <span th:text="${path}">/error</span></p>
        
        <div th:if="${exception}">
            <p><strong>异常:</strong> <span th:text="${exception}">Exception</span></p>
        </div>
        
        <div th:if="${trace}">
            <p><strong>堆栈跟踪:</strong></p>
            <pre th:text="${trace}">Stack trace</pre>
        </div>
    </div>
    
    <div class="error-actions">
        <a href="/" class="btn">返回首页</a>
    </div>
</div>
登录/注册 - 销售订单管理系统

销售订单管理系统

    <div th:if="${param.error}" class="alert alert-danger">
        用户名或密码错误,请重试
    </div>
    <div th:if="${param.logout}" class="alert alert-success">
        您已成功退出登录
    </div>
    <div th:if="${errorMessage}" class="alert alert-danger" th:text="${errorMessage}">
        错误信息
    </div>
    <div th:if="${success}" class="alert alert-success" th:text="${success}">
        成功信息
    </div>
    
    <ul class="nav nav-tabs" id="myTab" role="tablist">
        <li class="nav-item" role="presentation">
            <button class="nav-link active" id="login-tab" data-bs-toggle="tab" type="button" role="tab" aria-selected="true" onclick="showLoginForm()">登录</button>
        </li>
        <li class="nav-item" role="presentation">
            <button class="nav-link" id="register-tab" data-bs-toggle="tab" type="button" role="tab" aria-selected="false" onclick="showRegisterForm()">注册</button>
        </li>
    </ul>
    
    <!-- 登录表单 -->
    <form id="loginForm" action="/login" method="post">
        <div class="form-floating">
            <input type="text" class="form-control" id="username" name="username" placeholder="用户名" required>
            <label for="username">用户名</label>
        </div>
        <div class="form-floating">
            <input type="password" class="form-control" id="password" name="password" placeholder="密码" required>
            <label for="password">密码</label>
        </div>
        
        <div class="checkbox mb-3">
            <label>
                <input type="checkbox" value="remember-me"> 记住我
            </label>
        </div>
        <button class="w-100 btn btn-lg btn-primary" type="submit">登录</button>
    </form>
    
    <!-- 注册表单 -->
    <form id="registerForm" action="/register" method="post">
        <div class="form-floating">
            <input type="text" class="form-control" id="reg-username" name="username" placeholder="用户名" required>
            <label for="reg-username">用户名</label>
        </div>
        <div class="form-floating">
            <input type="password" class="form-control" id="reg-password" name="password" placeholder="密码" required>
            <label for="reg-password">密码</label>
        </div>
        <div class="form-floating">
            <input type="text" class="form-control" id="realName" name="realName" placeholder="真实姓名" required>
            <label for="realName">真实姓名</label>
        </div>
        <div class="form-floating">
            <input type="email" class="form-control" id="email" name="email" placeholder="邮箱" required>
            <label for="email">邮箱</label>
        </div>
        <div class="form-floating">
            <input type="tel" class="form-control" id="phone" name="phone" placeholder="电话" required>
            <label for="phone">电话</label>
        </div>
        <div class="form-floating">
            <select class="form-select" id="department" name="department" required>
                <option value="">请选择部门</option>
                <option value="客户">客户</option>
                <option value="市场部">市场部</option>
                <option value="工程部">工程部</option>
                <option value="计划部">计划部</option>
            </select>
            <label for="department">部门</label>
        </div>
        <div class="form-floating">
            <input type="text" class="form-control" id="position" name="position" placeholder="职位" required>
            <label for="position">职位</label>
        </div>
        <button class="w-100 btn btn-lg btn-success mt-3" type="submit">注册</button>
    </form>
    
    <p class="mt-5 mb-3 text-muted">&copy; 2023-2024</p>
</main>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
    function showLoginForm() {
        document.getElementById('loginForm').style.display = 'block';
        document.getElementById('registerForm').style.display = 'none';
        document.getElementById('login-tab').classList.add('active');
        document.getElementById('register-tab').classList.remove('active');
    }
    
    function showRegisterForm() {
        document.getElementById('loginForm').style.display = 'none';
        document.getElementById('registerForm').style.display = 'block';
        document.getElementById('login-tab').classList.remove('active');
        document.getElementById('register-tab').classList.add('active');
    }
    
    // 检查URL参数,如果有register参数,则显示注册表单
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.has('register')) {
        showRegisterForm();
    }
    // 在登录表单提交前添加事件监听器
    document.getElementById('loginForm').addEventListener('submit', function(event) {
        event.preventDefault();
        
        const username = document.getElementById('username').value;
        const password = document.getElementById('password').value;
        
        // 创建表单数据
        const formData = new FormData();
        formData.append('username', username);
        formData.append('password', password);
        
        fetch('/login', {
            method: 'POST',
            body: formData
        })
        .then(response => {
            if (response.ok) {
                // 登录成功,重定向到仪表盘
                window.location.href = '/admin/dashboard';
            } else {
                // 登录失败
                return response.text().then(text => {
                    throw new Error(text || '用户名或密码错误');
                });
            }
        })
        .catch(error => {
            console.error('登录失败:', error);
            alert('登录失败: ' + (error.message || '未知错误'));
        });
    });
</script>
spring.application.name=test

MySQL数据库连接配置

spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=wcd20050614
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

JPA配置

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

错误处理配置

server.error.include-message=always
server.error.include-binding-errors=always
server.error.include-stacktrace=never
server.error.include-exception=true
server.error.whitelabel.enabled=false`

posted @ 2025-05-31 15:53  仙人兵马俑  阅读(11)  评论(0)    收藏  举报