Compare commits

...

2 Commits

Author SHA1 Message Date
a48d3a2c73 更新代码 2025-05-30 13:50:33 +08:00
064f26801f 更新 .gitignore 文件 2025-05-30 13:43:31 +08:00
116 changed files with 8326 additions and 2433 deletions

64
.gitignore vendored Normal file
View File

@ -0,0 +1,64 @@
# 日志文件
logs/
*.log
# 前端依赖和构建文件
/frontend/node_modules/
/frontend/dist/
/frontend/.vite/
/frontend/.env.local
/frontend/.env.*.local
# 后端构建文件
/backend/target/
/backend/.mvn/
/backend/mvnw
/backend/mvnw.cmd
# IDE 配置文件
.idea/
.vscode/
*.iml
*.ipr
*.iws
# 操作系统文件
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# 数据库文件
*.db
*.sqlite
*.sqlite3
# 临时文件
*.tmp
*.temp
*.swp
*.swo
*~
# 编译文件
*.class
*.jar
*.war
*.ear
# 配置文件(包含敏感信息)
application-local.yml
application-local.properties
*.env
# 测试覆盖率报告
/backend/target/site/jacoco/
coverage/
# 其他
.cache/
.npm/
.yarn/

3
.idea/.gitignore vendored
View File

@ -1,3 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="stdproject-backend" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="stdproject-backend" options="-parameters" />
</option>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/backend/src/main/java" charset="UTF-8" />
</component>
</project>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/backend/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="corretto-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/StdProject.iml" filepath="$PROJECT_DIR$/.idea/StdProject.iml" />
</modules>
</component>
</project>

View File

@ -9,9 +9,9 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.stdproject</groupId>
<artifactId>stdproject-backend</artifactId>
<artifactId>stdproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>stdproject-backend</name>
<name>stdproject</name>
<description>Standard Project Backend</description>
<properties>
<java.version>17</java.version>

View File

@ -145,8 +145,6 @@ spring:
config:
activate:
on-profile: dev
jpa:
show-sql: true
security:
jwt:
enabled: false
@ -168,8 +166,6 @@ spring:
config:
activate:
on-profile: prod
jpa:
show-sql: false
security:
jwt:
enabled: true

View File

@ -1,14 +0,0 @@
# 数据库配置
DB_URL=jdbc:mysql://your-host:3306/your-db
DB_USERNAME=your-username
DB_PASSWORD=your-password
# JWT配置
JWT_SECRET=your-super-secret-key
JWT_EXPIRATION=86400000
# 环境配置
SPRING_PROFILES_ACTIVE=dev
# CORS配置
CORS_ALLOWED_ORIGINS=https://your-frontend.com

View File

@ -1,193 +0,0 @@
server:
port: 8080
servlet:
context-path: /
encoding:
charset: UTF-8
enabled: true
force: true
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
min-response-size: 1024
spring:
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
application:
name: stdproject-backend
datasource:
url: ${DB_URL:jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true}
username: ${DB_USERNAME:root}
password: ${DB_PASSWORD:mysql_F8ysiK@2024}
driver-class-name: com.mysql.cj.jdbc.Driver
# HikariCP连接池配置
hikari:
pool-name: StdProjectHikariCP
minimum-idle: 5
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
# url: jdbc:sqlite:D:/Trae_space/StdProject/backend/db/project.db
# username: # SQLite 不需要用户名
# password: # SQLite 不需要密码
# driver-class-name: org.sqlite.JDBC
# hikari:
# pool-name: StdProjectHikariCP
# minimum-idle: 5
# maximum-pool-size: 20
# auto-commit: true
# idle-timeout: 30000
# max-lifetime: 1800000
# connection-timeout: 30000
# connection-test-query: SELECT 1
cache:
jcache:
config: classpath:ehcache.xml # 指定Ehcache配置文件路径
security:
cors:
allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000,http://localhost:8080}
max-age: ${CORS_MAX_AGE:3600} # 预检请求的缓存时间(秒)
jwt:
enabled: ${JWT_ENABLED:true} # 控制是否启用JWT认证
secret: ${JWT_SECRET:YourJWTSecretKeyForStdProjectBackendApplicationWhichIsVeryLongAndSecure2024!@#$%^&*()}
expiration-ms: ${JWT_EXPIRATION:86400000} # Token 过期时间 (例如: 24小时)
refresh-expiration-ms: ${JWT_REFRESH_EXPIRATION:604800000} # 刷新Token过期时间 (例如: 7天)
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml # MyBatis Mapper XML文件位置
type-aliases-package: com.stdproject.entity
global-config:
db-config:
id-type: ASSIGN_ID # ID生成策略assign_id 表示手动分配ID通常使用雪花算法等
table-prefix: ${DB_TABLE_PREFIX:} # 如果表名有统一前缀,可以在这里配置
logic-delete-field: deleted # 逻辑删除字段名
logic-delete-value: 1 # 逻辑删除值
logic-not-delete-value: 0 # 逻辑未删除值
banner: false # 关闭MyBatis-Plus启动横幅
configuration:
map-underscore-to-camel-case: true # 开启驼峰命名转换
cache-enabled: true # 开启二级缓存
lazy-loading-enabled: true # 开启延迟加载
multiple-result-sets-enabled: true # 开启多结果集
use-column-label: true # 使用列标签
use-generated-keys: true # 使用生成的主键
auto-mapping-behavior: partial # 自动映射行为
default-executor-type: simple # 默认执行器类型
default-statement-timeout: 25000 # 默认语句超时时间
log-impl: ${MYBATIS_LOG_IMPL:org.apache.ibatis.logging.nologging.NoLoggingImpl} # SQL日志实现
logging:
config: classpath:logback-spring.xml # Logback配置文件
level:
root: ${LOG_LEVEL_ROOT:INFO}
com.stdproject: ${LOG_LEVEL_APP:DEBUG}
org.springframework.security: ${LOG_LEVEL_SECURITY:WARN}
org.hibernate.SQL: ${LOG_LEVEL_SQL:WARN}
org.hibernate.type.descriptor.sql.BasicBinder: ${LOG_LEVEL_SQL_PARAMS:WARN}
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
springdoc:
api-docs:
path: /v3/api-docs
enabled: ${SWAGGER_ENABLED:true}
swagger-ui:
path: /swagger-ui.html
enabled: ${SWAGGER_UI_ENABLED:true}
operations-sorter: alpha
tags-sorter: alpha
try-it-out-enabled: true
filter: true
default-consumes-media-type: application/json
default-produces-media-type: application/json
show-actuator: ${SWAGGER_SHOW_ACTUATOR:true}
packages-to-scan: com.stdproject.controller
# 管理端点配置
management:
endpoints:
web:
exposure:
include: ${ACTUATOR_ENDPOINTS:health,info,metrics}
base-path: /actuator
endpoint:
health:
show-details: ${ACTUATOR_HEALTH_DETAILS:when-authorized}
info:
enabled: true
info:
env:
enabled: true
java:
enabled: true
os:
enabled: true
# 应用信息配置
info:
app:
name: ${spring.application.name}
description: StdProject Backend Application
version: 1.0.0
encoding: UTF-8
java:
version: ${java.version}
---
# 开发环境配置
spring:
config:
activate:
on-profile: dev
jpa:
show-sql: true
security:
jwt:
enabled: false
logging:
level:
com.stdproject: DEBUG
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
springdoc:
swagger-ui:
enabled: true
---
# 生产环境配置
spring:
config:
activate:
on-profile: prod
jpa:
show-sql: false
security:
jwt:
enabled: true
logging:
level:
root: WARN
com.stdproject: INFO
org.springframework.security: ERROR
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
springdoc:
api-docs:
enabled: false
swagger-ui:
enabled: false
management:
endpoints:
web:
exposure:
include: health,info

View File

@ -1,58 +0,0 @@
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.ehcache.org/v3"
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd">
<!-- 默认缓存配置 -->
<cache-template name="default">
<expiry>
<ttl unit="seconds">3600</ttl> <!-- 默认1小时过期 -->
</expiry>
<resources>
<heap unit="entries">1000</heap> <!-- 堆内存中最多缓存1000个条目 -->
<offheap unit="MB">10</offheap> <!-- 堆外内存最多10MB -->
</resources>
</cache-template>
<!-- 用户信息缓存 -->
<cache alias="userCache" uses-template="default">
<expiry>
<ttl unit="minutes">30</ttl> <!-- 用户信息缓存30分钟 -->
</expiry>
</cache>
<!-- 角色信息缓存 -->
<cache alias="roleCache" uses-template="default">
<expiry>
<ttl unit="minutes">60</ttl> <!-- 角色信息缓存60分钟 -->
</expiry>
</cache>
<!-- 菜单信息缓存 -->
<cache alias="menuCache" uses-template="default">
<expiry>
<ttl unit="minutes">60</ttl> <!-- 菜单信息缓存60分钟 -->
</expiry>
</cache>
<!-- 权限信息缓存 -->
<cache alias="permissionCache" uses-template="default">
<expiry>
<ttl unit="minutes">60</ttl> <!-- 权限信息缓存60分钟 -->
</expiry>
</cache>
<!-- 数据字典缓存 -->
<cache alias="dictionaryCache" uses-template="default">
<expiry>
<ttl unit="hours">2</ttl> <!-- 数据字典缓存2小时 -->
</expiry>
</cache>
<!-- 组织机构缓存 -->
<cache alias="organizationCache" uses-template="default">
<expiry>
<ttl unit="hours">1</ttl> <!-- 组织机构缓存1小时 -->
</expiry>
</cache>
</config>

View File

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="stdproject"/>
<property name="LOG_PATH" value="logs/${APP_NAME}"/>
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory> <!-- 日志文件保留天数 -->
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- MyBatis Log -->
<logger name="com.stdproject.mapper" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</configuration>

View File

@ -1,71 +0,0 @@
com\stdproject\common\DataPermission.class
com\stdproject\service\IAppRoleUserService.class
com\stdproject\controller\AppMenuController$MenuOrderRequest.class
com\stdproject\service\impl\AppRoleUserServiceImpl.class
com\stdproject\config\SwaggerConfig.class
com\stdproject\controller\AppUserController$PasswordUpdateRequest.class
com\stdproject\service\IAppUserService.class
com\stdproject\controller\AppUserController.class
com\stdproject\controller\AppOptLogController$LogStatistics.class
com\stdproject\controller\AppDictionaryController.class
com\stdproject\entity\AppUser.class
com\stdproject\entity\AppRoleMenu.class
com\stdproject\entity\AppRoleUser.class
com\stdproject\config\WebConfig.class
com\stdproject\entity\AppOptLog.class
com\stdproject\service\IAppDictionaryService.class
com\stdproject\controller\AppOptLogController.class
com\stdproject\service\IAppRoleMenuService.class
com\stdproject\StdProjectApplication.class
com\stdproject\config\CustomUserDetailsService.class
com\stdproject\service\impl\AppDictionaryServiceImpl.class
com\stdproject\service\impl\AppRoleMenuServiceImpl.class
com\stdproject\service\IAppOptLogService.class
com\stdproject\controller\AppRoleController.class
com\stdproject\controller\AuthController$ChangePasswordRequest.class
com\stdproject\service\impl\AppOrganizationServiceImpl.class
com\stdproject\common\Result.class
com\stdproject\mapper\AppMenuMapper.class
com\stdproject\mapper\AppOptLogMapper.class
com\stdproject\config\JwtAuthenticationEntryPoint.class
com\stdproject\controller\AuthController.class
com\stdproject\utils\CaptchaUtils$CaptchaResult.class
com\stdproject\controller\AppMenuController$MenuTreeNode.class
com\stdproject\common\Constants.class
com\stdproject\common\OperationLogAspect.class
com\stdproject\service\impl\AppOptLogServiceImpl.class
com\stdproject\utils\JwtUtils$ClaimsResolver.class
com\stdproject\utils\CaptchaUtils.class
com\stdproject\common\OperationLog.class
com\stdproject\service\IAppRoleService.class
com\stdproject\common\BusinessException.class
com\stdproject\service\impl\AppMenuServiceImpl.class
com\stdproject\utils\PasswordUtils.class
com\stdproject\entity\AppDictionary.class
com\stdproject\utils\FileUtils.class
com\stdproject\service\impl\AppRoleServiceImpl.class
com\stdproject\utils\JwtUtils.class
com\stdproject\controller\AuthController$LoginRequest.class
com\stdproject\entity\AppRole.class
com\stdproject\common\ResultCode.class
com\stdproject\controller\AppOrganizationController.class
com\stdproject\mapper\AppRoleUserMapper.class
com\stdproject\controller\AppUserController$PasswordResetRequest.class
com\stdproject\mapper\AppRoleMapper.class
com\stdproject\service\IAppOrganizationService.class
com\stdproject\config\SecurityConfig.class
com\stdproject\controller\AppMenuController.class
com\stdproject\mapper\AppOrganizationMapper.class
com\stdproject\mapper\AppDictionaryMapper.class
com\stdproject\entity\AppOrganization.class
com\stdproject\config\JwtAuthenticationFilter.class
com\stdproject\mapper\AppUserMapper.class
com\stdproject\entity\AppMenu.class
com\stdproject\common\PageRequest.class
com\stdproject\controller\AppDictionaryController$DictOrderRequest.class
com\stdproject\service\impl\AppUserServiceImpl.class
com\stdproject\config\MybatisPlusConfig.class
com\stdproject\mapper\AppRoleMenuMapper.class
com\stdproject\common\GlobalExceptionHandler.class
com\stdproject\service\IAppMenuService.class
com\stdproject\config\CacheConfig.class

View File

@ -1,61 +0,0 @@
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\JwtAuthenticationFilter.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppDictionaryService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppOrganizationMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\PasswordUtils.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppOrganizationServiceImpl.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppOptLogController.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\MybatisPlusConfig.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppUser.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppDictionaryMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\SecurityConfig.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\SwaggerConfig.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\DataPermission.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppMenuService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\ResultCode.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppMenuServiceImpl.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRole.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppOrganization.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppRoleController.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleMenuServiceImpl.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleServiceImpl.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRoleMenu.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppOptLog.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleMenuMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleUserMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\PageRequest.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppOptLogMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppOrganizationController.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppUserController.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppDictionaryServiceImpl.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppOptLogService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\BusinessException.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppUserServiceImpl.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppUserService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\FileUtils.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\JwtUtils.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\CacheConfig.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\WebConfig.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\Constants.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRoleUser.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\OperationLogAspect.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppMenu.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppUserMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\JwtAuthenticationEntryPoint.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppDictionary.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\CaptchaUtils.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleUserService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppMenuController.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppOrganizationService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleMenuService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\GlobalExceptionHandler.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\OperationLog.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppDictionaryController.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppOptLogServiceImpl.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\StdProjectApplication.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AuthController.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\Result.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\CustomUserDetailsService.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppMenuMapper.java
D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleUserServiceImpl.java

349
frontend/README.md Normal file
View File

@ -0,0 +1,349 @@
# StdProject Frontend
基于 Vue 3 + Vite + Element Plus 的现代化前端管理系统
## 技术栈
- **Vue 3** - 渐进式 JavaScript 框架
- **Vite** - 下一代前端构建工具
- **Element Plus** - 基于 Vue 3 的组件库
- **Vue Router** - Vue.js 官方路由管理器
- **Pinia** - Vue 的状态管理库
- **Axios** - HTTP 客户端
- **SCSS** - CSS 预处理器
- **ESLint** - 代码质量检查工具
## 项目结构
```
frontend/
├── src/
│ ├── api/ # API 接口
│ │ ├── auth.js # 认证相关接口
│ │ ├── user.js # 用户管理接口
│ │ ├── role.js # 角色管理接口
│ │ ├── organization.js # 组织管理接口
│ │ └── dictionary.js # 字典管理接口
│ ├── components/ # 公共组件
│ ├── router/ # 路由配置
│ │ └── index.js # 路由定义
│ ├── store/ # 状态管理
│ │ ├── app.js # 应用状态
│ │ └── user.js # 用户状态
│ ├── styles/ # 样式文件
│ │ └── index.scss # 全局样式
│ ├── utils/ # 工具函数
│ │ ├── index.js # 通用工具函数
│ │ └── request.js # HTTP 请求封装
│ ├── views/ # 页面组件
│ │ ├── Login.vue # 登录页
│ │ ├── Dashboard.vue # 仪表盘
│ │ ├── Users.vue # 用户管理
│ │ ├── Roles.vue # 角色管理
│ │ ├── Organizations.vue # 组织管理
│ │ └── Dictionaries.vue # 字典管理
│ ├── App.vue # 根组件
│ └── main.js # 应用入口
├── package.json # 项目依赖
├── vite.config.js # Vite 配置
└── README.md # 项目说明
```
## 功能特性
### 🔐 认证授权
- JWT Token 认证
- 登录/登出
- 路由守卫
- 权限控制
### 👥 用户管理
- 用户列表查询
- 用户增删改查
- 用户状态管理
- 密码重置
- 批量操作
### 🛡️ 角色管理
- 角色列表查询
- 角色增删改查
- 权限分配
- 批量操作
### 🏢 组织管理
- 组织树形结构
- 组织增删改查
- 层级管理
- 拖拽排序
### 📚 字典管理
- 字典分类管理
- 字典数据管理
- 动态配置
- 缓存机制
### 📊 仪表盘
- 数据统计
- 图表展示
- 快捷操作
- 系统概览
## 开发指南
### 环境要求
- Node.js >= 16.0.0
- npm >= 8.0.0 或 yarn >= 1.22.0
### 安装依赖
```bash
# 使用 npm
npm install
# 或使用 yarn
yarn install
```
### 开发模式
```bash
# 启动开发服务器
npm run dev
# 或
yarn dev
```
访问 http://localhost:3000
### 构建生产版本
```bash
# 构建生产版本
npm run build
# 或
yarn build
```
### 代码检查
```bash
# 运行 ESLint
npm run lint
# 或
yarn lint
```
### 预览生产版本
```bash
# 预览构建结果
npm run preview
# 或
yarn preview
```
## 配置说明
### 环境变量
创建 `.env.local` 文件配置本地环境变量:
```env
# API 基础地址
VITE_API_BASE_URL=http://localhost:8080
# 应用标题
VITE_APP_TITLE=StdProject 管理系统
```
### 代理配置
开发环境下Vite 会自动将 `/api` 开头的请求代理到后端服务器:
```javascript
// vite.config.js
server: {
port: 3000,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
```
## API 接口
### 认证接口
- `POST /api/auth/login` - 用户登录
- `POST /api/auth/logout` - 用户登出
- `GET /api/auth/captcha` - 获取验证码
- `POST /api/auth/refresh` - 刷新 Token
### 用户接口
- `GET /api/users` - 获取用户列表
- `POST /api/users` - 创建用户
- `PUT /api/users/:id` - 更新用户
- `DELETE /api/users/:id` - 删除用户
### 角色接口
- `GET /api/roles` - 获取角色列表
- `POST /api/roles` - 创建角色
- `PUT /api/roles/:id` - 更新角色
- `DELETE /api/roles/:id` - 删除角色
### 组织接口
- `GET /api/organizations/tree` - 获取组织树
- `POST /api/organizations` - 创建组织
- `PUT /api/organizations/:id` - 更新组织
- `DELETE /api/organizations/:id` - 删除组织
### 字典接口
- `GET /api/dictionaries` - 获取字典列表
- `POST /api/dictionaries` - 创建字典
- `PUT /api/dictionaries/:id` - 更新字典
- `DELETE /api/dictionaries/:id` - 删除字典
## 开发规范
### 代码风格
- 使用 ESLint 进行代码检查
- 遵循 Vue 3 Composition API 规范
- 使用 SCSS 编写样式
- 组件命名使用 PascalCase
- 文件命名使用 kebab-case
### 组件开发
```vue
<template>
<!-- 模板内容 -->
</template>
<script setup>
// 使用 Composition API
import { ref, reactive, onMounted } from 'vue'
// 响应式数据
const loading = ref(false)
const form = reactive({})
// 生命周期
onMounted(() => {
// 初始化逻辑
})
</script>
<style lang="scss" scoped>
// 组件样式
</style>
```
### 状态管理
使用 Pinia 进行状态管理:
```javascript
// store/user.js
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
token: '',
userInfo: null
}),
actions: {
async login(credentials) {
// 登录逻辑
}
}
})
```
## 部署说明
### 构建部署
1. 构建生产版本:
```bash
npm run build
```
2. 将 `dist` 目录部署到 Web 服务器
### Nginx 配置
```nginx
server {
listen 80;
server_name your-domain.com;
root /path/to/dist;
index index.html;
# 处理 Vue Router 的 history 模式
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /api {
proxy_pass http://backend-server:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
## 常见问题
### Q: 如何添加新的页面?
A:
1. 在 `src/views` 目录下创建新的 Vue 组件
2. 在 `src/router/index.js` 中添加路由配置
3. 如需要,在导航菜单中添加对应链接
### Q: 如何添加新的 API 接口?
A:
1. 在 `src/api` 目录下对应的文件中添加接口函数
2. 使用 `request` 工具发送 HTTP 请求
3. 在组件中导入并使用
### Q: 如何自定义主题?
A:
1. 修改 `src/styles/index.scss` 中的 CSS 变量
2. 覆盖 Element Plus 的主题变量
3. 重新构建项目
## 贡献指南
1. Fork 项目
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 打开 Pull Request
## 许可证
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情
## 联系方式
- 项目地址:[GitHub Repository](https://github.com/your-username/stdproject)
- 问题反馈:[Issues](https://github.com/your-username/stdproject/issues)
- 邮箱your-email@example.com

3639
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

35
frontend/package.json Normal file
View File

@ -0,0 +1,35 @@
{
"name": "stdproject-frontend",
"version": "1.0.0",
"description": "StdProject Vue3 Frontend",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"vue": "^3.4.0",
"vue-router": "^4.2.5",
"pinia": "^2.1.7",
"axios": "^1.6.0",
"element-plus": "^2.4.4",
"@element-plus/icons-vue": "^2.3.1"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.2",
"vite": "^5.0.8",
"@vue/eslint-config-prettier": "^8.0.0",
"@rushstack/eslint-patch": "^1.3.3",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"prettier": "^3.0.3",
"sass": "^1.69.5"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
}
}

33
frontend/src/App.vue Normal file
View File

@ -0,0 +1,33 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
height: 100vh;
width: 100vw;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
}
</style>

78
frontend/src/api/auth.js Normal file
View File

@ -0,0 +1,78 @@
import request from '@/utils/request'
/**
* 用户登录
* @param {Object} data 登录数据
* @param {string} data.username 用户名
* @param {string} data.password 密码
* @param {string} data.captcha 验证码
* @param {string} data.captchaKey 验证码key
* @returns {Promise}
*/
export function login(data) {
return request({
url: '/auth/login',
method: 'post',
data
})
}
/**
* 用户登出
* @returns {Promise}
*/
export function logout() {
return request({
url: '/auth/logout',
method: 'post'
})
}
/**
* 获取验证码
* @returns {Promise}
*/
export function getCaptcha() {
return request({
url: '/auth/captcha',
method: 'get'
})
}
/**
* 刷新token
* @returns {Promise}
*/
export function refreshToken() {
return request({
url: '/auth/refresh',
method: 'post'
})
}
/**
* 获取当前用户信息
* @returns {Promise}
*/
export function getCurrentUser() {
return request({
url: '/auth/current',
method: 'get'
})
}
/**
* 修改密码
* @param {Object} data 修改密码数据
* @param {string} data.username 用户名
* @param {string} data.oldPassword 旧密码
* @param {string} data.newPassword 新密码
* @returns {Promise}
*/
export function changePassword(data) {
return request({
url: '/auth/changePassword',
method: 'post',
data
})
}

View File

@ -0,0 +1,103 @@
import request from '@/utils/request'
/**
* 获取字典列表
* @param {Object} params 查询参数
* @returns {Promise}
*/
export function getDictionaryList(params) {
return request({
url: '/dictionaries',
method: 'get',
params
})
}
/**
* 获取字典详情
* @param {string|number} id 字典ID
* @returns {Promise}
*/
export function getDictionaryById(id) {
return request({
url: `/dictionaries/${id}`,
method: 'get'
})
}
/**
* 根据字典编码和数据获取字典
* @param {string} dictCode 字典编码
* @param {string} dictData 字典数据
* @returns {Promise}
*/
export function getDictionaryByCodeAndData(dictCode, dictData) {
return request({
url: `/dictionaries/code/${dictCode}/data/${dictData}`,
method: 'get'
})
}
/**
* 根据字典名称获取字典数据
* @param {string} dictName 字典名称
* @returns {Promise}
*/
export function getDictionaryDataByName(dictName) {
return request({
url: `/dictionaries/name/${dictName}`,
method: 'get'
})
}
/**
* 创建字典
* @param {Object} data 字典数据
* @returns {Promise}
*/
export function createDictionary(data) {
return request({
url: '/dictionaries',
method: 'post',
data
})
}
/**
* 更新字典
* @param {string|number} id 字典ID
* @param {Object} data 字典数据
* @returns {Promise}
*/
export function updateDictionary(id, data) {
return request({
url: `/dictionaries/${id}`,
method: 'put',
data
})
}
/**
* 删除字典
* @param {string|number} id 字典ID
* @returns {Promise}
*/
export function deleteDictionary(id) {
return request({
url: `/dictionaries/${id}`,
method: 'delete'
})
}
/**
* 批量删除字典
* @param {Array} ids 字典ID数组
* @returns {Promise}
*/
export function batchDeleteDictionaries(ids) {
return request({
url: '/dictionaries/batch',
method: 'delete',
data: { ids }
})
}

View File

@ -0,0 +1,104 @@
import request from '@/utils/request'
/**
* 获取组织列表
* @param {Object} params 查询参数
* @returns {Promise}
*/
export function getOrganizationList(params) {
return request({
url: '/organizations',
method: 'get',
params
})
}
/**
* 获取组织树形结构
* @returns {Promise}
*/
export function getOrganizationTree() {
return request({
url: '/organizations/tree',
method: 'get'
})
}
/**
* 获取组织详情
* @param {string|number} id 组织ID
* @returns {Promise}
*/
export function getOrganizationById(id) {
return request({
url: `/organizations/${id}`,
method: 'get'
})
}
/**
* 创建组织
* @param {Object} data 组织数据
* @returns {Promise}
*/
export function createOrganization(data) {
return request({
url: '/organizations',
method: 'post',
data
})
}
/**
* 更新组织
* @param {string|number} id 组织ID
* @param {Object} data 组织数据
* @returns {Promise}
*/
export function updateOrganization(id, data) {
return request({
url: `/organizations/${id}`,
method: 'put',
data
})
}
/**
* 删除组织
* @param {string|number} id 组织ID
* @returns {Promise}
*/
export function deleteOrganization(id) {
return request({
url: `/organizations/${id}`,
method: 'delete'
})
}
/**
* 获取组织下的用户
* @param {string|number} id 组织ID
* @param {Object} params 查询参数
* @returns {Promise}
*/
export function getOrganizationUsers(id, params) {
return request({
url: `/organizations/${id}/users`,
method: 'get',
params
})
}
/**
* 移动组织
* @param {string|number} id 组织ID
* @param {string|number} parentId 新父组织ID
* @returns {Promise}
*/
export function moveOrganization(id, parentId) {
return request({
url: `/organizations/${id}/move`,
method: 'put',
data: { parentId }
})
}

104
frontend/src/api/role.js Normal file
View File

@ -0,0 +1,104 @@
import request from '@/utils/request'
/**
* 获取角色列表
* @param {Object} params 查询参数
* @returns {Promise}
*/
export function getRoleList(params) {
return request({
url: '/roles',
method: 'get',
params
})
}
/**
* 获取角色详情
* @param {string|number} id 角色ID
* @returns {Promise}
*/
export function getRoleById(id) {
return request({
url: `/roles/${id}`,
method: 'get'
})
}
/**
* 创建角色
* @param {Object} data 角色数据
* @returns {Promise}
*/
export function createRole(data) {
return request({
url: '/roles',
method: 'post',
data
})
}
/**
* 更新角色
* @param {string|number} id 角色ID
* @param {Object} data 角色数据
* @returns {Promise}
*/
export function updateRole(id, data) {
return request({
url: `/roles/${id}`,
method: 'put',
data
})
}
/**
* 删除角色
* @param {string|number} id 角色ID
* @returns {Promise}
*/
export function deleteRole(id) {
return request({
url: `/roles/${id}`,
method: 'delete'
})
}
/**
* 批量删除角色
* @param {Array} ids 角色ID数组
* @returns {Promise}
*/
export function batchDeleteRoles(ids) {
return request({
url: '/roles/batch',
method: 'delete',
data: { ids }
})
}
/**
* 获取角色权限
* @param {string|number} id 角色ID
* @returns {Promise}
*/
export function getRolePermissions(id) {
return request({
url: `/roles/${id}/permissions`,
method: 'get'
})
}
/**
* 设置角色权限
* @param {string|number} id 角色ID
* @param {Array} permissions 权限ID数组
* @returns {Promise}
*/
export function setRolePermissions(id, permissions) {
return request({
url: `/roles/${id}/permissions`,
method: 'put',
data: { permissions }
})
}

106
frontend/src/api/user.js Normal file
View File

@ -0,0 +1,106 @@
import request from '@/utils/request'
/**
* 获取用户列表
* @param {Object} params 查询参数
* @returns {Promise}
*/
export function getUserList(params) {
return request({
url: '/users',
method: 'get',
params
})
}
/**
* 获取用户详情
* @param {string|number} id 用户ID
* @returns {Promise}
*/
export function getUserById(id) {
return request({
url: `/users/${id}`,
method: 'get'
})
}
/**
* 创建用户
* @param {Object} data 用户数据
* @returns {Promise}
*/
export function createUser(data) {
return request({
url: '/users',
method: 'post',
data
})
}
/**
* 更新用户
* @param {string|number} id 用户ID
* @param {Object} data 用户数据
* @returns {Promise}
*/
export function updateUser(id, data) {
return request({
url: `/users/${id}`,
method: 'put',
data
})
}
/**
* 删除用户
* @param {string|number} id 用户ID
* @returns {Promise}
*/
export function deleteUser(id) {
return request({
url: `/users/${id}`,
method: 'delete'
})
}
/**
* 批量删除用户
* @param {Array} ids 用户ID数组
* @returns {Promise}
*/
export function batchDeleteUsers(ids) {
return request({
url: '/users/batch',
method: 'delete',
data: { ids }
})
}
/**
* 重置用户密码
* @param {string|number} id 用户ID
* @param {string} newPassword 新密码
* @returns {Promise}
*/
export function resetUserPassword(id, newPassword) {
return request({
url: `/users/${id}/password/reset`,
method: 'post',
data: { newPassword }
})
}
/**
* 启用/禁用用户
* @param {string|number} id 用户ID
* @param {boolean} enabled 是否启用
* @returns {Promise}
*/
export function toggleUserStatus(id, enabled) {
return request({
url: `/users/${id}/status`,
method: 'put',
data: { enabled }
})
}

21
frontend/src/main.js Normal file
View File

@ -0,0 +1,21 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import './styles/index.scss'
const app = createApp(App)
// 注册Element Plus图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount('#app')

View File

@ -0,0 +1,104 @@
import { createRouter, createWebHistory } from 'vue-router'
import { useUserStore } from '@/store/user'
// 路由配置
const routes = [
{
path: '/',
redirect: '/dashboard'
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue'),
meta: {
title: '登录',
requiresAuth: false
}
},
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: {
title: '仪表板',
requiresAuth: true
}
},
{
path: '/users',
name: 'Users',
component: () => import('@/views/Users.vue'),
meta: {
title: '用户管理',
requiresAuth: true
}
},
{
path: '/roles',
name: 'Roles',
component: () => import('@/views/Roles.vue'),
meta: {
title: '角色管理',
requiresAuth: true
}
},
{
path: '/organizations',
name: 'Organizations',
component: () => import('@/views/Organizations.vue'),
meta: {
title: '组织管理',
requiresAuth: true
}
},
{
path: '/dictionaries',
name: 'Dictionaries',
component: () => import('@/views/Dictionaries.vue'),
meta: {
title: '字典管理',
requiresAuth: true
}
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/views/NotFound.vue'),
meta: {
title: '页面未找到',
requiresAuth: false
}
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// 路由守卫
router.beforeEach((to, from, next) => {
const userStore = useUserStore()
// 设置页面标题
document.title = to.meta.title ? `${to.meta.title} - StdProject` : 'StdProject'
// 检查是否需要认证
if (to.meta.requiresAuth) {
if (userStore.isAuthenticated) {
next()
} else {
next('/login')
}
} else {
// 如果已登录且访问登录页,重定向到仪表板
if (to.path === '/login' && userStore.isAuthenticated) {
next('/dashboard')
} else {
next()
}
}
})
export default router

69
frontend/src/store/app.js Normal file
View File

@ -0,0 +1,69 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useAppStore = defineStore('app', () => {
// 侧边栏状态
const sidebarCollapsed = ref(false)
// 主题设置
const theme = ref(localStorage.getItem('theme') || 'light')
// 语言设置
const language = ref(localStorage.getItem('language') || 'zh-CN')
// 加载状态
const loading = ref(false)
// 面包屑导航
const breadcrumbs = ref([])
// 切换侧边栏
const toggleSidebar = () => {
sidebarCollapsed.value = !sidebarCollapsed.value
}
// 设置主题
const setTheme = (newTheme) => {
theme.value = newTheme
localStorage.setItem('theme', newTheme)
document.documentElement.setAttribute('data-theme', newTheme)
}
// 设置语言
const setLanguage = (newLanguage) => {
language.value = newLanguage
localStorage.setItem('language', newLanguage)
}
// 设置加载状态
const setLoading = (status) => {
loading.value = status
}
// 设置面包屑
const setBreadcrumbs = (crumbs) => {
breadcrumbs.value = crumbs
}
// 初始化主题
const initTheme = () => {
document.documentElement.setAttribute('data-theme', theme.value)
}
return {
// 状态
sidebarCollapsed,
theme,
language,
loading,
breadcrumbs,
// 方法
toggleSidebar,
setTheme,
setLanguage,
setLoading,
setBreadcrumbs,
initTheme
}
})

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