diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..be795f1 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +end_of_line = lf +charset = utf-8 +indent_style = space +indent_size = 4 + +[*.yml] +indent_style = space +indent_size = 2 + +[*.vue.ftl] +indent_style = space +indent_size = 2 + +[*.ts.ftl] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5b346c2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# 默认所有文件作为文本处理,统一换行符为 LF +* text eol=lf + +# 针对二进制文件禁止换行符转换 +*.png binary +*.xdb binary \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..dd84ea7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..8d675fe --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "maven" # See documentation for possible values + directory: "/sz-dependencies" # Location of package manifests + schedule: + interval: "weekly" + target-branch: dev # 指定要检查的目标分支 + open-pull-requests-limit: 20 # 限制同时打开的PR数量 \ No newline at end of file diff --git a/.github/workflows/Docker Sz Services CI.yml b/.github/workflows/Docker Sz Services CI.yml new file mode 100644 index 0000000..46bb9b8 --- /dev/null +++ b/.github/workflows/Docker Sz Services CI.yml @@ -0,0 +1,130 @@ +name: Docker Sz Services CI + +on: + push: + branches: [ "preview" ] + pull_request: + branches: [ "preview" ] + workflow_dispatch: + +jobs: + build-and-deploy: + name: Build & Deploy ${{ matrix.app_name }} + runs-on: ubuntu-latest + strategy: + max-parallel: 1 # 串行处理多个服务,保证部署顺序 + matrix: + include: + - app_name: sz-service-admin + service_port: 9991 + log_dir: /home/app/sz-service-admin/logs + config_dir: /home/conf/sz-service-admin + jar_dir: ./sz-service/sz-service-admin/target + docker_compose_path: /home/docker-compose/sz-service-admin + - app_name: sz-service-websocket + service_port: 9993 + log_dir: /home/app/sz-service-websocket/logs + config_dir: /home/conf/sz-service-websocket + jar_dir: ./sz-service/sz-service-websocket/target + docker_compose_path: /home/docker-compose/sz-service-websocket + + env: + # 镜像仓库相关配置 + ACR_DOMAIN: registry.cn-beijing.aliyuncs.com + ACR_ZONE: sz-action + VERSION: latest + # 应用环境配置 + RUNNING_ACTIVE: preview + # 容器启动脚本目录(如果直接 docker 启动需要) + SHELL_RUN_DIR: /home/run + + steps: + # 1. 拉取源码 + - name: Checkout code + uses: actions/checkout@v4 + + # 2. 安装 JDK 21 环境 + - name: Set up JDK 21 (Zulu) + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '21' + cache: 'maven' + + # 3. 安装 Maven 工具 + - name: Set up Maven 3.8.2 + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.8.2 + + # 4. Maven 编译打包 + - name: Build with Maven + run: mvn clean package + + # 5. 复制打包产物 JAR 文件到工作目录(方便 Docker 构建) + - name: Copy JAR file to workspace + run: | + cd ${{ matrix.jar_dir }} + cp ./*.jar ../../../app.jar + + # 6. 构建 Docker 镜像 + - name: Build Docker image + run: docker build -t ${{ matrix.app_name }}:${{ env.VERSION }} . + + # 7. 登录阿里云 ACR 仓库 + - name: Login to ACR + run: echo "${{ secrets.ACR_PASSWORD }}" | docker login --username=${{ secrets.ACR_USERNAME }} ${{ env.ACR_DOMAIN }} --password-stdin + + # 8. 镜像打标签(仓库命名规范) + - name: Tag Docker image + run: docker tag ${{ matrix.app_name }}:${{ env.VERSION }} ${{ env.ACR_DOMAIN }}/${{ env.ACR_ZONE }}/${{ matrix.app_name }}:${{ env.VERSION }} + + # 9. 推送镜像到远程仓库 + - name: Push Docker image to ACR + run: docker push ${{ env.ACR_DOMAIN }}/${{ env.ACR_ZONE }}/${{ matrix.app_name }}:${{ env.VERSION }} + + # 10. 使用 docker-compose 在远程服务器自动部署(推荐,结合 sz-deploy-v3 脚本) + - name: Deploy with docker-compose on remote server + uses: appleboy/ssh-action@v1.2.0 + with: + host: ${{ secrets.REMOTE_HOST }} + username: ${{ secrets.REMOTE_USER }} + password: ${{ secrets.REMOTE_PASSWORD }} + script: | + cd ${{ matrix.docker_compose_path }} + bash upgrade.sh + + # ————— 以下流程为可选直接 docker 启动,建议使用上方 docker-compose 部署,如需手动容器管理可启用————— +# - name: Direct Docker deploy on remote server +# uses: appleboy/ssh-action@v1.2.0 +# with: +# host: ${{ secrets.REMOTE_HOST }} +# username: ${{ secrets.REMOTE_USER }} +# password: ${{ secrets.REMOTE_PASSWORD }} +# script: | +# docker pull ${{ env.ACR_DOMAIN }}/${{ env.ACR_ZONE }}/${{ matrix.app_name }}:${{ env.VERSION }} +# echo "=== 生成容器启动脚本 ===" +# mkdir -p ${{ env.SHELL_RUN_DIR }} +# START_SCRIPT="${{ env.SHELL_RUN_DIR }}/docker_run_${{ matrix.app_name }}_${{ env.RUNNING_ACTIVE }}.sh" +# cat > $START_SCRIPT < $START_SCRIPT < [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1.3.2-beta) + +### sz-boot-parent + +#### 新增 + +- [代码生成器] 支持选择弹窗类型(抽屉、弹窗)。 +- 通用 API:新增获取 OSS 私有文件访问 URL 接口。 +- 通用 API:新增文件下载接口。 +- 参数管理新增「是否前端加载」字段。 +- websocket新增:支持同步字典、权限和前端参数。 + +#### 修改 + +- oss.yml 配置,新增 `oss.richtextBucketName` 配置项,用于为富文本编辑器**单独指定** bucket + +#### 优化 + +- 优化逻辑删除监听器的登录状态检查,增加异常处理以支持非Web环境 + +--- + +### sz-admin + +#### 新增 + +- [代码生成器] - 增加弹窗类型的支持(抽屉、弹窗)。 +- 参数 / 字典 / 权限的 websocket同步支持,并在参数管理中新增「是否前端加载」配置。 +- 新增: useDialogWidth Hook 组件,实现弹窗/对话框宽度的动态自适应。 + +#### 重构 + +- 重构 websocket实现,将消息解析与频道处理逻辑解耦,结构更清晰、扩展性更强。 + +#### 修复 + +- 修复 `MenuForm.vue` 中目录类型的可操作属性,恢复路由名称和路由地址属性。([issue 25](https://github.com/feiyuchuixue/sz-admin/issues/25))。 + +- 修复 `SearchFormItem` 组件仅在搜索项配置 `enum` 时读取 `undefined` 导致的报错问题。现在在 `SearchProps` 或 `ColumnProps` 任一处配置 `enum` 即可正常使用。([issue 26](https://github.com/feiyuchuixue/sz-admin/issues/26))。 + +#### 优化 + +- `Avatar` 头像组件:增加对 OSS 私有访问地址的支持。 +- `FileDownloadList` 文件回显展示组件:增加对 OSS 私有访问地址的支持。 +- `Img` 图片组件:增加对 OSS 私有访问地址的支持。 +- `Imgs` 多图片组件:增加对 OSS 私有访问地址的支持。 +- 账户管理 - 添加/编辑用户:头像字段增加对 OSS 私有访问地址的支持。 +- `JoditEditor` 富文本组件:支持使用独立的 bucket 空间(通过 `oss.richtextBucketName` 配置)。 +- 文件管理列表:优化文件下载方式。 +- `useUrlDownload`:移除前端 Fetch 下载逻辑,改为调用通用 API 文件下载接口,解决文件跨域问题。 + +### 数据库变更 + +- 更新 `sys_config` 表:增加 `frontend_visible` 字段,用于标记参数是否需要前端加载、缓存及使用。 +- 更新 `generator_table` 表:增加 `window_show_type` 字段,用于配置窗口展示方式(0:dialog 弹窗;1:drawer 抽屉)。 + +## v1.3.1-beta (20251210) +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1.3.1-beta) + +### sz-boot-parent + +#### 依赖升级 + +- modelmapper:3.2.6 +- mybatis-flex:1.11.4 +- commons-lang3:3.20.0 +- swagger-annotations:2.2.41 +- lombok:1.18.42 +- org.lionsoul-ip2region:3.1.0 +- springdoc-openapi-starter-webmvc-ui:2.8.14 + +#### 新增 + +- 添加 .editorconfig 文件以统一编码和行结束符设置。 + +#### 修复 + +- 代码生成设置中的业务名称修改后路由路径不生效问题。(感谢[lxwcv](https://github.com/lxwcv)) +- spring-doc 增加开关控制参数 `springdoc.api-docs.enabled` 和 `springdoc.swagger-ui.enabled`,生产环境建议关闭。 +- 更新ip2region 版本为3.1.0 RegionUtils 以支持 IPv4 地址库,改进 IP 地址库加载逻辑。 + +#### 修改 + +- 演示案例 - [教师统计] 增加富文本编辑器功能。 + +#### 优化 + +- 更新Dockerfile,安装curl支持容器内的健康检查。 +- [代码生成器] - 添加 jodit-editor 富文本编辑器的支持。 +- 代码模板 Dialog 弹窗组件添加动态宽度的支持。 + +--- + +### sz-admin + +### 依赖升级 + +- 对package.json文件中的依赖进行了兼容性升级。 + +#### 新增 + +- 新增:添加.editorconfig文件。 +- 富文本编辑器组件-JoditEditor。 +- 新增: useDialogWidth Hook 组件,实现弹窗/对话框宽度的动态自适应。 + +#### 重构 + +- [UploadFiles 组件] 增加多项功能并修正若干问题。 +- 角色管理-权限分配组件重构,提升交互体验。 + +#### 优化 + +- 权限组件,暗黑模式下的样式不适配的问题。 +- 多维选择器组件,暗黑模式下的样式不适配的问题。 +- 更新表格组件的 rowKey 属性为可选,并修复 radio 组件的类型问题。 + +#### 修复 + +- 更新protable组件部分类型问题。 + +#### 修改 + +- 演示案例 - 【教师统计】 增加富文本编辑器功能。 +- 【代码生成器】- 添加 jodit-editor 富文本编辑器的支持。 + +### 数据库变更 + +- 更新 `teacher_statistics` 表:增加`content_html`字段及演示数据。 +## v1.3.0-beta (20251109)| 大型更新 + +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1.3.0-beta) +> +> !存在潜在破坏性变更,请务必仔细阅读升级文档! +> +> **重要提示**:升级至本版本前,请先**清理 Redis 缓存**中的用户信息,否则可能因数据结构变更导致**登录异常**。 + +### sz-boot-parent + +#### 新增 + +- 支持 Spring Boot Actuator 监控。 +- login 相关密码传输支持 AES-GCM 加密,提升安全性。 +- 增加登录请求及验证码请求次数的限制配置。 +- [代码生成器] 支持多文件上传(fileUpload)。 +- [代码生成器] 支持数据权限创建。 +- 账户管理新增账户类型设置,支持超管账户指定。 +- 支持“超级管理员”角色参数配置。 + +#### 重构 + +- 破坏性变更:模板文件管理及下载等逻辑。 +- 破坏性变更:移除独立数据权限角色,合并至系统角色。 +- 破坏性变更:简化数据权限核心 SimplePermissionDialect,实现与处理流程更加清晰。 +- 破坏性变更:调整数据存储结构,login 相关方法引入 dataScope 缓存,移除 ruleMap、userRuleMap、deptRuleMap。因数据结构升级后可能需要清空redis缓存。 + +#### 修复 + +- 修复登录日志异步线程引发的记录异常。 +- 修复 IP 地址获取失败的问题。 +- 修复 Excel 导入时数据为空问题,移除代码模板中的 @Accessors(chain = true)。 +- 回退 FastExcel 版本至 1.2.0,解决部分 Excel 导出异常。 + +#### 修改/移除 + +- 移除生产环境配置中的 CORS 设置。 +- ImportExcel 方法支持数据库入库功能。 +- [演示案例] 教师统计,支持附件文件上传。 +- sys_data_role、sys_data_role_menu 相关业务标记为弃用,功能合并至 sys_role。 +- Dockerfile 镜像切换至 azul/zulu-openjdk(JDK 21)。 +- 移除 Flyway,数据库迁移已完全转至 liquibase。 + +#### 优化 + +- 登录列表倒序排序显示。 +- [代码生成器] 菜单按钮的查询与排序优化。 +- 修复[动态字典]部门、角色在 redisCache 中循环赋值导致的性能问题。 +- OSS 上传支持原始文件名元数据与特殊字符(如#)处理。 +- HttpReqResUtil 增加 getRequest 方法,支持全局 HttpServletRequest 获取。 +- StringUtils.getRealKey 方法增强字符串替换、null 处理与异常捕获。 + +--- + +### sz-admin + +#### 新增 + +- 新增 FileDownloadList 组件,实现 ProTable 中文件资源展示、支持多文件下载与预览、文件列表回显优化。 +- login 相关密码传输支持 AES-GCM 加密,提升安全性。 +- 账户管理支持账户类型设置,可直接指定管理员身份。 + +#### 重构 + +- [UploadFiles 组件] 增加多项功能并修正若干问题。 +- 角色管理-权限分配组件重构,提升交互体验。 + +#### 优化 + +- useDownload 组件优先采用 response header 中 filename 作为下载文件名。 +- 优化菜单表单的操作逻辑,新增提示说明。 +- 优化模板文件管理列表的文件操作列。 +- [ImportExcel] 增加模板信息展示及必填参数校验。 +- [file 组件] 优化 accept 文件类型检查,可选开启,默认不限制类型。 +- 文件下载和模板功能进一步优化,提升用户体验: + - 优化 useDownload Hook 的实现 + - 文件模板相关逻辑调整 + - 菜单 Form 表单增加提示性 tooltip + - 修正 blob 流响应拦截器的错误处理 + - 列表文件展示统一切换为 FileDownloadList 组件 + +#### 修复 + +- [ProTable] 因数据类型不匹配导致的列表字典项渲染样式异常。 + +#### 修改 + +- [演示案例] 教师统计,新增多文件上传及回显组件支持。 + +### 数据库变更 + +- 更新 `sys_menu` 表:优化菜单数据,采用更简洁的路由名称,并将原本在菜单上的查询权限提取为按钮级权限。 + +- 调整 `sys_role_menu` 表:新增字段 `permission_type`(权限类型,如功能权限、数据权限),新增字段 `data_scope_cd`(数据权限范围)。 + +- 更新 `sys_data_role_relation` 表:新增字段 `menu_id`,用于关联菜单。 + +- 表 `sys_data_role_menu`、`sys_data_role` 标记为**废弃**,相关业务已合并至 `sys_role` 和 `sys_data_role_relation` 表。 + +- 优化 `sys_temp_file`、`sys_temp_file_history` 表:将 `url` 字段类型调整为 JSON,并插入演示数据。 + +  !!注意:此更改会导致原有数据不兼容。 + +- `sys_temp_file` 表新增 `alias` 字段,用于标识文件别名。 + +- `sys_role`、`sys_role_menu`、`sys_data_role_relation`、`sys_user_role` 表补充及调整了演示数据。 + +> **升级建议**: +> +> - 建议在升级前做好数据和数据库结构的完整备份,以保障您的数据安全。 +> - 本次数据库结构及功能调整,可能影响部分旧数据兼容性及现有业务,请结合自身情况提前评估,并根据实际需求做好适配与数据处理。 +> - 欢迎在升级过程中通过社区或交流群反馈遇到的问题,我们也会积极协助答疑与经验分享。 + +## v1.2.6-beta (20250831) + +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1.2.6-beta) + +sz-boot-parent: + +- 依赖升级: + - **spring-boot-starter-parent:3.5.3 -> 3.5.5。** + - **mybatis-flex:1.11.0 -> 1.11.1。** + - software.amazon.awssdk:s3:2.31.78 -> 2.32.29。 + - fastexcel:1.2.0 -> 1.3.0。 + - io.swagger.core.v3-swagger-annotations:2.2.34 -> 2.2.36 + - jackson:2.19.0 -> 2.19.1 + - commons-lang3: 3.17.0 -> 3.18.0 + - HikariCP:6.3.0 -> 7.0.2 + - commons-io-commons-io:2.19.0 -> 2.20.0 + - jackson:2.19.1 -> 2.19.2 + - mysql-connector-j:9.3.0 -> 9.4.0 +- 新增: 新增部门角色设置功能,更新部门下所有用户的角色信息,实现用户在设置部门时自动继承部门角色权限 (感谢[liuce](https://github.com/nullPointer0123))。 +- 修复:增强WebSocket消息解析,添加错误处理。 +- 优化: 部门设置角色使用mybatisFlex链式操纵替换sql。 +- 新增:[动态字典] - 系统部门。 +- 新增:[动态字典] - 系统角色。 +- 优化:账号管理-部门、角色列展示查询。 +- 优化:部门管理-负责人查询。 +- 优化:部门管理-角色查询。 +- 优化:[代码生成器]- 添加Lombok @Accessors 的支持(感谢[liuce](https://github.com/nullPointer0123))。 +- 优化: [mysql.yml] - 指定 liquibase 版本表名,兼容不同环境表名大小写,避免版本控制失效。 +- 优化: [代码生成器] - 菜单管理SQL格式。 +- 新增:登录日志(感谢[liuce](https://github.com/nullPointer0123))。 + +sz-admin: + +- 新增: 新增部门角色设置功能,更新部门下所有用户的角色信息,实现用户在设置部门时自动继承部门角色权限(感谢[liuce](https://github.com/nullPointer0123))。 +- 优化:[ProTable-TableColumn组件] 支持多标签展示。 + + - 支持 tag=false 且 enum 配置时,自动翻译多值并逗号拼接展示。 + - 支持 tag=true 且 enum 配置时,多标签分组展示及收起。 + - 支持 tag 未设置且 enum 配置时,正常翻译多值展示。 + - 兼容多种数据格式(数组、逗号分隔字符串)。 + - 空值统一展示为 "--"。 + - 新增 tagLimit 属性说明:设置展示标签数量,超出部分通过 Popover 收起展示(tagLimit=-1 时展示全部标签,默认值tagLimit=3)。 +- 优化: 添加部门绑定角色提示,调整部门页面操作列宽(感谢[liuce](https://github.com/nullPointer0123))。 +- 新增: 添加登陆日志(感谢[liuce](https://github.com/nullPointer0123))。 +- 优化:账号管理-部门、角色列展示。 +- 优化:部门管理-负责人展示。 +- 优化:部门管理-角色展示。 + +## v1.2.5-beta (20250716) + +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1.2.5-beta) + + +- sz-boot-parent: + - 依赖升级: + - **spring-boot-starter-parent:3.5.0 -> 3.5.3。** + - **mybatis-flex:1.10.9 -> 1.11.0。** + - software.amazon.awssdk:s3:2.29.50 -> 2.31.78。 + - hutool-jwt:5.8.38 -> 5.8.39。 + - pagehelper:6.1.0 -> 6.1.1。 + - io.swagger.core.v3-swagger-annotations:2.2.32 -> 2.2.34 + - jackson:2.19.0 -> 2.19.1 + - commons-lang3: 3.17.0 -> 3.18.0 + - HikariCP:6.2.1 -> 6.3.0 + - commons-io-commons-io:2.18.0 -> 2.19.0 + - jackson:2.19.0 -> 2.19.1 + - modelmapper:3.2.3 -> 3.2.4 + - springdoc-springdoc-openapi-starter-webmvc-ui:2.8.8 -> 2.8.9 + - 优化:适配解决maven编译时无法识别Lombok和Mybatis-Flex APT注解器导致的”找不到符 + - 修复: 更正Excel最大columnWidth = 255 * 256。(Excel 中列宽(column width)最大值是 255 * 256 = 65280) + - 优化:[SQL] 查询用户具有的菜单。 + - 修复: 特殊情况下因用户session失效而导致的用户元数据同步失败的问题。 + - 修复:数据权限某些场景下导致page失效的问题。 + - 重构:字典加载器相关类的包结构和接口定义,优化动态字典加载逻辑。 + - 优化:JacksonConfiguration 全局配置文件;实现针对不同类型的 Jackson null 值序列化器。 + - String 类型 null → "" + - List/Set 类型 null → [] + - Map 类型 null → {} + - Other 类型 null → "" + - 优化:SysTempFileVO 添加 JacksonTypeHandler 以支持 url 字段的自定义序列化。 + - 优化: pom 文件中按需引入 knife4j,避免因多余依赖导致 WebSocket 服务可访问 knife4j 接口。 +- sz-admin: + + - 新增:[演示] 多维选择器组件。 + - 优化:上传组件,增加目录参数dir,更换上传接口。 + - 优化:downloadFile函数,将url类型由string改为string[]。 +- 文档: + + - 新增:[方案] [多数据源的实现](https://szadmin.cn/md/Help/doc/solution/multi-datasource.html)。 +## v1.2.4-beta (20250614) + +- sz-boot-parent: + + - 修复: 菜单路径和组件路径拼写错误"menuManage"。(感谢[Kang-Yang](https://github.com/Kang-Yang)) + - 修复:异常枚举类message方法并发问题。 + - 重构:将异常枚举类实现改为通用响应枚举模板。 + - 升级:sa-token v1.41.0 -> v1.44.0 && 同步改造。 +- sz-admin: + + - 修复: 菜单路径和组件路径拼写错误"menuManage"。(感谢[Kang-Yang](https://github.com/Kang-Yang)) + - 修复:账户管理批量设置部门后checkbox未重置的问题。 + - 优化:Grid组件,重构字段查找逻辑,提升性能和可读性。 + - 优化:ToolBarRight组件,修改展示项用户名为昵称。 + +## v1.2.3-beta (20250603) + +- sz-boot-parent: + + - 依赖升级: + - **spring-boot-starter-parent:3.4.4 -> 3.5.0。** + - software.amazon.awssdk.crt:aws-crt:0.33.7 -> 0.38.4。 + - software.amazon.awssdk:s3:2.29.50 -> 2.31.54。 + - hutool-jwt:5.8.34 -> 5.8.38。 + - fastexcel:1.1.0 -> 1.2.0。 + - mysql-mysql-connector-j: 9.2.0 -> 9.3.0 + - HikariCP:6.2.1 -> 6.3.0 + - commons-io-commons-io:2.18.0 -> 2.19.0 + - jackson:2.18.2 -> 2.19.0 + - springdoc-springdoc-openapi-starter-webmvc-ui:2.8.3 -> 2.8.8 + - org.aspectj-aspectjweaver:1.9.23 -> 1.9.24 + - modelmapper:3.2.2 -> 3.2.3 + - io.swagger.core.v3-swagger-annotations:2.2.27 -> 2.2.32 + - commons-collections4:4.4 -> 4.5.0 + - 优化:适配解决maven编译时无法识别Lombok和Mybatis-Flex APT注解器导致的”找不到符号“报错问题。 (感谢[JoeyFrancisTribbiani](https://github.com/JoeyFrancisTribbiani)) + - 修复:FastExcel 依赖 Apache POI漏洞。 + - 优化:logback.xml中`converterClass`已废弃,更换为新语法`class`。 + - 更新:com.diffplug.spotless-spotless-maven-plugin-2.44.5。 + - 优化:cicd 脚本,将admin和websocket合并成一个脚本。 + - 修改:多文件上传不再支持单字符串,统一改为JSON数组形式。 +- sz-admin: + + - 优化:多文件上传组件不再支持单字符串,统一改为数组形式。 + +## v1.2.2-beta (20250528) + +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1.2.2-beta) + +- sz-boot-parent: + + - 优化:将**继承** `WebMvcConfigurationSupport`改为**实现** `WebMvcConfigurer`,提升框架兼容性。 + - 修复:[数据权限]-一些已知问题。 + - 优化:[代码生成器] + - 导入数据表添加对createId/updateId/createTime/updateTime常用字段的支持。 + - 前端模版添加对useDict生成的支持 + - SQL Insert 支持IGNORE + - Teacher演示案例的同步改造 + - 代码模版格式优化 + - 新增: [sz-common-wechat]-新增企业微信消息发送的支持。 +- sz-admin: + + - 修复:版本号读取异常问题。 + - 优化:[演示案例] - 教师统计。 + - 优化:UploadFiles多文件上传组件, 简化使用方式并修复一些问题。 + +## v1.2.1-beta (20250509) + +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1.2.1-beta) + +- sz-boot-parent: + + - 新增:Liquibase数据库管理,弃用Flyway配置 (**Flyway 将于v1.3.0-beta 版本弃用**)。 + - 修改:已支持Liquibase,默认配置关闭Flyway(将于v1.3.0-beta版本弃用)。 + - 修复:部分菜单路由名称与组件名称不一致时导致的菜单keep-alive缓存失效问题。 + - 修改:README.md 添加deepwiki。感谢[dongyu6/main](https://github.com/dongyu6)。 + +- sz-admin: + + - 优化:.env环境变量,无需指定`.env.development.local `文件即可使用。 + - 升级:sass 1.79.6 -> 1.87.0, vite 5.4.17 -> 6.3.4,以及其他依赖的同步升级。 + - 修复:部分菜单路由名称与组件名称不一致时导致的菜单keep-alive缓存失效问题。 + - 修改:README.md 添加deepwiki。(感谢[dongyu6/main](https://github.com/dongyu6))。 + +## v1.2.0-beta (20250422) +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html#v1-2-0-beta) +- sz-boot-parent: + - 优化:[代码生成器] - 为生成代码增加是否忽略表前缀的功能。PR[#140](https://github.com/feiyuchuixue/sz-boot-parent/pull/140)(感谢[crash](https://github.com/processcrash))。 + - 优化:重构**数据权限**核心逻辑,修复部分问题。 + - 修复:[数据填充]-deptScope属性失败问题 + - 优化:Websocket相关:简化SocketMessage和TransferMessage类的泛型使用 + - 新增:系统消息功能 + - 新增:[演示] 消息发送接口 + - 新增:[CICD] Docker Sz-Socket CI Prod.yml + - 优化:提高用户元数据变更性能 +- sz-admin: + - 修复:滑块验证码在某些浏览器无法滑动的问题 + - 新增:分类筛选器组件 + - 优化:滑块验证码的耗时计算逻辑 + - 新增:系统消息功能(搭配Websocket可体验完整功能) + - 新增:功能演示 + - 新增:关于项目 + - 新增:全局菜单:[消息、功能演示菜、关于项目] + +## v1.1.0-beta (20250406) + +> [!NOTE] +> +> [升级指南](https://szadmin.cn/md/Help/doc/other/upgrade.html) + +- sz-boot-parent: + - 依赖升级: + - spring-boot-starter-parent:3.4.2 -> 3.4.4。 + - mybatis-flex.version:1.10.8 -> 1.10.9。 + - sa-token:1.40.0 -> 1.41.0。 + - swagger-annotations:2.2.27 -> 2.2.29。 + - aspectjweaver:1.9.22.10 -> 1.9.23。 + - springdoc-openapi-starter-webmvc-ui: 2.8.3 -> 2.8.6 + - aws-crt: 0.33.7 -> 0.37.0 + - HikariCP:6.2.1 -> 6.3.0 + - aws.s3:2.29.50 -> 2.31.11 + - 优化:[代码生成器] - 添加/api/types/*.ts生成模板 +- sz-admin: + - 升级:Eslint8.x -> Eslint9 + - 新增:`useDictOptions` Hook + - 优化:同步`useDictOptions` Hook写法 + - 修复:某些情况下部门树多选报错的问题 + - 优化:@import scss 官方已不推荐使用,修改为 @use + - 更新:pnpm 依赖 + +## v1.0.2-beta (20250302) + +- sz-boot-parent: + - 依赖升级: + - mybatis-flex.version:1.10.7 -> 1.10.8。 + - 优化:更新OSS配置,添加协议scheme支持并**弃用isHttps字段**。 + - 可能的破坏性更新: 请切换`isHttps=true/false"` 为` scheme="https/http"` + - 优化:重构isNotNull方法,支持更广泛的集合类型。 + - 优化:重构BeanCopyUtils以使用单例ModelMapper实例。 + - 优化:【代码生成器】添加将bigint类型映射成long Java类型处理。 + - 优化:在EntityChangeListener onInsert事件中添加对updateTime和updateId的初始设置。 + - 修复:Excel导出时Long类型在某些情况下报错的问题。 + - 新增:系统字典查询-根据类型查询接口。 +- sz-admin: + - 新增:[Hook] useDict 方法。(可使用此方法更新指定typeCode的字典缓存)。 + - 新增:[Hook] useDict 的演示案例。 + - 修改:删除字典接口注释。**Issue**[#11](https://github.com/feiyuchuixue/sz-admin/issues/11)(感谢[Kang-Yang](https://github.com/Kang-Yang))。 + - 修改:README中的地址更正。**Issue**[#12](https://github.com/feiyuchuixue/sz-admin/issues/12)(感谢[Kang-Yang](https://github.com/Kang-Yang))。 +## v1.0.1-beta (20250215) + +- sz-boot-parent: + - 依赖升级: + - spring-boot-starter-parent:3.4.1 -> 3.4.2。 + - mybatis-flex.version:1.10.5 -> 1.10.7。 + - sa-token:1.39.0 -> 1.40.0。 + - excel-fastexcel:1.0.0 -> 1.1.0。 + - mysql-connector-j:9.1.0 -> 9.2.0。 + - 优化:字典类型删除时同步清除缓存。 + - 优化:统一异常code规范,追加prefix。 + - 优化:指定目标账户密码修改后,触发“踢下线”功能。 + - 修改:菜单树增加返回参数。 + - 优化: 日志格式。**Issue**[#10](https://github.com/feiyuchuixue/sz-admin/issues/10)。(感谢[129duckflew](https://github.com/129duckflew))。 + - 新增:第三方开源库和许可证文件说明 +- sz-admin: + - 修复:无效Token响应码不一致的问题。 + - 修复:AES-GCM加密方法在某些场景(浏览器)不可用的问题(行为验证码)。 + - 优化:【代码生成器】- 生成信息中**上级菜单=目录**时与模块名的联动。 + - 新增:第三方开源库和许可证文件说明 +## v1.0.0-beta (20250128)| 大型更新 + +- sz-boot-parent: + - 优化:sonar 代码(质量)规范化 +- sz-admin: + - 优化:sonar 代码(质量)规范化 +## v0.9.0 (20250119) + +- sz-boot-parent: + - 优化:无效文件清理 + - 优化:javadoc 注释 + - 优化:[sz-service-websocket] 同步调整config路径至项目根目录下 + - 优化:qodana 代码(质量)规范化 +- sz-admin: + - 无 +## v0.8.8 (20250118) + +- sz-boot-parent: + - 修改:Jackson序列化添加对`MultipartFile`类型的支持。 + - 修改:`router.whitelist` 属性为Set结构。 + - 优化:系统用户更新时,同步更新缓存信息。 + - 优化:[行为验证码-滑块验证] 增加对double精度的支持。 + - 优化:接口白名单,删除非必要的放行接口。 + - 修复:aop日志打印的一些问题( http-topic.log)。 + - 修复:[代码生成器] 预览时插入按钮SQL问题。 + - 修复:EntityChangeListener 在处理未登录用户数据初始化时的异常问题。 + - 修复:验证码参数`sys.captcha.requestLimit`未启用时redis中仍然记录了次数的问题。 + - 修复:[部门管理] 上级部门为`根部门`时编辑校验未通过的问题。 + - 依赖升级: + - spotless-maven-plugin:2.43.0 -> 2.44.1。 + - mybatis-flex.version:1.10.2 -> 1.10.5。 + - aws.s3.version:2.29.23 -> 2.29.50。 + - springdoc-openapi-starter-webmvc-ui:2.7.0 -> 2.8.3。 + - modelmapper:3.2.1 -> 3.2.2。 + - swagger-annotations:2.2.26 -> 2.2.27。 +- sz-admin: + + - 修复:个别浏览器Socket异常的问题。 + - 优化:[行为验证码-滑块验证] 添加对移动端浏览器的支持。 +## v0.8.7 (20250109) + +- sz-boot-parent: + - 新增:`sz.cors.allowedOrigins`配置项,允许用户通过配置的方式指定限定域名 + - 修复:springboot启动时打印logback配置信息的问题 && 优化logback配置 + - 优化:接口防抖逻辑 + - 当全局设置忽略GET请求的参数为true时,如果GET请求的Controller未标注@Debounce注解,则跳过防抖处理;但若Controller标注了@Debounce注解,即使是GET请求,也会执行防抖逻辑。 + - 新增:行为验证码-滑块验证。感谢([阳纸伞](https://github.com/1327614618)) + - 新增:[演示案例] 远程搜索下拉选择组件 +- sz-admin: + + - 新增:行为验证码-滑块验证 + - 新增:远程搜索下拉选择组件 + - 新增:[演示案例] 远程搜索下拉选择组件 +## v0.8.6 (20250102) + +- sz-boot-parent: + - 修复: sys_config 缓存时间问题。 + - 修改: 移动配置文件至项目【根目录】下。| 可能的破坏性更新 + - 修改: 移除pom镜像源配置 + - 修改: Dockerfile 增加配置目录挂载的支持 + - 新增: GitHub Action workflow | +- sz-admin: + + - 修复:VITE自定义变量验证问题 + - 新增:gzip打包支持 + - 新增:Dockerfile + - 修改:.env.production 配置 + - 新增:GitHub Action workflow +## v0.8.5 (20241229) + +- sz-boot-parent: + - 优化:commons-logging 引用冲突问题。 + - 修复:部门编辑时层级deep赋值不正确问题。 + - 修复:前端module模板文件导入excel缺少参数问题。 + - 修复:部门列表节点数量展示问题。 + - 优化:升级EasyExcel为FastExcel。 | 可能的破坏性更新 (easyExcel -> fastExcel 的Package包切换) + - 优化:增强 Excel 导入异常处理,新增表头校验功能。详见[Excel导入导出](https://szadmin.cn/md/Help/doc/excel.html) + - 依赖升级: + - spring-boot-starter-parent:3.4.0 -> 3.4.1。 +- sz-admin: + + - 优化:文件上传模板组件样式。(感谢[Alex-1116](https://github.com/Alex-1116)) + - 优化:Excel导入组件,增加上传进度的支持。 + - 优化:axios对全局response error的处理。 +## v0.8.4 (20241216) + +- sz-boot-parent: + - 依赖升级: + - spring-boot-starter-parent:3.3.5 -> 3.4.0。 + - mybatis-flex.version:1.9.7 -> 1.10.2。 + - aws-crt:0.33.0 -> 0.33.3。 + - hutool-jwt:5.8.32 -> 5.8.34。 + - aws.s3:2.29.0 -> 2.29.23。 + - HikariCP:6.0.0 -> 6.2.1。 + - common-io:2.17.0 -> 2.18.0。 + - lombok:1.18.34 -> 1.18.36。 + - jackson:2.17.2 -> 2.18.2。 + - swagger-annotations:2.2.25 -> 2.2.26。 + - mysql-connector-j:9.0.0 -> 9.1.0。 + - 修改:SpringBoot升级3.4.0后对knife4j的兼容性处理 | 兼容性更新,springboot升级3.4.0后knife4增强默认需禁用!! + - 删除:minio dependency。 + - 优化:代码生成器查询。 **PR**[#57]([https://github.com/feiyuchuixue/sz-boot-parent/pull/57)。(感谢**[AiMing317](https://github.com/AiMing317)** )。 + - 优化:[代码生成器] 修复若干问题。 + - 新增:ossClient,新增oss文件流下载方法。 + - 优化:FileUtils 新增对response header的处理方法。 + - 优化:历史MapperXml/PO的结构映射。 + - 新增:模板文件管理模块。 +- sz-admin: + + - 优化:头像框样式。 + - 优化:代码生成器查询。 **PR**[#57]([https://github.com/feiyuchuixue/sz-boot-parent/pull/57)。(感谢**[AiMing317](https://github.com/AiMing317)** )。 + - 优化:Img、Imgs上传组件增加@change事件可获取完整的UploadResul。 + - 优化:[代码生成器] 修复一些问题,样式及便利性更新。 + - 优化:View.DefaultParams添加参数isAdd。可用于区分新增 OR 编辑。 + - 优化:useDownload组件!blob流式下载文件名从response中获取。 + - 新增:模板文件管理模块。 + - 修改:更新教师统计模板文件名。 + +## v0.8.3 (20241126) + +- sz-boot-parent: + + - **删除:minio模块。** | 可能的破坏性更新 + - 新增:oss模块,使用**AWS S3**协议,支持更多云存储厂商(阿里、七牛、腾讯、minio等)。 + - 修改:切换minio模块至oss模块,切换上传方法至ossClient。请将minio.yml文件切换为oss.yml。 + - 优化:移除冗余NotNull注解。 +- sz-admin: + + - 新增:文件管理。 + + - 修改:oss模块同步改动。 + + - 新增:vite-plugin-vue-devtools插件。 + + - 优化:完善UploadResult返回结构,优化文件代码格式。 + + - 新增:图片上传、批量图片上传组件 (感谢 **Geeker-Admin** https://github.com/HalseySpicy/Geeker-Admin)。 + + - 修改:切换用户头像上传为新的组件。 +- 文档: + + - [oss存储](https://szadmin.cn/md/Help/doc/oss.html) + +## v0.8.2 (20241119) + +- sz-boot-parent: + - 修复: 菜单详情页权限唯一值校验异常问题。 + - 修复: [代码生成] MySql5.7 导入表异常问题。 + - 新增: [代码生成] 对字典别名的支持。 + - 优化: 字典类型(sysDictType)增加缓存同步机制。 +- sz-admin: + - 修复:客户端管理列表,授权类型展示问题。 + - 新增:[代码生成] 对字典别名的支持。 + +## v0.8.1 (20241106) + +- sz-boot-parent: + - 依赖升级: + - spring-boot-starter-data-redis:3.3.4 -> 3.3.5。 + - spring-boot-starter-parent:3.3.4 -> 3.3.5。 + - 优化:sz-service-socket添加启动Banner与版本号。 + - 优化:部门列表-未设置部门节点用户数量查询逻辑调整 + - 优化:账户登录的查询。 + - 修复:excel导出字典CodeName为null时的异常问题。 + - 优化:Excel导入导出及字典转换,提升性能。 +- sz-admin: + - 优化: vite.config.mts更新 SCSS 预处理器配。 + - 优化: 锁定sass版本为~1.79.x版本。 + - 优化: tsconfig.app.json 增加package.json的支持。 + - 优化: 使用TypeScript的模块扩展,优化package.json 的version。 + - 优化: 增强 env.d.ts 文件中的类型定义。 + +- 文档: + + - [Excel导入导出](https://szadmin.cn/md/Help/doc/excel.html) + +## v0.8.0 (20241017) + +- sz-boot-parent: + - 依赖升级: + - spring-boot-starter-data-redis:3.3.3 -> 3.3.4。 + - 修复:sql预览模版结尾多余空格问题。 + - 修复:无法正常解锁用户问题 **PR**[#26](https://github.com/feiyuchuixue/sz-boot-parent/issues/26#issue-2577509320)。(感谢[andyjia](https://github.com/andyjia)) + - 优化:重构异常处理,引入错误前缀枚举,增强代码可读性和可维护。 + - 新增:spotless maven 格式化插件,全局格式化。 + - 新增:CHANGE.md 更新日志。 + - 修改:将数据表中的自增ID字段类型升级为**bigint**,以支持更大的数据范围和避免潜在的溢出问题。| 可能的破坏性更新 + - 优化:自增ID字段升级为bigint: + - 代码生成 + - 系统菜单 + - 系统字典 + - 角色 + - 用户 + - 教师统计(演示) + - 新增:自增ID字段升级为bigint DDL脚本。 + - 修复:部分页面批量删除异常问题。 + - 优化:[代码生成] 前端模版添加对(string | number)[] 类型的支持。 + - 优化:验证权限标识唯一性接口。 + - 优化:接口防抖增加GET请求忽略的支持。 + - 优化:通用返回接口对额外参数param的处理。 + - 优化:[代码生成] 模版对菜单预览SQL的调整。 + - 优化:数据库迁移脚本 --业务脚本 示例修改。 +- sz-admin: + - 依赖升级: + - **vite**:**4.5.3 -> 5.4.8**。 + - **axios**: 1.7.2 -> 1.7.7 + - **vue**:3.4.21 -> 3.5.12 + - pinia:2.1.7 -> 2.2.4 + - **vue-router**:**4.4.0 -> 4.4.5** + - sortablejs:1.15.2 -> 1.15.3 + - pinia-plugin-persistedstate: 3.2.1 -> 3.2.3 + - @vueuse/core:10.11.0 -> 10.11.1 + - prettier:3.3.2 -> 3.3.3 + - @types/node:18.19.39 -> 18.19.55 + - **element-plus**:**2.7.6 -> 2.8.5** + - **sass**:**1.77.7 -> 1.79.5** + - @vue/tsconfig:0.4.0 -> 0.5.1 + - vue-tsc:1.8.27 -> 2.1.6 + - 修复:菜单管理、字典管理 预览SQL的格式问题。 + - 修复:代码预览组件行号展示问题。 + - 优化: 更新API状态码常量。 + - 优化:提取请求超时时间参数**VITE_APP_HTTP_TIMEOUT** 单位ms,(默认超时时间60s)。 + - 优化: useSelection组件添加对number数组的支持。 + - 优化: 修改API参数类型以支持数字和字符串。 + - 优化: 角色标识展示样式。 + - 优化: vite5.x 使用ESM语法 vite.config.ts 升级为vite.config.mts。 + - 优化: eslintrc.cjs 规则。 + - 优化: prettier format配置。 + - 优化:代码格式化,代码清理。 + +## v0.7.11 (20241009) + +- sz-boot-parent: + - 依赖升级: + - spring-boot-starter-data-redis:3.3.3 -> 3.3.4。 + - 修复:sql预览模版结尾多余空格问题。 + - 修复:无法正常解锁用户问题 **PR**[#26](https://github.com/feiyuchuixue/sz-boot-parent/issues/26#issue-2577509320)。(感谢[andyjia](https://github.com/andyjia)) + - 优化:重构异常处理,引入错误前缀枚举,增强代码可读性和可维护。 + - 新增:spotless maven 格式化插件,全局格式化。 + - 新增:CHANGE.md 更新日志。 + - 修改:将数据表中的自增ID字段类型升级为**bigint**,以支持更大的数据范围和避免潜在的溢出问题。| 可能的破坏性更新 + - 优化:自增ID字段升级为bigint: + - 代码生成 + - 系统菜单 + - 系统字典 + - 角色 + - 用户 + - 教师统计(演示) + - 新增:自增ID字段升级为bigint DDL脚本。 + - 修复:部分页面批量删除异常问题。 + - 优化:[代码生成] 前端模版添加对(string | number)[] 类型的支持。 + - 优化:验证权限标识唯一性接口。 + - 优化:接口防抖增加GET请求忽略的支持。 + - 优化:通用返回接口对额外参数param的处理。 + - 优化:[代码生成] 模版对菜单预览SQL的调整。 + - 优化:数据库迁移脚本 --业务脚本 示例修改。 + +## v0.7.10 (20240919) + +- sz-boot-parent: + - 依赖升级: + - com.alibaba:easyexcel:4.0.2 -> 4.0.3。 + - 修复:某些情况下账户列表查询的分页问题。 + - 修复:数据权限组合拼接条件时OR、AND的优先级问题。 + - 新增:接口防抖功能。 + - 优化:sz自定义配置格式统一化。 +- sz-admin: + - 优化:WebSocket验证逻辑。 + - 优化:env环境变量。 + - 修复:dict接口登录时请求两次的问题。 + +## v0.7.9 (20240913) + +- sz-boot-parent: + - 依赖升级: + - org.apache.commons:commons-lang3:3.16.0 -> 3.17.0 + - swagger-annotations: 2.2.21 -> 2.2.23. + - org.aspectj:aspectjweaver:1.9.22 -> 1.9.22.1 + - mysql-connector-j: 8.4.0 -> 9.0.0 + - hutool-jwt: 5.8.31 -> 5.8.32 + - 新增:BeanCopyUtils 增加copy, copyNotIgnoreNull方法。 + - 优化:**数据权限**映射表名的获取规则:优先使用@Table注解名称属性。 + - 修复:角色管理标识空值校验问题。 + - 优化:[代码生成] 前端搜索项独立enum Select的支持。 + - 修复: @SaIgnore注解失效问题。 + - 优化: @SaIgnore的使用场景,[详见文档](https://szadmin.cn/md/Help/doc/code-standard.html#_9-%E6%8E%A5%E5%8F%A3%E9%89%B4%E6%9D%83) 。 + - 优化: 账户detail详情查询接口,排除敏感信息。 +- sz-admin: + - 优化:改造SearchForm组件,添加对enum的独立支持。(感谢[Alex-1116](https://github.com/Alex-1116)) + - 修改:[教师统计] searchColumns enum演示。 + +## v0.7.8 (20240902) + +- sz-boot-parent: + - 依赖升级: + - spring-boot-starter-parent:3.2.5 -> 3.3.3 + - jackson:2.16.1 -> 2.17.2 + - hutool-jwt:5.8.27 -> 5.8.31 + - easyexcel: 3.3.4 -> 4.0.2 + - aspectjweaver: 1.9.22 -> 1.9.22.1 + - commons-lang3:3.14.0 -> 3.16.0 + - mybatis-flex-spring-boot3-starter:1.9.3 -> 1.9.7 + - modelmapper:3.2.0 -> 3.2.1 + - minio:8.5.10 -> 8.5.12 + - sa-token:1.38.0 -> 1.39.0 + - 修复:代码生成,zip生成时流未关闭的问题。 + - 修复:ftl sql模板int类型参数自动转换千分位的问题。 + - 修复:字典更新问题。 + - 优化:类名、包结构。 + - 修改:MybatisFlex**禁用全局null值自动忽略**。代码生成器模版、部分业务查询拼接同步改动。|增强逻辑清晰和确定性。 +- sz-admin: + - 修改:客户端管理Form项描述错误 + - 优化:[代码生成] 编辑Form,字典类型下拉展示。区分静态字典和动态字典。(感谢[Alex-1116](https://github.com/Alex-1116)) + +## v0.7.7 (20240823) + +- sz-boot-parent: + - 优化:包结构及代码。 + - 修复:字典sql导出ID格式问题。 + - 修复:[代码生成] LocalDateTime范围查询Search区域展示异常问题。 + - 新增:字典改造,对静态字典、动态字典提供支持。 + - 优化:DictVO对象,完善字典查询sql增加对逻辑删除的支持。 + - 修改:SysUser 动态字典:用户信息的支持。 + - 优化:TeacherStatics演示示例,@DictFormat注解isSelected()的调整等。感谢[阳纸伞](https://github.com/1327614618)的贡献代码。 +- sz-admin: + - 优化:账户管理-切换部门列表时list接口请求两次额问题。 + +## v0.7.6 (20240814) + +- sz-boot-parent: + - 修复:[代码生成] excel导出条数与列表查询数不符的问题。 + - 修复:[代码生成] 关联字典的查询条件,生成类型为input而非select的问题。 + - 修复:[代码生成] 新增菜单类型【菜单】时,deep层级赋值不正确问题。 + - 优化:[代码生成] 代码生成逻辑,修复一些bug。 + - 优化:添加business业务Flyway README描述文件。 + - 优化:遵循jdk21建议,使用@Serial注解标识serialVersionUID。 + - 优化:角色增加is_lock, permissions属性。 + - 修复:字典菜单SQL查看时某些原因无法展示的问题。 +- sz-admin: + - 优化:代码生成字段类型添加描述。 + - 优化:角色管理增加标识属性(permissions)、锁定状态(is_lock)。 + +## v0.7.5 (20240812) + +- sz-boot-parent: + - 优化:账户新增时,如果选择了可用的部门,将账户创建到指定部门。 + - 新增:字典管理,SQL导出功能。 + - 优化:代码生成模板格式。 +- sz-admin: + - 修复:Header结构Avatar组件 默认头像展示问题。(感谢[Alex-1116](https://github.com/Alex-1116)) + - 优化: 代码生成HighCode组件 增加行号展示。(感谢[Alex-1116](https://github.com/Alex-1116)) + - 修复:账号管理 新增用户后 与部门列表的通讯问题。(感谢[Alex-1116](https://github.com/Alex-1116)) + - 优化:代码生成编辑操作 根据导入导出checkbox 动态展示对应columns。(感谢[Alex-1116](https://github.com/Alex-1116)) + - 优化:账户新增时,如果选择了可用的部门,将账户创建到指定部门下。 + - 新增:字典管理,SQL导出功能。 + - 修复:代码生成组件 行号 头部标题固定。(感谢[Alex-1116](https://github.com/Alex-1116)) + +## v0.7.4 (20240730) + +- sz-boot-parent: + - 优化:业务与框架Flyway迁移脚本分离 + + - 新增多 Flyway 实例配置,分别管理业务和框架迁移脚本。 + - 修改 `flyway.yml` 配置项,实现配置的清晰划分。 + - 利用 `@ConfigurationProperties` 自动绑定配置项,创建独立的 Flyway 实例 + - 各自使用独立的历史版本表(t_db_version 和 t_db_version_business)以避免相互干扰 + - 优化迁移管理,提高数据库版本管理的灵活性和扩展性 + - 更新了flyway的ddl脚本路径,在classpath:/db 路径下,新增framework、business路径,并**将原 classpath:/db 路径下 的DDL文件移动至 classpath:/db/framework下**。| 可能的破坏性更新 + + > [!IMPORTANT] + > + > - **重要通知:数据库迁移操作** + > + > 为了确保数据库迁移的顺利进行,我们特别提醒您注意以下步骤: + > + > 1. **迁移DDL脚本**:请将所有使用Flyway编写的自定义DDL(非框架提供的v1.1~v1.8版本)迁移脚本移动至`classpath:/db/business`目录下。 + > 2. **重新规划DDL版本**:在迁移脚本完成后,重新规划并更新DDL的版本号,确保版本控制的一致性和可追溯性。 + > 3. **数据备份**:**务必在执行迁移操作之前**,对现有数据库进行全面的数据备份。这是保障数据安全的关键步骤,避免在迁移过程中发生数据丢失或损坏的风险。 + > 4. **执行迁移操作**:在确认数据备份无误后,按照既定的迁移计划执行DDL迁移操作。 + +## v0.7.3 (20240728) + +- sz-boot-parent: + - 修复:部门逻辑删除后,account数据展示问题。 + - 优化:permission唯一性校验。 + - 新增:逻辑删除自动填充支持,delete_id,delete_time属性。 + - 优化:代码生成器,提取配置文件。 + - 优化:代码生成器,menu生成Sort逻辑。 + - 修复:预览时检查菜单重复的问题。 +- sz-admin: + - 优化:permission唯一性校验。 + - 优化:码生成器编辑Form表单的交互体验。 +- 官网文档: + - 新增:[代码生成器](https://szadmin.cn/md/Help/gen/generator-tools.html)文档。 +## v0.7.2 (20240719) + +> [!WARNING] +> +> **数据权限的session存储结构部分发生了改变,移除了customUserIds、customDeptIds。启用了userRuleMap、deptRuleMap来配合灵活的自定义规则。** + +- sz-boot-parent: + - 修改:数据权限,逻辑优化。减少用户操作,提升用户体验。 +- sz-admin: + + - 修改:数据权限Form,优化交互逻辑。 + - 修复:数据权限,编辑后再新增操作项disable的问题。 +- 官网文档: + + - 修改:[数据权限文档](https://szadmin.cn/md/Help/doc/data-scope.html) 对部分逻辑进行了简化。 + +## v0.7.1 (20240717) + +- sz-boot-parent: + + - 修复:代码生成pojo类注释名称问题 + + - 优化:用户管理功能,代码清理 + + - 修复:TreeUtils constructTreeRecursiveExcludeNode方法忽略指定节点不生效的问题 + + - 修复:AOP url参数解析异常问题 + + - 优化:文件清理,命名规范化 + + - 新增:StringUtils toSnakeCase方法 + + - **修改:字典管理,添加业务类型,区分系统字典、业务字典** | 可能的破坏性更新 + + > [!IMPORTANT] !重要 + > + > 1000号段为业务性字典,如有新增的字典请迁移至2000号段。受影响的字典类型值为“1006”、“1007”。 + + - 新增:数据权限实现 + +- sz-admin: + + - 优化:账户添加Form tooltip + - 修复:菜单缓存失效问题 [#IA8QI1](https://gitee.com/feiyuchuixue/sz-admin/issues/IA8QI1) | Gitee + - 优化:角色权限Form禁止esc关闭及点击其他区域关闭 + - 修复:socket参数不存在时仍连接socket的问题 + - 新增:数据字典-业务类型 + - 修复:默认头像无法展示问题 + - 修复:home页切换“分栏”布局报错问题 + - 修复:查询条件项在某些条件下无法展示全的问题 + - 优化:代码清理,规范化命名 + - 新增:数据权限 +- 官网文档: + + - 新增:[数据权限文档](https://szadmin.cn/md/Help/doc/data-scope.html) + + +## v0.6.5 (20240619) + +- sz-boot-parent: + - 修复:未登录状态接口自动数据填充异常问题 + - 修复:代码生成,批量删除异常问题 + - 升级:升级Mybatis-Flex版本v1.9.3 + +## v0.6.4 (20240612) + +- sz-boot-parent: + - 修复:权限问题orRole不生效的问题 [#IA4F9Z](https://gitee.com/feiyuchuixue/sz-boot-parent/issues/IA4F9Z) + - 新增:查询用户角色接口 +- sz-admin: + - 新增:权限校验(v-auth指令) 对超管角色的处理。env 新增 VITE_ADMIN_BYPASS_PERMISSION属性。 + +## v0.6.3 (20240609) + +- sz-boot-parent: + - 修复:代码生成器拖拽排序丢失问题 + - 优化:代码生成器-字段信息编辑模板调整,增加数据库模板 + - 优化:代码生成菜单唯一性检查逻辑 + - 修改: 升级Mybatis-Flex版本v1.9.2 +- sz-admin: + - 优化:代码生成器-字段信息编辑、生成信息编辑的操作逻辑 + - 优化:代码生成器-字段信息编辑 选择模板功能区,增加数据库模板选项,完善提示信息 + - 修复:ElMessage提示信息展示不在顶层的问题 + - 优化:页脚增加版本号展示 + +## v0.6.2 (20240605) + +- sz-boot-parent: + - 优化:将密码错误次数、错误冻结时间等魔法值提取到参数管理中 +- sz-admin: + - 优化:优化nginx推荐配置,解决网络原因导致socket频繁断开的问题 +- 官网文档: + - 新增:代码规范,前端代码提交前检查 + - 修改:序言,商业用途免费。 + - 优化:技术栈增加技术依赖超链接 + - 新增:websocket Nginx配置建议 + - 修改:感谢,对前端贡献者s1990218yao增加描述 + - 修改:页脚,增加友链 + +## v0.6.1 (20240603) + +- sz-boot-parent: + - 修改:admin账户初始密码为**sz123456** + - 优化:更新README文档 +- sz-admin: + - 修改:登陆页面placeholder + - 优化:更新README文档 + +---- + +## v0.6.0 (20240602) + +- sz-boot-parent: + - init +- sz-admin: + - init +- sz-deploy: + - init diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..55b0a72 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,128 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +feiyuchuixue@163.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct +enforcement ladder](https://github.com/mozilla/diversity). + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e7f5c6b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM azul/zulu-openjdk:21-latest +LABEL authors="sz" + +COPY *.jar app.jar +# 安装 curl, 用于蓝绿部署的容器健康检查等,并创建配置和日志目录 +RUN set -eux; \ + apt-get update && \ + apt-get install -y --no-install-recommends curl && \ + rm -rf /var/lib/apt/lists/* && \ + mkdir -p /config /logs + +ARG SPRING_PROFILES_ACTIVE + +# 声明挂载点(配置/日志) +VOLUME ["/config", "/logs"] + +ENTRYPOINT ["java", "-jar", "-Duser.timezone=Asia/Shanghai","-Dfile.encoding=UTF-8", "app.jar", "--spring.profiles.active=${SPRING_PROFILES_ACTIVE}"] \ No newline at end of file diff --git a/Knife4j访问地址 b/Knife4j访问地址 new file mode 100644 index 0000000..461b9ef --- /dev/null +++ b/Knife4j访问地址 @@ -0,0 +1,2 @@ +# api 文档地址 +http://127.0.0.1:9991/api/admin/doc.html# \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2cc1b6d --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2024] [升职哦(sz)] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/THIRD_PARTY_LICENSE.md b/THIRD_PARTY_LICENSE.md new file mode 100644 index 0000000..0bde9e8 --- /dev/null +++ b/THIRD_PARTY_LICENSE.md @@ -0,0 +1,697 @@ +# 第三方库和许可证 + +本项目中引用了以下第三方开源项目及其许可证信息: + +## 项目列表 + +### **[Geeker-Admin](https://github.com/HalseySpicy/Geeker-Admin)** + +- **仓库地址**: https://github.com/HalseySpicy/Geeker-Admin + +- **许可证类型**: MIT License + +- **许可证内容:** + + ``` + MIT License + + Copyright (c) 2022 Halsey + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + ``` + +### [Sa-Token](https://github.com/dromara/Sa-Token) + +- **仓库地址**: https://github.com/dromara/Sa-Token + +- **许可证类型**: Apache License 2.0 + +- **许可证内容:** + + ``` + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2011-2019 hubin. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ``` + +### **[mybatis-flex](https://github.com/mybatis-flex/mybatis-flex)** + +- **仓库地址**: https://github.com/mybatis-flex/mybatis-flex + +- **许可证类型**: Apache License 2.0 + +- **许可证内容:** + + ``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ``` + +### [knife4j](https://github.com/xiaoymin/knife4j) + +- **仓库地址**: https://github.com/xiaoymin/knife4j + +- **许可证类型**: Apache License 2.0 + +- **许可证内容:** + + ``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, and + distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by the copyright + owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all other entities + that control, are controlled by, or are under common control with that entity. + For the purposes of this definition, "control" means (i) the power, direct or + indirect, to cause the direction or management of such entity, whether by + contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity exercising + permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, including + but not limited to software source code, documentation source, and configuration + files. + + "Object" form shall mean any form resulting from mechanical transformation or + translation of a Source form, including but not limited to compiled object code, + generated documentation, and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or Object form, made + available under the License, as indicated by a copyright notice that is included + in or attached to the work (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object form, that + is based on (or derived from) the Work and for which the editorial revisions, + annotations, elaborations, or other modifications represent, as a whole, an + original work of authorship. For the purposes of this License, Derivative Works + shall not include works that remain separable from, or merely link (or bind by + name) to the interfaces of, the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including the original version + of the Work and any modifications or additions to that Work or Derivative Works + thereof, that is intentionally submitted to Licensor for inclusion in the Work + by the copyright owner or by an individual or Legal Entity authorized to submit + on behalf of the copyright owner. For the purposes of this definition, + "submitted" means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, and + issue tracking systems that are managed by, or on behalf of, the Licensor for + the purpose of discussing and improving the Work, but excluding communication + that is conspicuously marked or otherwise designated in writing by the copyright + owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity on behalf + of whom a Contribution has been received by Licensor and subsequently + incorporated within the Work. + + 2. Grant of Copyright License. + + Subject to the terms and conditions of this License, each Contributor hereby + grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the Work and such + Derivative Works in Source or Object form. + + 3. Grant of Patent License. + + Subject to the terms and conditions of this License, each Contributor hereby + grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, + irrevocable (except as stated in this section) patent license to make, have + made, use, offer to sell, sell, import, and otherwise transfer the Work, where + such license applies only to those patent claims licensable by such Contributor + that are necessarily infringed by their Contribution(s) alone or by combination + of their Contribution(s) with the Work to which such Contribution(s) was + submitted. If You institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work or a + Contribution incorporated within the Work constitutes direct or contributory + patent infringement, then any patent licenses granted to You under this License + for that Work shall terminate as of the date such litigation is filed. + + 4. Redistribution. + + You may reproduce and distribute copies of the Work or Derivative Works thereof + in any medium, with or without modifications, and in Source or Object form, + provided that You meet the following conditions: + + You must give any other recipients of the Work or Derivative Works a copy of + this License; and + You must cause any modified files to carry prominent notices stating that You + changed the files; and + You must retain, in the Source form of any Derivative Works that You distribute, + all copyright, patent, trademark, and attribution notices from the Source form + of the Work, excluding those notices that do not pertain to any part of the + Derivative Works; and + If the Work includes a "NOTICE" text file as part of its distribution, then any + Derivative Works that You distribute must include a readable copy of the + attribution notices contained within such NOTICE file, excluding those notices + that do not pertain to any part of the Derivative Works, in at least one of the + following places: within a NOTICE text file distributed as part of the + Derivative Works; within the Source form or documentation, if provided along + with the Derivative Works; or, within a display generated by the Derivative + Works, if and wherever such third-party notices normally appear. The contents of + the NOTICE file are for informational purposes only and do not modify the + License. You may add Your own attribution notices within Derivative Works that + You distribute, alongside or as an addendum to the NOTICE text from the Work, + provided that such additional attribution notices cannot be construed as + modifying the License. + You may add Your own copyright statement to Your modifications and may provide + additional or different license terms and conditions for use, reproduction, or + distribution of Your modifications, or for any such Derivative Works as a whole, + provided Your use, reproduction, and distribution of the Work otherwise complies + with the conditions stated in this License. + + 5. Submission of Contributions. + + Unless You explicitly state otherwise, any Contribution intentionally submitted + for inclusion in the Work by You to the Licensor shall be under the terms and + conditions of this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify the terms of + any separate license agreement you may have executed with Licensor regarding + such Contributions. + + 6. Trademarks. + + This License does not grant permission to use the trade names, trademarks, + service marks, or product names of the Licensor, except as required for + reasonable and customary use in describing the origin of the Work and + reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. + + Unless required by applicable law or agreed to in writing, Licensor provides the + Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, + including, without limitation, any warranties or conditions of TITLE, + NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are + solely responsible for determining the appropriateness of using or + redistributing the Work and assume any risks associated with Your exercise of + permissions under this License. + + 8. Limitation of Liability. + + In no event and under no legal theory, whether in tort (including negligence), + contract, or otherwise, unless required by applicable law (such as deliberate + and grossly negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, incidental, + or consequential damages of any character arising as a result of this License or + out of the use or inability to use the Work (including but not limited to + damages for loss of goodwill, work stoppage, computer failure or malfunction, or + any and all other commercial damages or losses), even if such Contributor has + been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. + + While redistributing the Work or Derivative Works thereof, You may choose to + offer, and charge a fee for, acceptance of support, warranty, indemnity, or + other liability obligations and/or rights consistent with this License. However, + in accepting such obligations, You may act only on Your own behalf and on Your + sole responsibility, not on behalf of any other Contributor, and only if You + agree to indemnify, defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason of your + accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work + + To apply the Apache License to your work, attach the following boilerplate + notice, with the fields enclosed by brackets "{}" replaced with your own + identifying information. (Don't include the brackets!) The text should be + enclosed in the appropriate comment syntax for the file format. We also + recommend that a file or class name and description of purpose be included on + the same "printed page" as the copyright notice for easier identification within + third-party archives. + + Copyright 2017 小明 + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ``` + +### [fastexcel](https://github.com/fast-excel/fastexcel) + +- **仓库地址**: https://github.com/fast-excel/fastexcel +- **许可证类型**: MIT License +- **许可证内容:** + + ``` + MIT License + + Copyright (c) 2024 CodePhiliaX + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + ``` + +## 其他 + +请确保您遵循每个项目的许可证要求,并在必要时进行相应的说明和归属。 \ No newline at end of file diff --git a/config/dev/knife4j.yml b/config/dev/knife4j.yml new file mode 100644 index 0000000..01b881b --- /dev/null +++ b/config/dev/knife4j.yml @@ -0,0 +1,30 @@ +# swagger文档配置 +knife4j: + enable: false + setting: + language: zh_cn +springdoc: + default-flat-param-object: true + swagger-ui: + # 是否开启swagger-ui,【生产环境】建议关闭 + enabled: true + path: /swagger-ui.html + tags-sorter: alpha + operations-sorter: alpha· + api-docs: + # 是否开启api-docs,【生产环境】建议关闭 + enabled: true + path: /v3/api-docs + group-configs: + - group: 'admin' + paths-to-match: '/**' + packages-to-scan: com.sz.admin + - group: 'generator工具' + paths-to-match: '/**' + packages-to-scan: com.sz.generator + - group: 'www网站' + paths-to-match: '/**' + packages-to-scan: com.sz.www + - group: '微信小程序' + paths-to-match: '/**' + packages-to-scan: com.sz.applet diff --git a/config/dev/mybatis-flex.yml b/config/dev/mybatis-flex.yml new file mode 100644 index 0000000..d65e6d0 --- /dev/null +++ b/config/dev/mybatis-flex.yml @@ -0,0 +1,11 @@ +mybatis-flex: + configuration: + map-underscore-to-camel-case: true + jdbc-type-for-null: null + auto-mapping-behavior: full + auto-mapping-unknown-column-behavior: none + cache-enabled: false + global-config: + deleted-value-of-logic-delete: "T" + normal-value-of-logic-delete: "F" + diff --git a/config/dev/mysql.yml b/config/dev/mysql.yml new file mode 100644 index 0000000..8f0134a --- /dev/null +++ b/config/dev/mysql.yml @@ -0,0 +1,28 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/sz_admin_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: Yanfa2023@ + hikari: + #连接池名 + pool-name: HikariCP + #最小空闲连接数 + minimum-idle: 5 + # 空闲连接存活最大时间,默认10分钟 + idle-timeout: 600000 + # 连接池最大连接数,默认是10 + maximum-pool-size: 10 + # 此属性控制从池返回的连接的默认自动提交行为,默认值:true + auto-commit: true + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + max-lifetime: 1800000 + # 数据库连接超时时间,默认30秒 + connection-timeout: 30000 + # 连接测试query + connection-test-query: SELECT 1 + liquibase: + change-log: classpath:db/changelog/changelog-master.xml + enabled: true + database-change-log-lock-table: databasechangeloglock + database-change-log-table: databasechangelog \ No newline at end of file diff --git a/config/dev/oss.yml b/config/dev/oss.yml new file mode 100644 index 0000000..131dc7c --- /dev/null +++ b/config/dev/oss.yml @@ -0,0 +1,12 @@ +oss: + # 支持S3协议的厂商 + provider: MINIO + endpoint: 192.168.56.101:9000 + accessKey: a4jtJvgEmk4ead5dzac6 + secretKey: UW6kxTGRetIAahV759rFkgoQ8ilXLRUMW0ULdIoo + bucketName: test + richtextBucketName: static + domain: http://192.168.56.101:9000 + # 命名方式: UUID、ORIGINAL原文件名偏好,冲突会补充时间 + naming: original + scheme: https \ No newline at end of file diff --git a/config/dev/page-helper.yml b/config/dev/page-helper.yml new file mode 100644 index 0000000..6195e2b --- /dev/null +++ b/config/dev/page-helper.yml @@ -0,0 +1,5 @@ +page-helper: + helperDialect: mysql + reasonable: false + supportMethodsArguments: true + params: count=countSql \ No newline at end of file diff --git a/config/dev/redis.yml b/config/dev/redis.yml new file mode 100644 index 0000000..13623e0 --- /dev/null +++ b/config/dev/redis.yml @@ -0,0 +1,28 @@ +# redis +spring: + data: + redis: + #单机配置 + host: 127.0.0.1 + port: 6379 + # 数据索引 + database: 0 + # 连接超时时间(毫秒) + timeout: 50000 + ###连接池配置### + jedis: + pool: + # 连接池最大连接数(使用负值表示没有限制) + max-active: 100 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1 + # 连接池中的最大空闲连接 + max-idle: 30 + # 连接池中的最小空闲连接 + min-idle: 10 + password: 123456 + +# 开启redis监听 +redis: + listener: + enable: true \ No newline at end of file diff --git a/config/dev/sa-token.yml b/config/dev/sa-token.yml new file mode 100644 index 0000000..fef73d1 --- /dev/null +++ b/config/dev/sa-token.yml @@ -0,0 +1,44 @@ +# sa-token +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否开启自动续签 + auto-renew: true + # token固定超时 设为七天 (必定过期) 单位: 秒 + timeout: 604800 + # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义 + # token最低活跃时间 (指定时间无操作就过期) 单位: 秒 + active-timeout: 86400 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: uuid + # 是否输出操作日志 + is-log: true + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + # 允许动态设置 token 有效期 + dynamic-active-timeout: true + # 允许从 请求参数 读取 token + is-read-body: false + # 允许从 header 读取 token + is-read-header: true + # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险 + is-read-cookie: false + # token前缀 + token-prefix: "Bearer" + # 同一账号最大登录数量,-1代表不限 + max-login-count: -1 +# 接口白名单 +router: + whitelist: + - "/v3/api-docs/**" + - "/doc.html" + - "/webjars/**" + - "/swagger-resources" + - "/favicon.ico" + - "/swagger-ui.html" + - "/www/**" + - "/wechat/**" \ No newline at end of file diff --git a/config/local/edgeBox.yml b/config/local/edgeBox.yml new file mode 100644 index 0000000..6447f68 --- /dev/null +++ b/config/local/edgeBox.yml @@ -0,0 +1,6 @@ +edgeBox: + connectTimeout: 8 + readTimeout: 10 + maxIdleConnections: 16 + keepAliveDuration: 5 + diff --git a/config/local/knife4j.yml b/config/local/knife4j.yml new file mode 100644 index 0000000..01b881b --- /dev/null +++ b/config/local/knife4j.yml @@ -0,0 +1,30 @@ +# swagger文档配置 +knife4j: + enable: false + setting: + language: zh_cn +springdoc: + default-flat-param-object: true + swagger-ui: + # 是否开启swagger-ui,【生产环境】建议关闭 + enabled: true + path: /swagger-ui.html + tags-sorter: alpha + operations-sorter: alpha· + api-docs: + # 是否开启api-docs,【生产环境】建议关闭 + enabled: true + path: /v3/api-docs + group-configs: + - group: 'admin' + paths-to-match: '/**' + packages-to-scan: com.sz.admin + - group: 'generator工具' + paths-to-match: '/**' + packages-to-scan: com.sz.generator + - group: 'www网站' + paths-to-match: '/**' + packages-to-scan: com.sz.www + - group: '微信小程序' + paths-to-match: '/**' + packages-to-scan: com.sz.applet diff --git a/config/local/mybatis-flex.yml b/config/local/mybatis-flex.yml new file mode 100644 index 0000000..d65e6d0 --- /dev/null +++ b/config/local/mybatis-flex.yml @@ -0,0 +1,11 @@ +mybatis-flex: + configuration: + map-underscore-to-camel-case: true + jdbc-type-for-null: null + auto-mapping-behavior: full + auto-mapping-unknown-column-behavior: none + cache-enabled: false + global-config: + deleted-value-of-logic-delete: "T" + normal-value-of-logic-delete: "F" + diff --git a/config/local/mysql.yml b/config/local/mysql.yml new file mode 100644 index 0000000..e0bf6bc --- /dev/null +++ b/config/local/mysql.yml @@ -0,0 +1,28 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/sz_admin_preview?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: 123456 + hikari: + #连接池名 + pool-name: HikariCP + #最小空闲连接数 + minimum-idle: 5 + # 空闲连接存活最大时间,默认10分钟 + idle-timeout: 600000 + # 连接池最大连接数,默认是10 + maximum-pool-size: 10 + # 此属性控制从池返回的连接的默认自动提交行为,默认值:true + auto-commit: true + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + max-lifetime: 1800000 + # 数据库连接超时时间,默认30秒 + connection-timeout: 30000 + # 连接测试query + connection-test-query: SELECT 1 + liquibase: + change-log: classpath:db/changelog/changelog-master.xml + enabled: true + database-change-log-lock-table: databasechangeloglock + database-change-log-table: databasechangelog \ No newline at end of file diff --git a/config/local/oss.yml b/config/local/oss.yml new file mode 100644 index 0000000..bfb2467 --- /dev/null +++ b/config/local/oss.yml @@ -0,0 +1,14 @@ +oss: + # 支持S3协议的厂商 + provider: MINIO + endpoint: 192.168.56.101:9000 + accessKey: a4jtJvgEmk4ead5dzac6 + secretKey: UW6kxTGRetIAahV759rFkgoQ8ilXLRUMW0ULdIoo + # 全局存储桶,偏私有存储 + bucketName: test + domain: http://192.168.56.101:9000 + # 富文本专用存储桶,偏公用存储 + richtextBucketName: static + # 命名方式: UUID、ORIGINAL原文件名偏好,冲突会补充时间 + naming: original + scheme: http \ No newline at end of file diff --git a/config/local/page-helper.yml b/config/local/page-helper.yml new file mode 100644 index 0000000..6195e2b --- /dev/null +++ b/config/local/page-helper.yml @@ -0,0 +1,5 @@ +page-helper: + helperDialect: mysql + reasonable: false + supportMethodsArguments: true + params: count=countSql \ No newline at end of file diff --git a/config/local/redis.yml b/config/local/redis.yml new file mode 100644 index 0000000..13623e0 --- /dev/null +++ b/config/local/redis.yml @@ -0,0 +1,28 @@ +# redis +spring: + data: + redis: + #单机配置 + host: 127.0.0.1 + port: 6379 + # 数据索引 + database: 0 + # 连接超时时间(毫秒) + timeout: 50000 + ###连接池配置### + jedis: + pool: + # 连接池最大连接数(使用负值表示没有限制) + max-active: 100 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1 + # 连接池中的最大空闲连接 + max-idle: 30 + # 连接池中的最小空闲连接 + min-idle: 10 + password: 123456 + +# 开启redis监听 +redis: + listener: + enable: true \ No newline at end of file diff --git a/config/local/sa-token.yml b/config/local/sa-token.yml new file mode 100644 index 0000000..fef73d1 --- /dev/null +++ b/config/local/sa-token.yml @@ -0,0 +1,44 @@ +# sa-token +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否开启自动续签 + auto-renew: true + # token固定超时 设为七天 (必定过期) 单位: 秒 + timeout: 604800 + # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义 + # token最低活跃时间 (指定时间无操作就过期) 单位: 秒 + active-timeout: 86400 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: uuid + # 是否输出操作日志 + is-log: true + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + # 允许动态设置 token 有效期 + dynamic-active-timeout: true + # 允许从 请求参数 读取 token + is-read-body: false + # 允许从 header 读取 token + is-read-header: true + # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险 + is-read-cookie: false + # token前缀 + token-prefix: "Bearer" + # 同一账号最大登录数量,-1代表不限 + max-login-count: -1 +# 接口白名单 +router: + whitelist: + - "/v3/api-docs/**" + - "/doc.html" + - "/webjars/**" + - "/swagger-resources" + - "/favicon.ico" + - "/swagger-ui.html" + - "/www/**" + - "/wechat/**" \ No newline at end of file diff --git a/config/local/zlmediakit.yml b/config/local/zlmediakit.yml new file mode 100644 index 0000000..e9988fe --- /dev/null +++ b/config/local/zlmediakit.yml @@ -0,0 +1,10 @@ +ZLMediaKit: + ip: 192.168.2.128 + port: 8080 + app: live + vhost: __defaultVhost__ + secret: liuzheng + connectTimeout: 8 + readTimeout: 10 + maxIdleConnections: 16 + keepAliveDuration: 5 \ No newline at end of file diff --git a/config/preview/knife4j.yml b/config/preview/knife4j.yml new file mode 100644 index 0000000..01b881b --- /dev/null +++ b/config/preview/knife4j.yml @@ -0,0 +1,30 @@ +# swagger文档配置 +knife4j: + enable: false + setting: + language: zh_cn +springdoc: + default-flat-param-object: true + swagger-ui: + # 是否开启swagger-ui,【生产环境】建议关闭 + enabled: true + path: /swagger-ui.html + tags-sorter: alpha + operations-sorter: alpha· + api-docs: + # 是否开启api-docs,【生产环境】建议关闭 + enabled: true + path: /v3/api-docs + group-configs: + - group: 'admin' + paths-to-match: '/**' + packages-to-scan: com.sz.admin + - group: 'generator工具' + paths-to-match: '/**' + packages-to-scan: com.sz.generator + - group: 'www网站' + paths-to-match: '/**' + packages-to-scan: com.sz.www + - group: '微信小程序' + paths-to-match: '/**' + packages-to-scan: com.sz.applet diff --git a/config/preview/mybatis-flex.yml b/config/preview/mybatis-flex.yml new file mode 100644 index 0000000..be8de79 --- /dev/null +++ b/config/preview/mybatis-flex.yml @@ -0,0 +1,10 @@ +mybatis-flex: + configuration: + map-underscore-to-camel-case: true + jdbc-type-for-null: null + auto-mapping-behavior: full + auto-mapping-unknown-column-behavior: none + cache-enabled: false + global-config: + deleted-value-of-logic-delete: "T" + normal-value-of-logic-delete: "F" diff --git a/config/preview/mysql.yml b/config/preview/mysql.yml new file mode 100644 index 0000000..8f0134a --- /dev/null +++ b/config/preview/mysql.yml @@ -0,0 +1,28 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/sz_admin_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: Yanfa2023@ + hikari: + #连接池名 + pool-name: HikariCP + #最小空闲连接数 + minimum-idle: 5 + # 空闲连接存活最大时间,默认10分钟 + idle-timeout: 600000 + # 连接池最大连接数,默认是10 + maximum-pool-size: 10 + # 此属性控制从池返回的连接的默认自动提交行为,默认值:true + auto-commit: true + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + max-lifetime: 1800000 + # 数据库连接超时时间,默认30秒 + connection-timeout: 30000 + # 连接测试query + connection-test-query: SELECT 1 + liquibase: + change-log: classpath:db/changelog/changelog-master.xml + enabled: true + database-change-log-lock-table: databasechangeloglock + database-change-log-table: databasechangelog \ No newline at end of file diff --git a/config/preview/oss.yml b/config/preview/oss.yml new file mode 100644 index 0000000..131dc7c --- /dev/null +++ b/config/preview/oss.yml @@ -0,0 +1,12 @@ +oss: + # 支持S3协议的厂商 + provider: MINIO + endpoint: 192.168.56.101:9000 + accessKey: a4jtJvgEmk4ead5dzac6 + secretKey: UW6kxTGRetIAahV759rFkgoQ8ilXLRUMW0ULdIoo + bucketName: test + richtextBucketName: static + domain: http://192.168.56.101:9000 + # 命名方式: UUID、ORIGINAL原文件名偏好,冲突会补充时间 + naming: original + scheme: https \ No newline at end of file diff --git a/config/preview/page-helper.yml b/config/preview/page-helper.yml new file mode 100644 index 0000000..6195e2b --- /dev/null +++ b/config/preview/page-helper.yml @@ -0,0 +1,5 @@ +page-helper: + helperDialect: mysql + reasonable: false + supportMethodsArguments: true + params: count=countSql \ No newline at end of file diff --git a/config/preview/redis.yml b/config/preview/redis.yml new file mode 100644 index 0000000..13623e0 --- /dev/null +++ b/config/preview/redis.yml @@ -0,0 +1,28 @@ +# redis +spring: + data: + redis: + #单机配置 + host: 127.0.0.1 + port: 6379 + # 数据索引 + database: 0 + # 连接超时时间(毫秒) + timeout: 50000 + ###连接池配置### + jedis: + pool: + # 连接池最大连接数(使用负值表示没有限制) + max-active: 100 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1 + # 连接池中的最大空闲连接 + max-idle: 30 + # 连接池中的最小空闲连接 + min-idle: 10 + password: 123456 + +# 开启redis监听 +redis: + listener: + enable: true \ No newline at end of file diff --git a/config/preview/sa-token.yml b/config/preview/sa-token.yml new file mode 100644 index 0000000..fef73d1 --- /dev/null +++ b/config/preview/sa-token.yml @@ -0,0 +1,44 @@ +# sa-token +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否开启自动续签 + auto-renew: true + # token固定超时 设为七天 (必定过期) 单位: 秒 + timeout: 604800 + # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义 + # token最低活跃时间 (指定时间无操作就过期) 单位: 秒 + active-timeout: 86400 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: uuid + # 是否输出操作日志 + is-log: true + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + # 允许动态设置 token 有效期 + dynamic-active-timeout: true + # 允许从 请求参数 读取 token + is-read-body: false + # 允许从 header 读取 token + is-read-header: true + # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险 + is-read-cookie: false + # token前缀 + token-prefix: "Bearer" + # 同一账号最大登录数量,-1代表不限 + max-login-count: -1 +# 接口白名单 +router: + whitelist: + - "/v3/api-docs/**" + - "/doc.html" + - "/webjars/**" + - "/swagger-resources" + - "/favicon.ico" + - "/swagger-ui.html" + - "/www/**" + - "/wechat/**" \ No newline at end of file diff --git a/config/prod/knife4j.yml b/config/prod/knife4j.yml new file mode 100644 index 0000000..f6b3044 --- /dev/null +++ b/config/prod/knife4j.yml @@ -0,0 +1,30 @@ +# swagger文档配置 +knife4j: + enable: false + setting: + language: zh_cn +springdoc: + default-flat-param-object: true + swagger-ui: + # 是否开启swagger-ui,【生产环境】建议关闭 + enabled: false + path: /swagger-ui.html + tags-sorter: alpha + operations-sorter: alpha· + api-docs: + # 是否开启api-docs,【生产环境】建议关闭 + enabled: false + path: /v3/api-docs + group-configs: + - group: 'admin' + paths-to-match: '/**' + packages-to-scan: com.sz.admin + - group: 'generator工具' + paths-to-match: '/**' + packages-to-scan: com.sz.generator + - group: 'www网站' + paths-to-match: '/**' + packages-to-scan: com.sz.www + - group: '微信小程序' + paths-to-match: '/**' + packages-to-scan: com.sz.applet diff --git a/config/prod/mybatis-flex.yml b/config/prod/mybatis-flex.yml new file mode 100644 index 0000000..be8de79 --- /dev/null +++ b/config/prod/mybatis-flex.yml @@ -0,0 +1,10 @@ +mybatis-flex: + configuration: + map-underscore-to-camel-case: true + jdbc-type-for-null: null + auto-mapping-behavior: full + auto-mapping-unknown-column-behavior: none + cache-enabled: false + global-config: + deleted-value-of-logic-delete: "T" + normal-value-of-logic-delete: "F" diff --git a/config/prod/mysql.yml b/config/prod/mysql.yml new file mode 100644 index 0000000..8f0134a --- /dev/null +++ b/config/prod/mysql.yml @@ -0,0 +1,28 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/sz_admin_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true + username: root + password: Yanfa2023@ + hikari: + #连接池名 + pool-name: HikariCP + #最小空闲连接数 + minimum-idle: 5 + # 空闲连接存活最大时间,默认10分钟 + idle-timeout: 600000 + # 连接池最大连接数,默认是10 + maximum-pool-size: 10 + # 此属性控制从池返回的连接的默认自动提交行为,默认值:true + auto-commit: true + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + max-lifetime: 1800000 + # 数据库连接超时时间,默认30秒 + connection-timeout: 30000 + # 连接测试query + connection-test-query: SELECT 1 + liquibase: + change-log: classpath:db/changelog/changelog-master.xml + enabled: true + database-change-log-lock-table: databasechangeloglock + database-change-log-table: databasechangelog \ No newline at end of file diff --git a/config/prod/oss.yml b/config/prod/oss.yml new file mode 100644 index 0000000..131dc7c --- /dev/null +++ b/config/prod/oss.yml @@ -0,0 +1,12 @@ +oss: + # 支持S3协议的厂商 + provider: MINIO + endpoint: 192.168.56.101:9000 + accessKey: a4jtJvgEmk4ead5dzac6 + secretKey: UW6kxTGRetIAahV759rFkgoQ8ilXLRUMW0ULdIoo + bucketName: test + richtextBucketName: static + domain: http://192.168.56.101:9000 + # 命名方式: UUID、ORIGINAL原文件名偏好,冲突会补充时间 + naming: original + scheme: https \ No newline at end of file diff --git a/config/prod/page-helper.yml b/config/prod/page-helper.yml new file mode 100644 index 0000000..6195e2b --- /dev/null +++ b/config/prod/page-helper.yml @@ -0,0 +1,5 @@ +page-helper: + helperDialect: mysql + reasonable: false + supportMethodsArguments: true + params: count=countSql \ No newline at end of file diff --git a/config/prod/redis.yml b/config/prod/redis.yml new file mode 100644 index 0000000..13623e0 --- /dev/null +++ b/config/prod/redis.yml @@ -0,0 +1,28 @@ +# redis +spring: + data: + redis: + #单机配置 + host: 127.0.0.1 + port: 6379 + # 数据索引 + database: 0 + # 连接超时时间(毫秒) + timeout: 50000 + ###连接池配置### + jedis: + pool: + # 连接池最大连接数(使用负值表示没有限制) + max-active: 100 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1 + # 连接池中的最大空闲连接 + max-idle: 30 + # 连接池中的最小空闲连接 + min-idle: 10 + password: 123456 + +# 开启redis监听 +redis: + listener: + enable: true \ No newline at end of file diff --git a/config/prod/sa-token.yml b/config/prod/sa-token.yml new file mode 100644 index 0000000..fef73d1 --- /dev/null +++ b/config/prod/sa-token.yml @@ -0,0 +1,44 @@ +# sa-token +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否开启自动续签 + auto-renew: true + # token固定超时 设为七天 (必定过期) 单位: 秒 + timeout: 604800 + # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义 + # token最低活跃时间 (指定时间无操作就过期) 单位: 秒 + active-timeout: 86400 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: uuid + # 是否输出操作日志 + is-log: true + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + # 允许动态设置 token 有效期 + dynamic-active-timeout: true + # 允许从 请求参数 读取 token + is-read-body: false + # 允许从 header 读取 token + is-read-header: true + # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险 + is-read-cookie: false + # token前缀 + token-prefix: "Bearer" + # 同一账号最大登录数量,-1代表不限 + max-login-count: -1 +# 接口白名单 +router: + whitelist: + - "/v3/api-docs/**" + - "/doc.html" + - "/webjars/**" + - "/swagger-resources" + - "/favicon.ico" + - "/swagger-ui.html" + - "/www/**" + - "/wechat/**" \ No newline at end of file diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..796f49f --- /dev/null +++ b/lombok.config @@ -0,0 +1,3 @@ +config.stopBubbling=true +# 解决子类警告:Generating equals/hashCode implementation but without a call to superclass +lombok.equalsAndHashCode.callSuper=call \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..714804c --- /dev/null +++ b/pom.xml @@ -0,0 +1,134 @@ + + + 4.0.0 + + com.sz + sz-boot-parent + pom + + sz-common + sz-service + sz-dependencies + + + com.sz + sz-build + ${revision} + ./sz-build/pom.xml + + + + 21 + 21 + 21 + true + + + + + + com.sz + sz-dependencies + ${project.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.projectlombok + lombok + + + io.swagger.core.v3 + swagger-annotations + + + + + + + + + com.diffplug.spotless + spotless-maven-plugin + 2.44.5 + + + UTF-8 + + sz-build/baeldung-style.xml + + + + + + + + \ No newline at end of file diff --git a/sz-build/baeldung-style.xml b/sz-build/baeldung-style.xml new file mode 100644 index 0000000..7037691 --- /dev/null +++ b/sz-build/baeldung-style.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sz-build/pom.xml b/sz-build/pom.xml new file mode 100644 index 0000000..cf23a65 --- /dev/null +++ b/sz-build/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.5.5 + + + + com.sz + sz-build + pom + ${revision} + + + + 1.3.2-beta-SNAPSHOT + + + \ No newline at end of file diff --git a/sz-common/pom.xml b/sz-common/pom.xml new file mode 100644 index 0000000..fe33c3c --- /dev/null +++ b/sz-common/pom.xml @@ -0,0 +1,28 @@ + + + + sz-boot-parent + com.sz + ${revision} + + 4.0.0 + + sz-common + pom + + sz-common-core + sz-common-db-mongodb + sz-common-db-mysql + sz-common-db-redis + sz-common-excel + sz-common-generator + sz-common-log + sz-common-oss + sz-common-mq + sz-common-security + sz-common-wechat + + + \ No newline at end of file diff --git a/sz-common/sz-common-core/pom.xml b/sz-common/sz-common-core/pom.xml new file mode 100644 index 0000000..0e1f2af --- /dev/null +++ b/sz-common/sz-common-core/pom.xml @@ -0,0 +1,96 @@ + + + + sz-common + com.sz + ${revision} + + 4.0.0 + + sz-common-core + + + + + org.springframework.boot + spring-boot-starter-web + provided + true + + + org.projectlombok + lombok + + + + com.github.pagehelper + pagehelper + provided + true + + + + org.apache.commons + commons-collections4 + + + commons-io + commons-io + + + org.apache.commons + commons-lang3 + + + + org.springframework.boot + spring-boot-starter-validation + + + + com.fasterxml.jackson.core + jackson-databind + + + org.modelmapper + modelmapper + + + com.mybatis-flex + mybatis-flex-spring-boot3-starter + provided + true + + + + org.springframework + spring-websocket + provided + true + + + cn.dev33 + sa-token-spring-boot3-starter + provided + true + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + provided + true + + + com.alibaba + transmittable-thread-local + + + org.lionsoul + ip2region + + + + + \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/annotation/Debounce.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/annotation/Debounce.java new file mode 100644 index 0000000..bd79877 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/annotation/Debounce.java @@ -0,0 +1,27 @@ +package com.sz.core.common.annotation; + +import java.lang.annotation.*; + +/** + * 防抖注解(自定义防抖时间) + *

+ * 自定义防抖注解 + *

+ * + * @author sz + * @version 1.0 + * @since 2024/9/18 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +@Documented +public @interface Debounce { + + /** + * 默认防抖时间,1000 ms + * + * @return 超时时间(ms) + */ + long time() default 1000; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/annotation/DebounceIgnore.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/annotation/DebounceIgnore.java new file mode 100644 index 0000000..7a5cd87 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/annotation/DebounceIgnore.java @@ -0,0 +1,19 @@ +package com.sz.core.common.annotation; + +import java.lang.annotation.*; + +/** + * 忽略防抖注解 + * + * @author sz + * @version 1.0 + * @since 2024/9/18 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +@Documented +public @interface DebounceIgnore { + + boolean required() default true; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/JacksonConfiguration.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/JacksonConfiguration.java new file mode 100644 index 0000000..17df847 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/JacksonConfiguration.java @@ -0,0 +1,158 @@ +package com.sz.core.common.configuration; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; +import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.sz.core.common.entity.MultipartFileSerializer; +import com.sz.core.common.jackson.EmptySerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.boot.jackson.JsonComponent; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.convert.converter.Converter; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.TimeZone; + +/** + * (Jackson)全局统一格式化处理 + *

+ * - Null 转为 空字符串 - date 格式化 - 时区 - 驼峰-蛇形转换 + *

+ * + * @author sz + * @version 1.0 + * @since 2022/8/26 + */ +@Configuration +@JsonComponent +@Slf4j +public class JacksonConfiguration extends JsonSerializer { + + private static final String TIME_ZONE = "GMT+8"; + + private static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + + private static final String DATE_PATTERN = "yyyy-MM-dd"; + + private static final long JS_SAFE_INTEGER_MAX = 9007199254740991L; + + private static final long JS_SAFE_INTEGER_MIN = -9007199254740991L; + + @Bean + public Converter localDateConverter() { + return new Converter() { + + @Override + public LocalDate convert(String source) { + if (source.trim().isEmpty()) { + return null; + } + try { + return LocalDate.parse(source); + } catch (Exception e) { + return LocalDate.parse(source, DateTimeFormatter.ofPattern(DATE_PATTERN)); + } + } + }; + } + + @Bean + public Converter localDateTimeConverter() { + return new Converter() { + + @Override + public LocalDateTime convert(String source) { + if (source.trim().isEmpty()) { + return null; + } + try { + return LocalDateTime.parse(source); + } catch (Exception e) { + return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)); + } + } + }; + } + + @Bean + public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() { + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN))); + return builder -> { + builder.modules(javaTimeModule); + builder.simpleDateFormat(DATE_TIME_PATTERN); + builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_PATTERN))); + builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN))); + }; + } + + @Bean + @Primary + @ConditionalOnMissingBean(ObjectMapper.class) + public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { + ObjectMapper objectMapper = builder.createXmlMapper(false).build(); + objectMapper.setTimeZone(TimeZone.getTimeZone(TIME_ZONE)); // 指定时区为:中国时 + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 针对实体映射时不匹配类型或序列化的处理配置:即找不到、不可用也不抛出异常。 + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + objectMapper.setSerializerFactory(objectMapper.getSerializerFactory().withSerializerModifier(new BeanSerializerModifier() { + + @Override + public List changeProperties(SerializationConfig config, BeanDescription beanDesc, List beanProperties) { + for (BeanPropertyWriter writer : beanProperties) { + JavaType type = writer.getType(); + + if (type.isTypeOrSubTypeOf(String.class)) { + writer.assignNullSerializer(EmptySerializer.EmptyStringSerializer.INSTANCE); + } else if (type.isCollectionLikeType()) { + writer.assignNullSerializer(EmptySerializer.EmptyArraySerializer.INSTANCE); + } else if (type.isMapLikeType()) { + writer.assignNullSerializer(EmptySerializer.EmptyObjectSerializer.INSTANCE); + } else { + // default fallback + writer.assignNullSerializer(EmptySerializer.EmptyStringSerializer.INSTANCE); + } + } + return beanProperties; + } + })); + // 对MultipleFile序列化的支持 + SimpleModule module = new SimpleModule(); + module.addSerializer(MultipartFile.class, new MultipartFileSerializer()); + // 添加Long类型的自定义序列化器 + module.addSerializer(Long.class, new JsonSerializer<>() { + + @Override + public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value > JS_SAFE_INTEGER_MAX || value < JS_SAFE_INTEGER_MIN) { + gen.writeString(value.toString()); + } else { + gen.writeNumber(value); + } + } + }); + objectMapper.registerModule(module); + return objectMapper; + } + + @Override + public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + String formattedValue = value.format(DateTimeFormatter.ofPattern(DATE_TIME_PATTERN)); + gen.writeString(formattedValue); + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/ThreadTaskConfiguration.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/ThreadTaskConfiguration.java new file mode 100644 index 0000000..6c88413 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/ThreadTaskConfiguration.java @@ -0,0 +1,53 @@ +package com.sz.core.common.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 自定义线程池配置 + * + * @author sz + * @version 1.0 + * @since 2022/8/29 + */ +@EnableAsync +@Configuration +public class ThreadTaskConfiguration { + + private static final String THREAD_NAME_PREFIX = "sz-admin-thread_"; + + @Bean + public Executor taskExecutor() { + // 根据ThreadPoolTaskExecutor 创建建线程池 + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + // 为线程设置初始的线程数量 + executor.setCorePoolSize(5); + // 为线程设置最大的线程数量 + executor.setMaxPoolSize(30); + // 为任务队列设置最大Queue数量 + executor.setQueueCapacity(200); + // 设置 超出初始化线程的 存在时间为60秒 + // 也就是 如果现有线程数超过corePoolSize 则会对超出的空闲线程 设置摧毁时间 也就是60秒 + executor.setKeepAliveSeconds(60); + // 设置 线程前缀 + executor.setThreadNamePrefix(THREAD_NAME_PREFIX); + // 线程池的饱和策略 我这里设置的是 CallerRunsPolicy 也就是由用调用者所在的线程来执行任务 共有四种 + // AbortPolicy:直接抛出异常,这是默认策略; + // CallerRunsPolicy:用调用者所在的线程来执行任务; + // DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务; + // DiscardPolicy:直接丢弃任务; + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 设置在关闭线程池时是否等待任务完成 + executor.setWaitForTasksToCompleteOnShutdown(true); + // 设置等待终止的秒数 + executor.setAwaitTerminationSeconds(60); + // 返回设置完成的线程池 + return executor; + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/WebMvcConfiguration.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/WebMvcConfiguration.java new file mode 100644 index 0000000..f4f4ad5 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/configuration/WebMvcConfiguration.java @@ -0,0 +1,36 @@ +package com.sz.core.common.configuration; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +/** + * + * @author sz + * @version 1.0 + * @since 2022/8/29 + */ +@Configuration +@RequiredArgsConstructor +public class WebMvcConfiguration implements WebMvcConfigurer { + + private final ObjectProvider messageConverters; + + @Override + public void extendMessageConverters(List> converters) { + // 将你自定义的转换器加到现有列表中 + this.messageConverters.ifAvailable(customConverters -> converters.addAll(customConverters.getConverters())); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/constant/GlobalConstant.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/constant/GlobalConstant.java new file mode 100644 index 0000000..59b27db --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/constant/GlobalConstant.java @@ -0,0 +1,43 @@ +package com.sz.core.common.constant; + +/** + * 常量 + * + * @author sz + * @version 1.0 + * @since 2022/8/23 + */ +public class GlobalConstant { + + private GlobalConstant() { + throw new IllegalStateException("GlobalConstant class Illegal"); + } + + public static final String UTF_8 = "utf-8"; + + /** + * redis的发布订阅channel(用于 [服务->websocket]方向的消息传递) + */ + public static final String SERVICE_TO_WS = "channel:service_to_ws"; + + /** + * redis的发布订阅channel(用于 [websocket->服务]方向的消息传递) + */ + public static final String WS_TO_SERVICE = "channel:ws_to_service"; + + /** + * redis的发布订阅channel (用于permission变更) + */ + public static final String CHANGE_PERMISSIONS_SIGNAL = "change_permissions_signal"; + + /** + * 超级管理员角色标识 + */ + public static final String SUPER_ROLE = "admin"; + + /** + * 动态字典前缀 + */ + public static final String DYNAMIC_DICT_PREFIX = "dynamic_"; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictLoader.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictLoader.java new file mode 100644 index 0000000..12ec3ac --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictLoader.java @@ -0,0 +1,30 @@ +package com.sz.core.common.dict; + +import com.sz.core.common.entity.DictVO; + +import java.util.List; +import java.util.Map; + +/** + * 字典加载器 + */ +public interface DictLoader { + + /** + * 加载所有字典数据,以 Map 结构返回。 + * + * @return 字典数据的 Map,key 是 typeCode,value 是字典列表 DictVO + */ + Map> loadDict(); + + /** + * 根据typeCode获取Dict + * + * @param typeCode + * 类型 + * @return DictVO集合 + */ + default List getDict(String typeCode) { + return loadDict().get(typeCode); + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictLoaderFactory.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictLoaderFactory.java new file mode 100644 index 0000000..9cba1f4 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictLoaderFactory.java @@ -0,0 +1,88 @@ +package com.sz.core.common.dict; + +import com.sz.core.common.entity.DictVO; +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.core.util.Utils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class DictLoaderFactory { + + // 动态字典加载器 + private final List dynamicLoaders = new ArrayList<>(); + + // 唯一的静态字典加载器 + private final DictLoader defaultLoader; + + @Autowired + public DictLoaderFactory(List allLoaders) { + DictLoader foundDefault = null; + for (DictLoader loader : allLoaders) { + if (loader instanceof DynamicDictLoader dynamicLoader) { + if (Utils.isNotNull(dynamicLoader.getDynamicTypeCode())) { + dynamicLoaders.add(dynamicLoader); + } + } else { + if (foundDefault == null) { + foundDefault = loader; + } + } + } + this.defaultLoader = foundDefault; + } + + /** + * 获取所有字典(静态 + 动态) + * + * @return Map + */ + public Map> loadAllDict() { + Map> result = defaultLoader != null ? new HashMap<>(defaultLoader.loadDict()) : new HashMap<>(); + for (DynamicDictLoader loader : dynamicLoaders) { + result.putAll(loader.loadDict()); + } + return result; + } + + /** + * 获取指定类型的字典 + * + * @param typeCode + * 类型 + * @return DictVO集合 + */ + public List getDictByType(String typeCode) { + Map> allDict = loadAllDict(); + if (!allDict.containsKey(typeCode)) { + if (typeCode.contains("dynamic_")) { + return List.of(); + } + return defaultLoader != null ? defaultLoader.getDict(typeCode) : List.of(); + } + return allDict.get(typeCode); + } + + /** + * 查询所有字典类型(静态 + 动态) + * + * @return DictTypeVO 集合 + */ + public List getAllDictType() { + DictTypeService dictTypeService = SpringApplicationContextUtils.getInstance().getBean(DictTypeService.class); + List result = new ArrayList<>(dictTypeService.findDictType()); + + for (DynamicDictLoader loader : dynamicLoaders) { + String typeCode = loader.getDynamicTypeCode(); + String name = loader.getTypeName(); + DictTypeVO dictTypeVO = DictTypeVO.builder().typeName(name).typeCode(typeCode).isDynamic(true).build(); + result.add(dictTypeVO); + } + return result; + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictService.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictService.java new file mode 100644 index 0000000..17165b2 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictService.java @@ -0,0 +1,89 @@ +package com.sz.core.common.dict; + +import com.sz.core.common.entity.DictVO; + +import java.util.List; +import java.util.Map; + +/** + * 通用字典获取 + * + * @author sz + * @since 2023/12/26 16:38 + */ +public interface DictService { + + /** + * 分隔符 + */ + String SEPARATOR = ","; + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType + * 字典类型 + * @param dictValue + * 字典值 + * @return 字典标签 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType + * 字典类型 + * @param dictLabel + * 字典标签 + * @return 字典值 + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType + * 字典类型 + * @param dictValue + * 字典值 + * @param separator + * 分隔符 + * @return 字典标签 + */ + String getDictLabel(String dictType, String dictValue, String separator); + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType + * 字典类型 + * @param dictLabel + * 字典标签 + * @param separator + * 分隔符 + * @return 字典值 + */ + String getDictValue(String dictType, String dictLabel, String separator); + + /** + * 获取字典下所有的字典值与标签 + * + * @param dictType + * 字典类型 + * @return dictValue为key,dictLabel为值组成的Map + */ + Map getAllDictByType(String dictType); + + /** + * 获取所有字典 + * + * @return 字典类型为key,字典列表为值的Map + */ + Map> getAllDict(); + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictTypeService.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictTypeService.java new file mode 100644 index 0000000..4f1b4df --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictTypeService.java @@ -0,0 +1,8 @@ +package com.sz.core.common.dict; + +import java.util.List; + +public interface DictTypeService { + + List findDictType(); +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictTypeVO.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictTypeVO.java new file mode 100644 index 0000000..cf52e75 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DictTypeVO.java @@ -0,0 +1,30 @@ +package com.sz.core.common.dict; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +/** + * DictTypeVO + * + * @author sz + * @since 2024/8/22 11:17 + * @version 1.0 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DictTypeVO { + + @Schema(description = "字典类型code") + private String typeCode; + + @Schema(description = "字典类型名称") + private String typeName; + + @Schema(description = "是否是动态字典") + @JsonProperty("isDynamic") + private boolean isDynamic = false; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DynamicDictLoader.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DynamicDictLoader.java new file mode 100644 index 0000000..d9dcf0e --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/dict/DynamicDictLoader.java @@ -0,0 +1,33 @@ +package com.sz.core.common.dict; + +import static com.sz.core.common.constant.GlobalConstant.DYNAMIC_DICT_PREFIX; + +/** + * 动态字典loader + */ +public interface DynamicDictLoader extends DictLoader { + + /** + * 返回动态 typeCode(不含前缀) + */ + String getTypeCode(); + + /** + * 返回动态 typeName + */ + String getTypeName(); + + /** + * 返回动态前缀 + */ + default String getDynamicPrefix() { + return DYNAMIC_DICT_PREFIX; + } + + /** + * 返回完整的动态 typeCode(含前缀) + */ + default String getDynamicTypeCode() { + return getDynamicPrefix() + getTypeCode(); + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/AccessRequestLog.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/AccessRequestLog.java new file mode 100644 index 0000000..3561282 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/AccessRequestLog.java @@ -0,0 +1,59 @@ +package com.sz.core.common.entity; + +import lombok.Data; +import lombok.experimental.SuperBuilder; + +/** + * @author sz + * @since 2022/02/16 09:39 + */ +@Data +@SuperBuilder +public class AccessRequestLog { + + private String type = "request"; + + /** + * 请求标识 + */ + private String traceId; + + private String userId; + + /** + * 请求路径 + */ + private String url; + + /** + * 开始时间戳 + */ + private long timestamp; + + /** + * http 方法:GET、POST等 + */ + private String method; + + /** + * url 参数体 + */ + private Object param; + + /** + * form表单参数体 + */ + private Object form; + + /** + * post body参数体 + */ + private Object body; + + private String ip; + + private String contentType; + + private Object requestBody; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/AccessResponseLog.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/AccessResponseLog.java new file mode 100644 index 0000000..75a13c0 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/AccessResponseLog.java @@ -0,0 +1,58 @@ +package com.sz.core.common.entity; + +import lombok.Data; +import lombok.experimental.SuperBuilder; + +/** + * @author sz + * @since 2023/2/20 16:33 + */ + +@Data +@SuperBuilder +public class AccessResponseLog { + + private String traceId; + + /** + * 开始时间戳 + */ + private long timestamp; + + private String userId; + + /** + * 请求地址 + */ + private String url; + + /** + * 请求耗时 (ms) + */ + private long ms; + + /** + * 响应结果 + */ + private Object resBody; + + /** + * url 参数体 + */ + private Object param; + + /** + * form表单参数体 + */ + private Object form; + + /** + * post body参数体 + */ + private Object reqBody; + + private String type = "response"; + + private String method; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ApiPageResult.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ApiPageResult.java new file mode 100644 index 0000000..eb24095 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ApiPageResult.java @@ -0,0 +1,55 @@ +package com.sz.core.common.entity; + +import com.mybatisflex.core.paginate.Page; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.PageUtils; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 全局通用返回结构 + * + * @author sz + * @version 1.0 + * @since 2022/8/23 + */ +@Data +public class ApiPageResult extends ApiResult implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + public static ApiResult> success(List data) { + ApiResult> apiResult = new ApiPageResult<>(); + apiResult.data = (data != null) ? PageUtils.getPageResult(data) : PageUtils.getPageResult(new ArrayList<>()); + return apiResult; + } + + public static ApiResult> success(Page page) { + return success(PageUtils.getPageResult(page)); + } + + public static ApiResult> success(List data, Object param) { + ApiResult> apiResult = new ApiPageResult<>(); + apiResult.data = (data != null) ? PageUtils.getPageResult(data) : PageUtils.getPageResult(new ArrayList<>()); + apiResult.setParam(param); + return apiResult; + } + + public static ApiPageResult> success(PageResult data) { + ApiPageResult> apiResult = new ApiPageResult<>(); + apiResult.data = (data != null) ? data : PageUtils.getPageResult(new ArrayList<>()); + return apiResult; + } + + public static ApiPageResult error(CommonResponseEnum responseEnum) { + ApiPageResult apiResult = new ApiPageResult<>(); + apiResult.setCode(getResponseCode(responseEnum)); + apiResult.setMessage(responseEnum.getMessage()); + return apiResult; + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ApiResult.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ApiResult.java new file mode 100644 index 0000000..8094c70 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ApiResult.java @@ -0,0 +1,92 @@ +package com.sz.core.common.entity; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BusinessExceptionCustomAssert; +import com.sz.core.util.Utils; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * ApiResult + * + * @author sz + * @version 1.0 + * @since 2025/1/12 + */ +@JsonInclude(JsonInclude.Include.USE_DEFAULTS) +@Data +public class ApiResult implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "自定义响应码", example = "0000") + public String code = "0000"; + + @Schema(description = "响应信息", example = "SUCCESS") + public String message = "SUCCESS"; + + @Schema(description = "响应数据") + public T data; + + @Schema(description = "额外参数") + private Object param = new Object(); + + public ApiResult() { + } + + public ApiResult(String code, String message) { + this.code = code; + this.message = message; + } + + public static ApiResult success() { + ApiResult apiResult = new ApiResult<>(); + apiResult.data = null; + return apiResult; + } + + public static ApiResult success(T data) { + ApiResult apiResult = new ApiResult<>(); + apiResult.data = data; + return apiResult; + } + + public static ApiResult success(T data, Object param) { + ApiResult apiResult = new ApiResult<>(); + apiResult.data = data; + if (Utils.isNotNull(param)) { + apiResult.param = param; + } + return apiResult; + } + + public static ApiResult error(CommonResponseEnum responseEnum) { + ApiResult apiResult = new ApiResult<>(); + apiResult.code = getResponseCode(responseEnum); + apiResult.message = responseEnum.getMessage(); + apiResult.data = null; + return apiResult; + } + + protected static String getResponseCode(CommonResponseEnum responseEnum) { + return responseEnum.getCodePrefixEnum().getPrefix() + responseEnum.getCode(); + } + + public static ApiResult error(BusinessExceptionCustomAssert responseEnum) { + ApiResult apiResult = new ApiResult<>(); + apiResult.code = getResponseCode(responseEnum); + apiResult.message = responseEnum.getMessage(); + apiResult.data = null; + return apiResult; + } + + protected static String getResponseCode(BusinessExceptionCustomAssert responseEnum) { + return responseEnum.getCodePrefixEnum().getPrefix() + responseEnum.getCode(); + } + +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/BaseUserInfo.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/BaseUserInfo.java new file mode 100644 index 0000000..3c24990 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/BaseUserInfo.java @@ -0,0 +1,34 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * BaseUserInfo - 用于表示用户信息的类。 + * + * @author sz + * @version 1.0 + * @since 2023-12-12 + */ +@Data +public class BaseUserInfo { + + @Schema(description = "用户id") + private Long id; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "LOGO") + private String logo; + + @Schema(description = "邮箱") + private String email; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/CheckPuzzle.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/CheckPuzzle.java new file mode 100644 index 0000000..c2aa283 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/CheckPuzzle.java @@ -0,0 +1,25 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * CheckPuzzle + * + * @version 1.0 + * @since 2025-01-08 + * @author sz + */ +@Data +public class CheckPuzzle { + + @Schema(description = "请求标识") + private String requestId; + + @Schema(description = "移动变量(x轴位置)加密串") + private String moveEncrypted; + + @Schema(description = "iv向量") + private String iv; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ControlPermissions.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ControlPermissions.java new file mode 100644 index 0000000..23c19a8 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ControlPermissions.java @@ -0,0 +1,16 @@ +package com.sz.core.common.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@AllArgsConstructor +@Data +public class ControlPermissions { + + private String[] permissions; + + private String mode; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/DictVO.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/DictVO.java new file mode 100644 index 0000000..f36823f --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/DictVO.java @@ -0,0 +1,49 @@ +package com.sz.core.common.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class DictVO { + + @Schema(description = "字典id", example = "1000001") + private String id; + + @Schema(description = "字典类型id", example = "1000") + private Long sysDictTypeId; + + @Schema(description = "字典名称", example = "正常") + private String codeName; + + @Schema(description = "别名", example = "normal") + private String alias; + + @Schema(description = "排序", example = "1") + private Integer sort; + + @Schema(description = "回显样式", example = "success", allowableValues = "success,info,warning,danger") + private String callbackShowStyle; + + @Schema(description = "是否锁定", example = "F", allowableValues = "T,F") + private String isLock; + + @Schema(description = "是否展示", example = "T", allowableValues = "T,F") + private String isShow; + + @Schema(description = "字典类型名", example = "账户状态") + private String sysDictTypeName; + + @Schema(description = "字典类型码", example = "account_status") + private String sysDictTypeCode; + + @Schema(description = "是否动态字典") + @JsonProperty("isDynamic") + private boolean isDynamic = false; +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ImportExcelDTO.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ImportExcelDTO.java new file mode 100644 index 0000000..622f3d5 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/ImportExcelDTO.java @@ -0,0 +1,15 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +@Data +public class ImportExcelDTO { + + private MultipartFile file; + + @Schema(description = "是否数据覆盖", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") + private Boolean isCover; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/LoginUser.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/LoginUser.java new file mode 100644 index 0000000..88141a7 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/LoginUser.java @@ -0,0 +1,32 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.*; + +@Data +public class LoginUser { + + @Schema(description = "基础用户信息") + private BaseUserInfo userInfo; + + @Schema(description = "权限标识列表") + private Set permissions = new HashSet<>(); + + @Schema(description = "角色列表") + private Set roles = new HashSet<>(); + + @Schema(description = "所属部门") + private List depts = new ArrayList<>(); + + @Schema(description = "所属部门及其子孙节点部门") + private List deptAndChildren = new ArrayList<>(); + + @Schema(description = "权限标识与菜单关系数组") + private Map permissionAndMenuIds = new HashMap<>(); + + @Schema(description = "数据权限范围") + private Map dataScope; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/MultipartFileSerializer.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/MultipartFileSerializer.java new file mode 100644 index 0000000..969f24e --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/MultipartFileSerializer.java @@ -0,0 +1,19 @@ +package com.sz.core.common.entity; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +/** + * 自定义MultipleFile序列化 + */ +public class MultipartFileSerializer extends JsonSerializer { + + @Override + public void serialize(MultipartFile value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(value.getOriginalFilename()); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PageQuery.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PageQuery.java new file mode 100644 index 0000000..fd383e4 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PageQuery.java @@ -0,0 +1,21 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 分页查询基础类 + * + * @author sz + * @since 2022/8/25 15:58 + */ +@Data +public class PageQuery { + + @Schema(description = "页数", example = "1") + private Integer page = 1; + + @Schema(description = "每页条数", example = "10") + private Integer limit = 10; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PageResult.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PageResult.java new file mode 100644 index 0000000..2c37cd5 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PageResult.java @@ -0,0 +1,44 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 分页对象 + * + * @author sz + * @since 2022/8/25 10:25 + */ +@Data +public class PageResult implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "当前页") + private long current; + + @Schema(description = "每页条数") + private long limit; + + @Schema(description = "总页数") + private long totalPage; + + @Schema(description = "总条数") + private long total; + + @Schema(description = "结果集") + private List rows; + + public PageResult(long current, long limit, long totalPage, long total, List rows) { + this.current = current; + this.limit = limit; + this.totalPage = totalPage; + this.total = total; + this.rows = rows; + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PointVO.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PointVO.java new file mode 100644 index 0000000..f0c3a84 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/PointVO.java @@ -0,0 +1,16 @@ +package com.sz.core.common.entity; + +import lombok.*; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PointVO { + + private int x; + + private int y; + + private String secretKey; + +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/RoleMenuScopeVO.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/RoleMenuScopeVO.java new file mode 100644 index 0000000..9c27a53 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/RoleMenuScopeVO.java @@ -0,0 +1,32 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.Collection; + +@Schema(description = "用户的数据权限范围汇总信息") +@Data +public class RoleMenuScopeVO { + + @Schema(description = "sys_menu_id (菜单表)") + private String menuId; + + @Schema(description = "数据权限范围") + private String dataScopeCd; + + @Schema(description = "自定义数据权限范围,当dataScopeCd为1006005时使用") + private CustomScope customScope; + + @Data + public static class CustomScope { + + @Schema(description = "用户ID") + private Collection userIds; + + @Schema(description = "部门ID") + private Collection deptIds; + + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SelectIdsDTO.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SelectIdsDTO.java new file mode 100644 index 0000000..33cb19a --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SelectIdsDTO.java @@ -0,0 +1,23 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Data +public class SelectIdsDTO { + + @Schema(description = "选择的标识数组") + private List ids = new ArrayList<>(); + + public SelectIdsDTO() { + } + + public SelectIdsDTO(List ids) { + this.ids = ids; + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SliderPuzzle.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SliderPuzzle.java new file mode 100644 index 0000000..8ea9cce --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SliderPuzzle.java @@ -0,0 +1,38 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class SliderPuzzle { + + @Schema(description = "请求ID") + private String requestId; + + @Schema(description = "大图宽度") + private Integer bigWidth; + + @Schema(description = "大图高度") + private Integer bigHeight; + + @Schema(description = "大图转BASE64字符串") + private String bigImageBase64; + + @Schema(description = "小图宽度") + private Integer smallWidth; + + @Schema(description = "小图高度") + private Integer smallHeight; + + @Schema(description = "小图转BASE64字符串") + private String smallImageBase64; + + @Schema(description = "随机坐标Y") + private Integer posY; + + @Schema(description = "随机坐标X") + private Integer posX; + + @Schema(description = "加密key") + private String secretKey; +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SocketMessage.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SocketMessage.java new file mode 100644 index 0000000..4e9debd --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/SocketMessage.java @@ -0,0 +1,30 @@ +package com.sz.core.common.entity; + +import com.sz.core.common.enums.MessageTransferScopeEnum; +import com.sz.core.common.enums.SocketChannelEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author sz + * @since 2023/9/6 17:20 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SocketMessage { + + @Schema(description = "data") + protected Object data; + + @Schema(description = "通道类型") + protected SocketChannelEnum channel = SocketChannelEnum.DEFAULTS; + + @Schema(description = "消息通知作用域") + protected MessageTransferScopeEnum scope = MessageTransferScopeEnum.SOCKET_CLIENT; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/TransferMessage.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/TransferMessage.java new file mode 100644 index 0000000..8ac88de --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/TransferMessage.java @@ -0,0 +1,34 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author sz + * @since 2023/9/8 16:10 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TransferMessage { + + @Schema(description = "消息体bean") + private SocketMessage message; + + @Schema(description = "消息接收人") + private List toUsers = new ArrayList<>(); + + @Schema(description = "消息发送人") + private String fromUser; + + @Schema(description = "是否通知全部用户") + private boolean toPushAll = false; + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/UploadResult.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/UploadResult.java new file mode 100644 index 0000000..10e6867 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/UploadResult.java @@ -0,0 +1,46 @@ +package com.sz.core.common.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * @author sz + * @since 2024/11/12 16:22 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UploadResult { + + // URL + private String url; + + // 文件名 + private String filename; + + // 对象名称 (带路径) + private String objectName; + + // 标记 + private String eTag; + + // 标记 + private String dirTag; + + // 文件类型 + private String contextType; + + // 文件大小 + private Long size; + + // 文件id + private Long fileId; + + // 元数据 + private Map metaData; +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/UserPermissionChangeMessage.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/UserPermissionChangeMessage.java new file mode 100644 index 0000000..576f546 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/UserPermissionChangeMessage.java @@ -0,0 +1,34 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +public class UserPermissionChangeMessage { + + @Schema(description = "username") + private String username; + + @Schema(description = "用户id") + private Long userId; + + /** + * 是否是对所有用户进行permission更新 + */ + private boolean toChangeAll; + + public UserPermissionChangeMessage() { + } + + public UserPermissionChangeMessage(String username, Long userId, boolean toChangeAll) { + this.username = username; + this.userId = userId; + this.toChangeAll = toChangeAll; + } + + public UserPermissionChangeMessage(String username, boolean toChangeAll) { + this.username = username; + this.toChangeAll = toChangeAll; + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/WsSession.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/WsSession.java new file mode 100644 index 0000000..e6263be --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/entity/WsSession.java @@ -0,0 +1,28 @@ +package com.sz.core.common.entity; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.web.socket.WebSocketSession; + +/** + * @author sz + * @since 2023/9/8 8:32 + */ +@Data +public class WsSession { + + @Schema(description = "sid,自定义生成的uuid") + private String sid; + + @Schema(description = "loginId") + private String loginId; + + @Schema(description = "socket-session") + private WebSocketSession session; + + public WsSession(String sid, String loginId, WebSocketSession session) { + this.sid = sid; + this.loginId = loginId; + this.session = session; + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/CommonResponseEnum.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/CommonResponseEnum.java new file mode 100644 index 0000000..a170e69 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/CommonResponseEnum.java @@ -0,0 +1,72 @@ +package com.sz.core.common.enums; + +/** + * 异常枚举类 + */ +public enum CommonResponseEnum implements ResponseEnumTemplate { + + // @formatter:off + VALID_ERROR(100, "参数校验异常"), + BAD_USERNAME_OR_PASSWORD(101, "账户不存在或密码错误"), + CNT_PASSWORD_ERR(102, "密码错误次数过多,账户锁定!"), + CLIENT_INVALID(103, "无效的ClientId"), + CLIENT_BLOCKED(104, "Client认证已禁用"), + INVALID_TOKEN(105, "无效Token"), + INVALID_USER(106, "无效用户"), + BAD_USERNAME_STATUS_INVALID(107, "用户被禁用"), + INVALID_PERMISSION(108, "抱歉,您目前无权执行此操作,请联系管理员获取相应权限。"), + WEBSOCKET_SEND_FAIL(109, "WebSocket消息发送异常"), + DEBOUNCE(110, "您的请求过于频繁,请稍后再试!"), + MEDIA_HTTP_FAIL(602,"流媒体服务器调用失败"), + + INVALID_ID(1000, "无效ID"), + EXISTS(1001, "已存在"), + NOT_EXISTS(1002, "不存在"), + FILE_NOT_EXISTS(1003, "文件不存在"), + FILE_UPLOAD_EXT_ERROR(1004, "上传文件类型错误"), + FILE_UPLOAD_SIZE_ERROR(1005, "上传文件大小不能超过10MB"), + FILE_UPLOAD_ERROR(1006, "上传文件失败"), + USERNAME_EXISTS(1007, "用户名已存在"), + INVALID(1008, "无效的数据"), + EXCEL_IMPORT_ERROR(1009, "Excel导入失败"), + CAPTCHA_LACK(1010, "验证参数缺失"), + CAPTCHA_EXPIRED(1011, "验证码失效,请重新获取"), + CAPTCHA_FAILED(1012, "验证失败"), + CAPTCHA_LIMIT(1013,"验证码请求已达到最大次数"), + BACKGROUND_NOT_EXISTS(1014, "背景图片不存在"), + LOGIN_LIMIT(1015,"登录请求已达到最大次数"), + + UNKNOWN(9999, "未知异常"), + ; + // @formatter:on + + /** + * 返回码 + */ + private final int code; + + /** + * 返回消息 + */ + private final String message; + + CommonResponseEnum(int code, String message) { + this.code = code; + this.message = message; + } + + @Override + public int getCode() { + return this.code; + } + + @Override + public String getMessage() { + return this.message; + } + + @Override + public ErrorPrefixEnum getCodePrefixEnum() { + return ErrorPrefixEnum.COMMON; + } +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/ErrorPrefixEnum.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/ErrorPrefixEnum.java new file mode 100644 index 0000000..23f0710 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/ErrorPrefixEnum.java @@ -0,0 +1,40 @@ +package com.sz.core.common.enums; + +import lombok.Getter; + +/** + * ErrorPrefixEnum - 定义错误前缀的枚举类。 + *

+ * 此枚举类用于集中管理和定义应用中的错误前缀,以便统一错误代码格式。 + *

+ * + * @version 1.0 + * @since 2024-10-11 + * @author sz + */ +@Getter +public enum ErrorPrefixEnum { + + // @formatter:off + COMMON("C", "common异常"), + ADMIN("A", "admin异常"), + + // ...其他业务模块的异常前缀 + ; + // @formatter:on + + /** + * 前缀标识 + */ + private final String prefix; + + /** + * 描述 + */ + private final String description; + + ErrorPrefixEnum(String prefix, String description) { + this.prefix = prefix; + this.description = description; + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/MessageTransferScopeEnum.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/MessageTransferScopeEnum.java new file mode 100644 index 0000000..a7a7439 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/MessageTransferScopeEnum.java @@ -0,0 +1,18 @@ +package com.sz.core.common.enums; + +/** + * MessageTransferScopeEnum - 定义消息传输范围的枚举类。 + * + * @version 1.0 + * @since 2024-02-17 + * @author sz + */ +public enum MessageTransferScopeEnum { + // 后台服务端 + SERVER, + // socket服务端 + SOCKET_SERVER, + // socket客户端 (web、app等) + SOCKET_CLIENT, + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/ResponseEnumTemplate.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/ResponseEnumTemplate.java new file mode 100644 index 0000000..eefb3ec --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/ResponseEnumTemplate.java @@ -0,0 +1,51 @@ +package com.sz.core.common.enums; + +import com.sz.core.common.exception.common.BusinessExceptionCustomAssert; + +/** + * 通用响应枚举模板接口,提供线程安全的message方法 + * + * @param + * 枚举类型 + */ +public interface ResponseEnumTemplate & ResponseEnumTemplate> extends BusinessExceptionCustomAssert { + + class CustomMessageWrapper & ResponseEnumTemplate> implements BusinessExceptionCustomAssert { + + private final T original; + + private final int customCode; + + private final String customMessage; + + public CustomMessageWrapper(T original, int customCode, String customMessage) { + this.original = original; + this.customCode = customCode; + this.customMessage = customMessage; + } + + @Override + public int getCode() { + return this.customCode; + } + + @Override + public String getMessage() { + return this.customMessage; + } + + @Override + public ErrorPrefixEnum getCodePrefixEnum() { + return original.getCodePrefixEnum(); + } + } + + @SuppressWarnings("unchecked") + default BusinessExceptionCustomAssert message(int code, String message) { + return new CustomMessageWrapper<>((E) this, code, message); + } + + default BusinessExceptionCustomAssert message(String message) { + return message(getCode(), message); + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/SocketChannelEnum.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/SocketChannelEnum.java new file mode 100644 index 0000000..57cac6d --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/SocketChannelEnum.java @@ -0,0 +1,48 @@ +package com.sz.core.common.enums; + +import lombok.Getter; + +/** + * @author sz + * @since 2023/9/6 10:24 + */ +@Getter +public enum SocketChannelEnum { + + // @formatter:off + DEFAULTS("default", "默认channel", "push_or_receive"), + AUTH("auth", "鉴权", "push_or_receive"), + CLOSE("close", "断开连接", "push"), + KICK_OFF("kick_off", "踢下线", "push"), + SYNC_MENU("sync_menu", "同步菜单", "push"), + SYNC_DICT("sync_dict", "同步字典", "push"), + SYNC_PERMISSIONS("sync_permissions", "同步permission权限", "push"), + UPGRADE_CHANNEL("upgrade_channel", "升级通告", "push"), + MESSAGE("message", "系统消息", "push"), + READ("read","消息已读刷新数量","push"), + TEST("test","测试","push"), + SYNC_FRONTEND_CONF("sync_frontend_conf","同步前端配置","push"), + ; + // @formatter:on + + /** + * 字符串标识 + */ + private final String name; + + /** + * 备注 + */ + private final String remark; + + /** + * 状态:push 发送、1 receive、2 push_or_receive + */ + private final String status; + + SocketChannelEnum(String name, String remark, String status) { + this.name = name; + this.remark = remark; + this.status = status; + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/TrueFalseEnum.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/TrueFalseEnum.java new file mode 100644 index 0000000..b04dd7f --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/enums/TrueFalseEnum.java @@ -0,0 +1,5 @@ +package com.sz.core.common.enums; + +public enum TrueFalseEnum { + T, F +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/event/BaseEvent.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/event/BaseEvent.java new file mode 100644 index 0000000..a6006ed --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/event/BaseEvent.java @@ -0,0 +1,16 @@ +package com.sz.core.common.event; + +import lombok.Getter; +import org.springframework.context.ApplicationEvent; + +@Getter +public abstract class BaseEvent extends ApplicationEvent { + + private final T payload; + + protected BaseEvent(Object source, T payload) { + super(source); + this.payload = payload; + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/event/EventPublisher.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/event/EventPublisher.java new file mode 100644 index 0000000..89237da --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/event/EventPublisher.java @@ -0,0 +1,22 @@ +package com.sz.core.common.event; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Component; + +/** + * @version 1.0 + * @since 2024-02-29 + * @author sz + */ +@Component +@RequiredArgsConstructor +public class EventPublisher { + + private final ApplicationEventPublisher applicationEventPublisher; + + public void publish(BaseEvent event) { + applicationEventPublisher.publishEvent(event); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/GlobalExceptionHandler.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..4804669 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/GlobalExceptionHandler.java @@ -0,0 +1,104 @@ +package com.sz.core.common.exception; + +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BaseException; +import com.sz.core.common.exception.common.BusinessException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * 全局异常捕获处理 + * + * @author sz + * @since 2022/8/23 10:56 + */ +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResponseEntity> exceptionHandler(Exception e) { + log.error(e.getMessage(), e); + ApiResult error = ApiResult.error(CommonResponseEnum.UNKNOWN); + return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR); + } + + /** + * 业务异常 + * + * @param e + * 异常 + * @return 异常结果 + */ + @ExceptionHandler(value = BusinessException.class) + @ResponseBody + public ApiResult handleBusinessException(BusinessException e) { + log.error(e.getMessage(), e); + return new ApiResult<>(getCode(e), e.getMessage()); + } + + /** + * 自定义异常 + * + * @param e + * 异常 + * @return 异常结果 + */ + @ExceptionHandler(value = BaseException.class) + @ResponseBody + public ApiResult handleBaseException(BaseException e) { + log.error(e.getMessage(), e); + return new ApiResult<>(getCode(e), e.getMessage()); + } + + /** + * 参数校验异常 + * + * @param e + * 参数校验异常 + * @return 异常结果 + */ + @ExceptionHandler(value = MethodArgumentNotValidException.class) + public ResponseEntity> handleValidException(MethodArgumentNotValidException e) { + log.error(e.getMessage(), e); + ApiResult apiResult = wrapperBindingResult(e); + return new ResponseEntity<>(apiResult, HttpStatus.UNPROCESSABLE_ENTITY); + } + + /** + * 参数绑定异常 + * + * @param e + * 参数绑定异常 + * @return 异常结果 + */ + @ExceptionHandler(value = BindException.class) + public ResponseEntity> handleBindException(BindException e) { + log.error(e.getMessage(), e); + ApiResult apiResult = wrapperBindingResult(e); + return new ResponseEntity<>(apiResult, HttpStatus.UNPROCESSABLE_ENTITY); + } + + private ApiResult wrapperBindingResult(BindingResult bindingResult) { + StringBuilder msg = new StringBuilder(); + for (ObjectError error : bindingResult.getAllErrors()) { + msg.append(", "); + msg.append(error.getDefaultMessage() == null ? "" : error.getDefaultMessage()); + } + return new ApiResult<>(CommonResponseEnum.VALID_ERROR.getCodePrefixEnum().getPrefix() + CommonResponseEnum.VALID_ERROR.getCode(), msg.substring(2)); + } + + private String getCode(BaseException e) { + return e.getResponseEnum().getCodePrefixEnum().getPrefix() + e.getResponseEnum().getCode(); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BaseException.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BaseException.java new file mode 100644 index 0000000..a8e5710 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BaseException.java @@ -0,0 +1,29 @@ +package com.sz.core.common.exception.common; + +import lombok.Getter; + +import java.io.Serial; + +@Getter +public class BaseException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + private final IResponseEnum responseEnum; + + private final Object[] args; + + public BaseException(IResponseEnum responseEnum, Object[] args, String message) { + super(message); + this.responseEnum = responseEnum; + this.args = args; + } + + public BaseException(IResponseEnum responseEnum, Object[] args, String message, Throwable cause) { + super(message, cause); + this.responseEnum = responseEnum; + this.args = args; + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BusinessException.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BusinessException.java new file mode 100644 index 0000000..5065423 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BusinessException.java @@ -0,0 +1,16 @@ +package com.sz.core.common.exception.common; + +import java.io.Serial; + +public class BusinessException extends BaseException { + + @Serial + private static final long serialVersionUID = 1L; + + public BusinessException(IResponseEnum responseEnum, Object[] args, String message) { + super(responseEnum, args, message); + } + public BusinessException(IResponseEnum responseEnum, Object[] args, String message, Throwable cause) { + super(responseEnum, args, message, cause); + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BusinessExceptionCustomAssert.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BusinessExceptionCustomAssert.java new file mode 100644 index 0000000..03f8ab7 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/BusinessExceptionCustomAssert.java @@ -0,0 +1,33 @@ +package com.sz.core.common.exception.common; + +import java.text.MessageFormat; + +public interface BusinessExceptionCustomAssert extends IResponseEnum, CustomAssert { + + @Override + default BaseException newException(Object... args) { + String msg = MessageFormat.format(this.getMessage(), args); + return new BusinessException(this, args, msg); + } + + @Override + default BaseException newException(Throwable t, Object... args) { + String msg = MessageFormat.format(this.getMessage(), args); + return new BusinessException(this, args, msg, t); + } + + /** + * 创建异常,允许传递自定义的message和args + * + * @param message + * 自定义错误消息 + * @param args + * message占位符对应的参数列表 + * @return 创建的异常 + */ + default BaseException newException(String message, Object... args) { + String formattedMessage = MessageFormat.format(message, args); + return new BaseException(this, args, formattedMessage); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/CustomAssert.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/CustomAssert.java new file mode 100644 index 0000000..5643b53 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/CustomAssert.java @@ -0,0 +1,85 @@ +package com.sz.core.common.exception.common; + +public interface CustomAssert { + + /** + * 创建异常 + * + * @param args + * 异常信息参数 + * @return 异常 + */ + BaseException newException(Object... args); + + /** + * 创建异常 + * + * @param t + * Throwable + * @param args + * 异常信息参数 + * @return 异常 + */ + BaseException newException(Throwable t, Object... args); + + /** + *

+ * 断言对象obj为空。如果对象obj为空,则抛出异常 + * + * @param obj + * 待判断对象 + */ + default void assertNull(Object obj) { + if (obj == null) { + throw newException(); + } + } + + default void assertNotNull(Object obj) { + if (obj != null) { + throw newException(); + } + } + + /** + * boolean型的断言 true则抛出异常 + * + * @param bool + * boolean值 + */ + default void assertTrue(boolean bool) { + if (bool) { + throw newException(); + } + } + + /** + * boolean型的断言 false则抛出异常 + * + * @param bool + * boolean值 + */ + default void assertFalse(boolean bool) { + if (!bool) { + throw newException(); + } + } + + /** + *

+ * 断言对象obj非空。如果对象obj为空,则抛出异常 + *

+ * 异常信息message支持传递参数方式,避免在判断之前进行字符串拼接操作 + * + * @param obj + * 待判断对象 + * @param args + * message占位符对应的参数列表 + */ + default void assertNull(Object obj, Object... args) { + if (obj == null) { + throw newException(args); + } + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/IResponseEnum.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/IResponseEnum.java new file mode 100644 index 0000000..14752aa --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/exception/common/IResponseEnum.java @@ -0,0 +1,28 @@ +package com.sz.core.common.exception.common; + +import com.sz.core.common.enums.ErrorPrefixEnum; + +public interface IResponseEnum { + + /** + * 获取错误码 + * + * @return 错误码 + */ + int getCode(); + + /** + * 获取错误信息 + * + * @return 错误信息 + */ + String getMessage(); + + /** + * 获取错误码前缀 + * + * @return 错误码前缀 + */ + ErrorPrefixEnum getCodePrefixEnum(); + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/jackson/EmptySerializer.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/jackson/EmptySerializer.java new file mode 100644 index 0000000..43576d2 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/jackson/EmptySerializer.java @@ -0,0 +1,88 @@ +package com.sz.core.common.jackson; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; + +/** + * 提供针对不同类型的 Jackson null 值序列化器,可用于精细化控制字段为 {@code null} 时的序列化行为。 + *

+ * 通常搭配 {@code BeanSerializerModifier} 使用,根据字段类型指定对应的 null 值序列化策略, 用于替代默认的 + * {@code null} 输出,提升前端兼容性和可读性。 + *

+ * + *

+ * 典型应用: + *

+ *
    + *
  • String 类型 null → ""
  • + *
  • List/Set 类型 null → []
  • + *
  • Map 类型 null → {}
  • + *
  • Number 类型 null → 0
  • + *
  • Boolean 类型 null → false
  • + *
+ * + *

+ * 示例用法(配合 BeanSerializerModifier): + * + *

{@code
+ * if (type.isTypeOrSubTypeOf(String.class)) {
+ *     writer.assignNullSerializer(EmptyStringSerializer.INSTANCE);
+ * }
+ * }
+ *

+ * + * @author sz + * @since 2025/7/14 + */ +public class EmptySerializer { + + public static class EmptyStringSerializer extends JsonSerializer { + + public static final EmptyStringSerializer INSTANCE = new EmptyStringSerializer(); + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeString(""); + } + } + + public static class EmptyArraySerializer extends JsonSerializer { + + public static final EmptyArraySerializer INSTANCE = new EmptyArraySerializer(); + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeStartArray(); + gen.writeEndArray(); + } + } + + public static class EmptyObjectSerializer extends JsonSerializer { + + public static final EmptyObjectSerializer INSTANCE = new EmptyObjectSerializer(); + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeStartObject(); + gen.writeEndObject(); + } + } + + public static class ZeroNumberSerializer extends JsonSerializer { + + public static final ZeroNumberSerializer INSTANCE = new ZeroNumberSerializer(); + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeNumber(0); + } + } + + public static class FalseBooleanSerializer extends JsonSerializer { + + public static final FalseBooleanSerializer INSTANCE = new FalseBooleanSerializer(); + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeBoolean(false); + } + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/jackson/EmptyStringAsEmptyMapDeserializer.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/jackson/EmptyStringAsEmptyMapDeserializer.java new file mode 100644 index 0000000..8c09800 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/jackson/EmptyStringAsEmptyMapDeserializer.java @@ -0,0 +1,44 @@ +package com.sz.core.common.jackson; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +/** + * Jackson 反序列化器:用于将空字符串("")反序列化为一个空的 {@link Map}。 + *

+ * 当后端字段为 {@code Map} 类型,但前端传入的是空字符串(如 {@code ""}), 默认 Jackson + * 会抛出反序列化异常。此类可用于兼容这种情况,将空字符串安全地转为 {@code new HashMap<>()}。 + *

+ * + *

+ * 使用方式: + *

+ * + *
{@code
+ * 
+ * @JsonDeserialize(using = EmptyStringAsEmptyMapDeserializer.class)
+ * private Map extraParams;
+ * }
+ * + *

+ * 推荐搭配字段级使用 + *

+ * + * @author sz + * @since 2025/7/14 + */ +public class EmptyStringAsEmptyMapDeserializer extends JsonDeserializer> { + + @Override + public Map deserialize(JsonParser parser, DeserializationContext ctx) throws IOException { + if (parser.getCurrentToken().isScalarValue() && "".equals(parser.getText())) { + return new HashMap<>(); + } + // 其他情况下走默认处理 + return ctx.readValue(parser, Map.class); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/service/ConfService.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/service/ConfService.java new file mode 100644 index 0000000..3edbf7a --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/service/ConfService.java @@ -0,0 +1,29 @@ +package com.sz.core.common.service; + +/** + * 系统配置获取 + * + * @author sz + * @since 2024/1/9 15:25 + */ +public interface ConfService { + + /** + * 验证配置是否存在 + * + * @param key + * 配置key + * @return boolean + */ + boolean hasConfKey(String key); + + /** + * 根据配置key获取value + * + * @param key + * 配置key + * @return 配置信息 + */ + String getConfValue(String key); + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/service/Treeable.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/service/Treeable.java new file mode 100644 index 0000000..5f7432b --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/service/Treeable.java @@ -0,0 +1,22 @@ +package com.sz.core.common.service; + +import java.util.List; + +/** + * @author sz + * @since 2024/3/22 17:34 + */ +public interface Treeable { + + Object getId(); + + Object getPid(); + + Long getDeep(); + + Long getSort(); + + List getChildren(); + + void setChildren(List children); +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/valid/annotation/NotZero.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/valid/annotation/NotZero.java new file mode 100644 index 0000000..13e76d9 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/valid/annotation/NotZero.java @@ -0,0 +1,22 @@ +package com.sz.core.common.valid.annotation; + +import com.sz.core.common.valid.validator.NotZeroValidator; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = NotZeroValidator.class) +public @interface NotZero { + + String message() default "Value must be non-null and non-zero"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/common/valid/validator/NotZeroValidator.java b/sz-common/sz-common-core/src/main/java/com/sz/core/common/valid/validator/NotZeroValidator.java new file mode 100644 index 0000000..458fdf5 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/common/valid/validator/NotZeroValidator.java @@ -0,0 +1,29 @@ +package com.sz.core.common.valid.validator; + +import com.sz.core.common.valid.annotation.NotZero; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class NotZeroValidator implements ConstraintValidator { + + @Override + public void initialize(NotZero constraintAnnotation) { + ConstraintValidator.super.initialize(constraintAnnotation); + } + + @Override + public boolean isValid(Number value, ConstraintValidatorContext constraintValidatorContext) { + if (value == null) { + return false; + } + + if (value instanceof Integer) { + return value.intValue() != 0; + } + + if (value instanceof Long) { + return value.longValue() != 0L; + } + return true; + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/datascope/ControlThreadLocal.java b/sz-common/sz-common-core/src/main/java/com/sz/core/datascope/ControlThreadLocal.java new file mode 100644 index 0000000..beeee7b --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/datascope/ControlThreadLocal.java @@ -0,0 +1,34 @@ +package com.sz.core.datascope; + +import com.alibaba.ttl.TransmittableThreadLocal; +import com.sz.core.common.entity.ControlPermissions; + +/** + * @author sz + * @since 2024/6/19 8:37 + */ +public class ControlThreadLocal { + + private ControlThreadLocal() { + throw new IllegalStateException("Utility class"); + } + + protected static final TransmittableThreadLocal LOCAL_CONTROLLER = new TransmittableThreadLocal<>(); + + public static void set(ControlPermissions permission) { + LOCAL_CONTROLLER.set(permission); + } + + public static ControlPermissions get() { + return LOCAL_CONTROLLER.get(); + } + + public static boolean hasLocal() { + return LOCAL_CONTROLLER.get() != null; + } + + public static void clearDataScope() { + LOCAL_CONTROLLER.remove(); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/datascope/SimpleDataScopeHelper.java b/sz-common/sz-common-core/src/main/java/com/sz/core/datascope/SimpleDataScopeHelper.java new file mode 100644 index 0000000..3c4e2d3 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/datascope/SimpleDataScopeHelper.java @@ -0,0 +1,33 @@ +package com.sz.core.datascope; + +import com.alibaba.ttl.TransmittableThreadLocal; + +/** + * @author sz + * @since 2024/6/19 8:37 + */ +public class SimpleDataScopeHelper { + + private SimpleDataScopeHelper() { + throw new IllegalStateException("SimpleDataScopeHelper class Illegal"); + } + + protected static final TransmittableThreadLocal> LOCAL_DATA_SCOPE = new TransmittableThreadLocal<>(); + + public static void start(Class clazz) { + LOCAL_DATA_SCOPE.set(clazz); + } + + public static Class get() { + return LOCAL_DATA_SCOPE.get(); + } + + public static boolean isDataScope() { + return LOCAL_DATA_SCOPE.get() != null; + } + + public static void clearDataScope() { + LOCAL_DATA_SCOPE.remove(); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/ip/IpUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/ip/IpUtils.java new file mode 100644 index 0000000..0800459 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/ip/IpUtils.java @@ -0,0 +1,160 @@ +package com.sz.core.ip; + +import lombok.extern.slf4j.Slf4j; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * IP地址工具类,提供IP地址验证、归属地查询等功能 + * + * @author sz + * @since 2025/7/28 13:45 + */ +@Slf4j +public class IpUtils { + + // 判断ip地址正则 + public static final Pattern IPV4 = Pattern.compile( + "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)$"); + + public static final Pattern IPV6 = Pattern.compile( + "(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))"); + + // 未知IP + public static final String UNKNOWN_IP = "XX XX"; + + // 内网地址 + public static final String LOCAL_ADDRESS = "内网IP"; + + // 未知地址 + public static final String UNKNOWN_ADDRESS = "未知"; + + /** + * 根据IP地址获取真实归属地 + * + * @param ip + * IP地址字符串 + * @return 归属地信息,内网IP返回{@link #LOCAL_ADDRESS},不支持的IP类型返回{@link #UNKNOWN_IP} + */ + public static String getRealAddressByIP(String ip) { + // 判断是否为IPv4 + if (isIPv4(ip)) { + // 内网不查询 + if (isInnerIP(ip)) { + return LOCAL_ADDRESS; + } + return RegionUtils.getCityInfo(ip); + } + // 如果不是IPv4,则返回未知IP + return UNKNOWN_IP; + } + + /** + * 根据IPv6地址查询IP归属行政区域 + *

+ * 目前ip2region不支持IPv6解析,直接返回未知地址 + *

+ * + * @param ip + * ipv6地址 + * @return 归属行政区域,固定返回{@link #UNKNOWN_ADDRESS} + */ + private static String resolverIPv6Region(String ip) { + log.warn("ip2region不支持IPV6地址解析:{}", ip); + // 不支持IPv6,直接返回 + return UNKNOWN_ADDRESS; + } + + /** + * 判断是否为IPv4地址 + * + * @param ip + * IP地址字符串 + * @return true-是IPv4地址,false-不是IPv4地址 + */ + private static boolean isIPv4(String ip) { + return ip != null && IPV4.matcher(ip).matches(); + } + + /** + * 判断是否为IPv6地址 + * + * @param ip + * IP地址字符串 + * @return true-是IPv6地址,false-不是IPv6地址 + */ + private static boolean isIPv6(String ip) { + return ip != null && IPV6.matcher(ip).matches(); + } + + /** + * 判断是否为内网IP地址 + *

+ * 支持10.0.0.0/8、172.16.0.0/12、192.168.0.0/16网段及127.0.0.1 + *

+ * + * @param ipAddress + * IP地址字符串 + * @return true-是内网IP,false-不是内网IP + */ + private static boolean isInnerIP(String ipAddress) { + long ipNum = ipv4ToLong(ipAddress); + long aBegin = ipv4ToLong("10.0.0.0"); + long aEnd = ipv4ToLong("10.255.255.255"); + long bBegin = ipv4ToLong("172.16.0.0"); + long bEnd = ipv4ToLong("172.31.255.255"); + long cBegin = ipv4ToLong("192.168.0.0"); + long cEnd = ipv4ToLong("192.168.255.255"); + return isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || "127.0.0.1".equals(ipAddress); + } + + /** + * 将IPv4地址转换为长整型数字 + * + * @param strIP + * IPv4地址字符串 + * @return 转换后的长整型数字 + * @throws IllegalArgumentException + * 如果IP地址格式不正确 + */ + private static long ipv4ToLong(String strIP) { + Matcher matcher = IPV4.matcher(strIP); + if (matcher.matches()) { + return matchAddress(matcher); + } else { + throw new IllegalArgumentException("Invalid IPv4 address!"); + } + } + + /** + * 解析Matcher中的IP地址组并转换为长整型 + * + * @param matcher + * 已匹配IPv4地址的Matcher对象 + * @return 转换后的长整型IP地址 + */ + private static long matchAddress(Matcher matcher) { + long addr = 0L; + for (int i = 1; i <= 4; ++i) { + addr |= Long.parseLong(matcher.group(i)) << 8 * (4 - i); + } + return addr; + } + + /** + * 判断IP数值是否在指定范围内 + * + * @param userIp + * 用户IP转换的长整型数值 + * @param begin + * 起始IP数值 + * @param end + * 结束IP数值 + * @return true-在范围内,false-不在范围内 + */ + private static boolean isInner(long userIp, long begin, long end) { + return userIp >= begin && userIp <= end; + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/ip/RegionUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/ip/RegionUtils.java new file mode 100644 index 0000000..03af830 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/ip/RegionUtils.java @@ -0,0 +1,70 @@ +package com.sz.core.ip; + +import com.sz.core.util.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.lionsoul.ip2region.xdb.LongByteArray; +import org.lionsoul.ip2region.xdb.Searcher; +import org.lionsoul.ip2region.xdb.Version; + +import java.io.InputStream; + +/** + * 根据ip地址定位工具类,离线方式 + * + * @author sz + */ +@Slf4j +public class RegionUtils { + + // IP地址库文件名称 + public static final String IP_XDB_CLASSPATH_V4 = "region/ip2region_v4.xdb"; + + private static final Searcher SEARCHER; + + private static final Version version = Version.IPv4; + + static { + LongByteArray cBuff = null; + try (InputStream is = RegionUtils.class.getClassLoader().getResourceAsStream(IP_XDB_CLASSPATH_V4)) { + if (is == null) { + log.error("无法找到 ip2region 地址库文件: {}", IP_XDB_CLASSPATH_V4); + } else { + // 将 InputStream 转为 byte[] + byte[] bytes = is.readAllBytes(); + cBuff = new LongByteArray(bytes); + } + } catch (Exception e) { + log.error("加载ip地址库失败", e); + } + Searcher searcher = null; + try { + searcher = Searcher.newWithBuffer(version, cBuff); + } catch (Exception e) { + System.out.printf("failed to create content cached searcher: %s\n", e); + log.error("创建Region缓存搜索器失败", e); + } + SEARCHER = searcher; + } + + /** + * 根据IP地址离线获取城市 + */ + public static String getCityInfo(String ip) { + if (SEARCHER == null) { + log.error("IP地址库未初始化,无法查询IP: {}", ip); + return "未知"; + } + try { + String region = SEARCHER.search(StringUtils.trim(ip)); + if (region == null) { + log.warn("IP地址库未查询到结果: {}", ip); + return "未知"; + } + return region.replace("0|", "").replace("|0", ""); + } catch (Exception e) { + log.error("IP地址离线获取城市异常 {}", ip, e); + return "未知"; + } + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/AESUtil.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/AESUtil.java new file mode 100644 index 0000000..aaf6105 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/AESUtil.java @@ -0,0 +1,177 @@ +package com.sz.core.util; + +import javax.crypto.*; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.util.Base64; + +import static org.apache.commons.lang3.StringUtils.isBlank; + +public class AESUtil { + + private AESUtil() { + throw new IllegalStateException("Utility class"); + } + + private static final SecureRandom RANDOM = new SecureRandom(); + + private static final String ALGORITHM = "AES/GCM/NoPadding"; + + private static final int GCM_TAG_LENGTH = 16 * 8; // 128 bits + + private static final int GCM_IV_LENGTH = 12; // 96 bits + + /** + * 将byte[]转为各种进制的字符串 + * + * @param bytes + * byte[] + * @param radix + * 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制 + * @return 转换后的字符串 + */ + public static String binary(byte[] bytes, int radix) { + return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数 + } + + /** + * base 64 encode + * + * @param bytes + * 待编码的byte[] + * @return 编码后的base 64 code + */ + public static String base64Encode(byte[] bytes) { + return Base64.getEncoder().encodeToString(bytes); + } + + /** + * base 64 decode + * + * @param base64Code + * 待解码的base 64 code + * @return 解码后的byte[] + */ + public static byte[] base64Decode(String base64Code) { + Base64.Decoder decoder = Base64.getDecoder(); + return StringUtils.isEmpty(base64Code) ? null : decoder.decode(base64Code); + } + + /** + * AES加密 + * + * @param content + * 待加密的内容 + * @param encryptKey + * 加密密钥 + * @param iv + * 初始化向量 (IV),Base64 编码的字符串 + * @return 加密后的byte[] + */ + public static byte[] aesEncryptToBytes(String content, String encryptKey, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { + // 生成AES密钥 + SecretKeySpec keySpec = new SecretKeySpec(encryptKey.getBytes(StandardCharsets.UTF_8), "AES"); + + // 解码IV + byte[] ivBytes = Base64.getDecoder().decode(iv); + GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes); + + // 创建Cipher实例 + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec); + return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)); + } + + /** + * AES加密为base 64 code + * + * @param content + * 待加密的内容 + * @param encryptKey + * 加密密钥 + * @param iv + * 初始化向量 (IV),Base64 编码的字符串 + * @return 加密后的base 64 code + */ + public static String aesEncrypt(String content, String encryptKey, String iv) throws InvalidAlgorithmParameterException, NoSuchPaddingException, + IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + if (isBlank(encryptKey)) { + return content; + } + return base64Encode(aesEncryptToBytes(content, encryptKey, iv)); + } + + /** + * AES解密 + * + * @param encryptBytes + * 待解密的byte[] + * @param decryptKey + * 解密密钥 + * @param iv + * 初始化向量 (IV),Base64 编码的字符串 + * @return 解密后的String + */ + public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey, String iv) throws NoSuchAlgorithmException, NoSuchPaddingException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException { + // 解码IV + byte[] ivBytes = Base64.getDecoder().decode(iv); + GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, ivBytes); + + // 初始化密钥 + SecretKeySpec keySpec = new SecretKeySpec(decryptKey.getBytes(StandardCharsets.UTF_8), "AES"); + + // 初始化加密器 + Cipher cipher = Cipher.getInstance(ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec); + + // 执行解密 + byte[] decryptBytes = cipher.doFinal(encryptBytes); + + return new String(decryptBytes, StandardCharsets.UTF_8); + } + + /** + * 将base 64 code AES解密 + * + * @param encryptStr + * 待解密的base 64 code + * @param decryptKey + * 解密密钥 + * @param iv + * 初始化向量 (IV),Base64 编码的字符串 + * @return 解密后的string + */ + public static String aesDecrypt(String encryptStr, String decryptKey, String iv) throws InvalidAlgorithmParameterException, NoSuchPaddingException, + IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + if (isBlank(decryptKey)) { + return encryptStr; + } + return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey, iv); + } + + public static String getRandomString(int length) { + String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + int number = RANDOM.nextInt(str.length()); + sb.append(str.charAt(number)); + } + return sb.toString(); + } + + /** + * 生成AES加密的随机IV + * + * @return 随机生成的初始化向量 (IV),Base64 编码的字符串 + */ + public static String generateRandomIV() { + byte[] iv = new byte[GCM_IV_LENGTH]; + RANDOM.nextBytes(iv); + return base64Encode(iv); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/BeanCopyUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/BeanCopyUtils.java new file mode 100644 index 0000000..dbcf42a --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/BeanCopyUtils.java @@ -0,0 +1,139 @@ +package com.sz.core.util; + +import org.modelmapper.ModelMapper; +import org.modelmapper.convention.MatchingStrategies; +import org.springframework.beans.BeanUtils; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * bean copy + * + * @author sz + * @since 2021/9/1 22:04 + */ +public class BeanCopyUtils { + + private static final ModelMapper modelMapper; + + static { + modelMapper = new ModelMapper(); + modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); // 设置严格模式 + } + + private BeanCopyUtils() { + throw new IllegalStateException("BeanCopyUtils class Illegal"); + } + + /** + * !!!将在下个版本移除!!! 已弃用的方法,用于复制对象属性。 + *

+ * 此方法使用 Spring 的 `BeanUtils.copyProperties` 来复制源对象的属性到目标对象。 建议使用 `ModelMapper` + * 实现,提供更灵活和强大的映射功能。 + *

+ * + * @param + * 源对象的类型 + * @param + * 目标对象的类型 + * @param source + * 源对象 + * @param target + * 目标对象 + * @deprecated 此方法将在后续版本中弃用,请使用 `ModelMapper` 实现。 + * @since 2021-09-01 + */ + @Deprecated(since = "2021-09-01", forRemoval = true) + public static void springCopy(T source, M target) { + BeanUtils.copyProperties(source, target); + } + + /** + * !!!将在下个版本移除!!! 已弃用的方法,用于将源对象转换为指定类型的目标对象。 + *

+ * 此方法将在后续版本中弃用,建议使用 `ModelMapper` 实现以获得更灵活和强大的映射功能。 + *

+ * + * @param + * 目标对象的类型 + * @param source + * 源对象 + * @param clazz + * 目标对象的类类型 + * @return 转换后的目标对象实例 + * @deprecated 使用 `ModelMapper` 替代此方法,以支持更加灵活的对象转换。 + */ + @Deprecated(since = "2021-09-01", forRemoval = true) + public static T springCopy(Object source, Class clazz) { + T target = BeanUtils.instantiateClass(clazz); + BeanUtils.copyProperties(source, target); + return target; + } + + /** + * 使用 ModelMapper 进行对象属性复制,采用严格匹配模式。 + *

+ * 只有属性名称和类型完全一致的情况下,才会进行属性复制。此方法适用于需要精确映射的场景。 + *

+ * + * @param + * 目标对象的类型 + * @param source + * 源对象 + * @param clazz + * 目标对象的类类型 + * @return 转换后的目标对象实例 + */ + public static T copy(Object source, Class clazz) { + return modelMapper.map(source, clazz); + } + + public static M copy(T source, M target) { + modelMapper.map(source, target); + return target; + } + + /** + * 使用 ModelMapper 进行对象属性复制,严格匹配且不忽略 `null` 值。 + *

+ * 此方法在属性名称和类型完全一致时进行复制,即使属性值为 `null` 也会进行覆盖。 + *

+ * + * @param + * 源对象的类型 + * @param + * 目标对象的类型 + * @param source + * 源对象 + * @param target + * 目标对象 + * @return 无返回值,目标对象的属性会被源对象对应的属性值覆盖 + */ + public static M copyNotIgnoreNull(T source, M target) { + modelMapper.getConfiguration().setSkipNullEnabled(false); // 不跳过null值 + modelMapper.map(source, target); + return target; + } + + /** + * 使用 ModelMapper 将源列表中的每个对象复制为目标类型的对象列表。 + *

+ * 此方法通过流操作,将源列表中的每个对象映射为目标类型的新实例。适用于需要批量转换对象类型的场景。 + *

+ * + * @param + * 源列表中对象的类型 + * @param + * 目标列表中对象的类型 + * @param sourceList + * 源对象列表,包含需要转换的对象 + * @param targetClass + * 目标对象的类类型,用于指定转换的目标类型 + * @return 转换后的目标对象列表,每个对象都是 `targetClass` 类型的新实例 + */ + public static List copyList(List sourceList, Class targetClass) { + return sourceList.stream().map(source -> modelMapper.map(source, targetClass)).collect(Collectors.toList()); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/CollectorUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/CollectorUtils.java new file mode 100644 index 0000000..c6e470c --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/CollectorUtils.java @@ -0,0 +1,209 @@ +package com.sz.core.util; + +import java.util.*; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toList; + +/** + * 集合工具类 + * + * @author sz + * @since 2022/8/26 9:09 + */ +public class CollectorUtils { + + private CollectorUtils() { + throw new IllegalStateException("CollectorUtils class Illegal"); + } + + /** + * 返回两个列表的交集。 + *

+ * 此方法通过流操作,过滤出在两个列表中都存在的元素。适用于需要找出两个集合共同元素的场景。 + *

+ *

+ * 例如: + * + *

+     * list1 = [1, 2, 3]
+     * list2 = [2, 3]
+     * 结果: [2, 3]
+     * 
+ *

+ * + * @param + * 列表中元素的类型 + * @param list1 + * 第一个列表 + * @param list2 + * 第二个列表 + * @return 包含两个列表中共同元素的列表 + */ + public static List intersection(List list1, List list2) { + return list1.stream().filter(list2::contains).collect(toList()); + } + + /** + * 返回两个列表的差集,即在第一个列表中存在但在第二个列表中不存在的元素。 + *

+ * 此方法通过流操作,过滤出在第一个列表中但不在第二个列表中的元素。适用于需要找出一个列表中独有元素的场景。 + *

+ *

+ * 例如: + * + *

+     * list1 = [1, 2, 3]
+     * list2 = [2, 3]
+     * 结果: [1]
+     * 
+ *

+ * + * @param + * 列表中元素的类型 + * @param list1 + * 第一个列表 + * @param list2 + * 第二个列表 + * @return 只包含在第一个列表中但不在第二个列表中的元素的列表 + */ + public static List reduce(List list1, List list2) { + return list1.stream().filter(item -> !list2.contains(item)).collect(toList()); + } + + /** + * 返回两个列表的并集(未去重),即将两个列表的元素合并。 + *

+ * 此方法通过流操作,将两个列表的元素合并为一个新列表,保留重复元素。适用于需要将两个集合的元素合并在一起的场景。 + *

+ *

+ * 例如: + * + *

+     * list1 = [1, 2, 3]
+     * list2 = [2, 3]
+     * 结果: [1, 2, 3, 2, 3]
+     * 
+ *

+ * + * @param + * 列表中元素的类型 + * @param list1 + * 第一个列表 + * @param list2 + * 第二个列表 + * @return 合并后的列表,包含两个列表中的所有元素,未去重 + */ + public static List union(List list1, List list2) { + List listAll = new ArrayList<>(list1); // 直接用list1初始化,避免冗余的 parallelStream + listAll.addAll(list2); // 合并list2到listAll + return listAll; + } + + /** + * 返回两个列表的并集(去重),即将两个列表的元素合并并移除重复的元素。 + *

+ * 此方法通过流操作,将两个列表的元素合并,并使用 `Set` 来去除重复的元素。适用于需要将两个集合合并且确保元素唯一的场景。 + *

+ *

+ * 例如: + * + *

+     * list1 = [1, 2, 3]
+     * list2 = [2, 3, 4]
+     * 结果: [1, 2, 3, 4]
+     * 
+ *

+ * + * @param + * 列表中元素的类型 + * @param list1 + * 第一个列表 + * @param list2 + * 第二个列表 + * @return 合并后的列表,包含两个列表中的所有唯一元素 + */ + public static List unionDistinct(List list1, List list2) { + List listAll = union(list1, list2); + return listAll.stream().distinct().collect(toList()); + } + + /** + * 判断两个列表在排序后是否相同,比较它们的元素及顺序。 + *

+ * 此方法对两个列表进行排序,排序规则是根据每个元素的 `hashCode` 排序,然后比较排序后的两个列表是否相同。 + * 适用于需要判断两个列表内容是否相同,且顺序一致的场景。 + *

+ *

+ * 例如: + * + *

+     * list1 = ["apple", "banana", "cherry"]
+     * list2 = ["banana", "cherry", "apple"]
+     * 结果: true
+     * 
+ *

+ * + * @param list1 + * 第一个列表 + * @param list2 + * 第二个列表 + * @return 如果两个列表排序后相同,则返回 `true`;否则返回 `false` + */ + public static boolean listEquals(List list1, List list2) { + list1.sort(Comparator.comparing(String::hashCode)); + list2.sort(Comparator.comparing(String::hashCode)); + return list1.toString().equals(list2.toString()); + } + + /** + * 将列表转换为逗号分隔的字符串。 + *

+ * 此方法将列表中的每个元素转换为字符串,并用逗号将它们连接起来,适用于需要将列表元素合并为一个字符串的场景。 + *

+ *

+ * 例如: + * + *

+     * list = ["a", "b", "c"]
+     * 结果: "a,b,c"
+     * 
+ *

+ * + * @param + * 列表中元素的类型 + * @param list + * 需要转换的列表 + * @return 以逗号分隔的字符串,包含列表中的所有元素 + */ + public static String listToStr(List list) { + return list.stream().map(String::valueOf).collect(Collectors.joining(",")); + } + + /** + * 根据 map 的键进行 ASCII 顺序排序。 + *

+ * 此方法将传入的 `map` 按照键的 ASCII 值进行升序排序,并返回排序后的新 `map`。 如果 `map` 为 `null` 或空,方法将返回 + * `null`。 + *

+ *

+ * 例如: + * + *

+     * map = {"b":1, "d":2, "a":3, "b2":4, "c":5}
+     * 结果: {"a":3, "b":1, "b2":4, "c":5, "d":2}
+     * 
+ *

+ * + * @param map + * 待排序的 `Map`,其键将根据 ASCII 顺序排序 + * @return 排序后的 `Map`,如果输入 `map` 为 `null` 或空,则返回 `null` + */ + public static Map sortMap(Map map) { + if (map == null || map.isEmpty()) { + return Collections.emptyMap(); + } + return new TreeMap<>(map); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/DateUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/DateUtils.java new file mode 100644 index 0000000..f479eea --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/DateUtils.java @@ -0,0 +1,118 @@ +package com.sz.core.util; + +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +/** + * 时间工具类 + * + * @author sz + * @since 2022/5/28 16:44 + */ +public class DateUtils { + + private static final String DATE_PATTERN = "yyyy-MM-dd"; + + private static final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; + private DateUtils() { + throw new IllegalStateException("DateUtils class Illegal"); + } + + /** + * 获取当前日期和时间,格式化为字符串。 + *

+ * 该方法返回当前的日期和时间,格式为 `TIME_PATTERN` 指定的格式。 + *

+ * + * @return 当前日期和时间的字符串表示 + */ + public static String getCurrentDateTime() { + DateTimeFormatter df = DateTimeFormatter.ofPattern(TIME_PATTERN); + LocalDateTime now = LocalDateTime.now(); + return df.format(now); + } + + /** + * 将字符串类型的日期时间转换为 `LocalDateTime` 对象。 + *

+ * 该方法使用指定的日期时间格式(`TIME_PATTERN`)将字符串解析为 `LocalDateTime` 对象。 + *

+ * + * @param dateTime + * 日期时间字符串,必须符合 `TIME_PATTERN` 格式 + * @return 解析后的 `LocalDateTime` 对象 + */ + public static LocalDateTime getLocalDateTime(String dateTime) { + DateTimeFormatter fmt = DateTimeFormatter.ofPattern(TIME_PATTERN); + return LocalDateTime.parse(dateTime, fmt); + } + + /** + * 获取当前日期,格式化为字符串。 + *

+ * 该方法返回当前日期,格式为 `DATE_PATTERN` 指定的格式。 + *

+ * + * @return 当前日期的字符串表示 + */ + public static String getDefaultDate() { + DateTimeFormatter df = DateTimeFormatter.ofPattern(DATE_PATTERN); + LocalDateTime now = LocalDateTime.now(); + return df.format(now); + } + + /** + * 将 `Date` 对象转换为格式化后的字符串。 + *

+ * 该方法使用 `SimpleDateFormat` 将 `Date` 对象转换为 `yyyy-MM-dd HH:mm:ss` 格式的字符串。 + *

+ * + * @param datetime + * `Date` 对象 + * @return 格式化后的日期时间字符串 + */ + public static String formatDateTime(Date datetime) { + // 创建 SimpleDateFormat 实例,指定日期格式 + SimpleDateFormat sdf = new SimpleDateFormat(TIME_PATTERN); + // 使用 SimpleDateFormat 将 Date 对象转换为字符串 + return sdf.format(datetime); + } + + /** + * 将 `LocalDateTime` 对象转换为 `Date` 对象。 + *

+ * 该方法将 `LocalDateTime` 转换为 `Instant`,然后转换为 `Date`。 + *

+ * + * @param localDateTime + * `LocalDateTime` 对象 + * @return 转换后的 `Date` 对象 + */ + public static Date localDateTimeToDate(LocalDateTime localDateTime) { + // 将 LocalDateTime 转换为 Instant + Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant(); + // 将 Instant 转换为 Date + return Date.from(instant); + } + + /** + * 将 `Date` 对象转换为 `LocalDateTime` 对象。 + *

+ * 该方法将 `Date` 对象转换为 `Instant`,然后转换为 `LocalDateTime`。 + *

+ * + * @param date + * `Date` 对象 + * @return 转换后的 `LocalDateTime` 对象 + */ + public static LocalDateTime dateToLocalDateTime(Date date) { + // 将 Date 转换为 Instant + Instant instant = date.toInstant(); + // 将 Instant 转换为 LocalDateTime + return instant.atZone(ZoneId.systemDefault()).toLocalDateTime(); + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/FileUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/FileUtils.java new file mode 100644 index 0000000..0b5baca --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/FileUtils.java @@ -0,0 +1,121 @@ +package com.sz.core.util; + +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.FileCopyUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * @author sz + * @since 2023/12/25 10:01 + */ +public class FileUtils { + + private FileUtils() { + throw new IllegalStateException("FileUtils class Illegal"); + } + + /** + * 下载模板文件并写入到响应输出流中。 + *

+ * 该方法从指定路径加载模板文件,并将其内容写入到 `HttpServletResponse` 的输出流中,供客户端下载。 + *

+ * + * @param resourceLoader + * 用于加载资源的 `ResourceLoader` + * @param response + * HTTP 响应对象 + * @param templateFileName + * 模板文件名 + * @throws IOException + * 如果在读取模板文件或写入响应时发生 I/O 错误 + */ + public static void downloadTemplateFile(ResourceLoader resourceLoader, HttpServletResponse response, String templateFileName) throws IOException { + String templatePath = "classpath:/templates/" + templateFileName; + Resource resource = resourceLoader.getResource(templatePath); + OutputStream os = getOutputStream(response, templateFileName); + InputStream inputStream = resource.getInputStream(); + FileCopyUtils.copy(inputStream, os); + os.flush(); + } + + /** + * 检查给定的磁盘路径是否存在且为目录。 + *

+ * 该方法用于验证指定路径是否存在并且是一个目录。 + *

+ * + * @param path + * 待检查的路径 + * @return 如果路径存在且为目录返回 `true`,否则返回 `false` + */ + public static boolean isPathExists(String path) { + if (path == null || path.trim().isEmpty() || path.isEmpty()) { + return false; + } + Path pathObj = Paths.get(path); + return Files.exists(pathObj) && Files.isDirectory(pathObj); + } + + /** + * 获取响应的 `OutputStream`,用于文件下载。 + *

+ * 该方法设置响应头,以支持文件下载,并返回 `ServletOutputStream`。 + *

+ * + * @param response + * HTTP 响应对象 + * @param fileName + * 文件名,例如:教师统计.xlsx + * @return 用于写入文件内容的 `OutputStream` + * @throws IOException + * 如果在获取输出流时发生 I/O 错误 + */ + public static OutputStream getOutputStream(HttpServletResponse response, String fileName) throws IOException { + fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); + // 设置响应头 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName); + return response.getOutputStream(); + } + + /** + * 获取响应的 `OutputStream`,用于文件下载,并可设置内容长度。 + *

+ * 该方法设置响应头,以支持文件下载,并返回 `ServletOutputStream`,还可以指定内容长度。 + *

+ * + * @param response + * HTTP 响应对象 + * @param fileName + * 文件名,例如:教师统计.xlsx + * @param contentLength + * 文件内容长度(可选) + * @return 用于写入文件内容的 `OutputStream` + * @throws IOException + * 如果在获取输出流时发生 I/O 错误 + */ + public static OutputStream getOutputStream(HttpServletResponse response, String fileName, Integer contentLength) throws IOException { + fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); + // 设置响应头 + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName); + if (contentLength != null) { + response.setContentLength(contentLength); + } + return response.getOutputStream(); + } +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/HttpReqResUtil.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/HttpReqResUtil.java new file mode 100644 index 0000000..f1d06ae --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/HttpReqResUtil.java @@ -0,0 +1,155 @@ +package com.sz.core.util; + +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * @author sz + * @since 2023/2/21 10:04 + */ +@Slf4j +public class HttpReqResUtil { + + private HttpReqResUtil() { + throw new IllegalStateException("Utility class"); + } + + /** + * 获取客户端的IP地址。 + *

+ * 通过多种方式尝试获取客户端的真实IP地址,考虑了反向代理和多层代理的情况。 + *

+ * + * @param request + * HttpServletRequest 对象 + * @return 客户端的IP地址 + */ + public static String getIpAddress(HttpServletRequest request) { + String[] headers = {"X-Forwarded-For", "X-Real-IP", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"}; + String ip = null; + for (String header : headers) { + String value = request.getHeader(header); + if (StringUtils.isNotBlank(value) && !"unknown".equalsIgnoreCase(value)) { + // 多级代理,取第一个非 unknown 的 IP + value = value.split(",")[0].trim(); + if (!"unknown".equalsIgnoreCase(value)) { + ip = value; + break; + } + } + } + if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + // IPv6 本地回环处理 + if ("0:0:0:0:0:0:0:1".equals(ip) || "::1".equals(ip)) { + ip = "127.0.0.1"; + } + return ip; + } + private static String getHeaderIp(HttpServletRequest request, String header) { + String ip = request.getHeader(header); + if (StringUtils.isNotBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { + return ip; + } + return null; + } + + /** + * 将URL参数字符串转换为Map。 + *

+ * 解析URL参数,将键值对存储在Map中。如果参数中有键没有值,则值为空字符串。 + *

+ * + * @param param + * 包含URL参数的字符串 + * @return 包含参数键值对的Map + */ + public static Map getUrlParams(String param) { + Map map = new HashMap<>(); + if (param != null && !param.isEmpty()) { + String[] params = param.split("&"); + for (String paramPair : params) { + String[] p = paramPair.split("=", 2); // Limit the split to 2 parts + if (p.length == 2) { + String key = URLDecoder.decode(p[0], StandardCharsets.UTF_8); + String value = URLDecoder.decode(p[1], StandardCharsets.UTF_8); + map.put(key, value); + } else if (p.length == 1) { + // Handle case where there is a key without a value + String key = URLDecoder.decode(p[0], StandardCharsets.UTF_8); + map.put(key, ""); + } + } + } + return map; + } + + /** + * 获取请求体中的内容。 + *

+ * 读取并返回请求体中的所有内容,移除空格和换行符。 + *

+ * + * @param request + * ServletRequest 对象 + * @return 请求体中的字符串内容 + */ + public static String getBody(ServletRequest request) { + StringBuilder stringBuilder = new StringBuilder(); + + try (InputStream inputStream = request.getInputStream(); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) { + + char[] charBuffer = new char[128]; + int bytesRead; + while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { + stringBuilder.append(charBuffer, 0, bytesRead); + } + } catch (IOException ex) { + log.error("Error reading the request body...", ex); + } + + return stringBuilder.toString().replace(" ", "").replace("\\r\\n", ""); + } + + /** + * 获取表单参数并转换为Map。 + *

+ * 遍历请求中的所有表单参数,将它们存储在Map中。 + *

+ * + * @param request + * ServletRequest 对象 + * @return 包含表单参数的Map + */ + public static Map getParameter(ServletRequest request) { + Map paramMap = new HashMap<>(); + Enumeration parameterNames = request.getParameterNames(); + while (parameterNames.hasMoreElements()) { + String paramName = parameterNames.nextElement(); + String paramValue = request.getParameter(paramName); + paramMap.put(paramName, paramValue); + } + return paramMap; + } + + public static HttpServletRequest getRequest() { + return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/JsonUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/JsonUtils.java new file mode 100644 index 0000000..e45a337 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/JsonUtils.java @@ -0,0 +1,243 @@ +package com.sz.core.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.github.xiaoymin.knife4j.core.util.StrUtil.isBlank; + +/** + * @author sz + * @since 2022/10/8 18:59 + */ +@Slf4j +public class JsonUtils { + + private JsonUtils() { + throw new IllegalStateException("Utility class"); + } + + private static final ObjectMapper OBJECT_MAPPER = SpringApplicationContextUtils.getInstance().getBean(ObjectMapper.class); + + /** + * 读取指定路径的 JSON 文件并返回其内容。 + * + * @param filePath + * JSON 文件的路径 + * @return 文件内容的字符串表示,如果读取失败返回 null + */ + public static String readJsonFile(String filePath) { + String jsonStr; + try { + File jsonFile = new File(filePath); + Reader reader = new InputStreamReader(new FileInputStream(jsonFile), StandardCharsets.UTF_8); + int ch; + StringBuilder sb = new StringBuilder(); + while ((ch = reader.read()) != -1) { + sb.append((char) ch); + } + reader.close(); + jsonStr = sb.toString(); + return jsonStr; + } catch (Exception ex) { + log.error("readJsonFile error: {}", ex.getMessage()); + return null; + } + } + + /** + * 校验给定的字符串是否是有效的 JSON 格式。 + * + * @param jsonString + * 待验证的 JSON 字符串 + * @return 如果是有效的 JSON 返回 true,否则返回 false + */ + public static boolean isJsonValid(String jsonString) { + if (jsonString == null || jsonString.isEmpty()) { + return false; // 空字符串不是有效的 JSON + } + try { + // 使用 JsonNodeFactory 创建一个虚拟的 JSON 对象 + JsonNodeFactory nodeFactory = JsonNodeFactory.instance; + ObjectNode rootNode = nodeFactory.objectNode(); + // 尝试解析 JSON,如果解析失败会抛出异常 + OBJECT_MAPPER.readerForUpdating(rootNode).readValue(jsonString); + return true; // 解析成功,说明是有效的 JSON + } catch (Exception e) { + return false; // 解析失败,不是有效的 JSON + } + } + + /** + * 将对象转换为 JSON 字符串。 + * + * @param object + * 要转换的对象 + * @return 对象的 JSON 字符串表示,如果对象为 null 返回 null + */ + public static String toJsonString(Object object) { + if (object == null) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 将对象转换为格式化的 JSON 字符串。 + * + * @param object + * 要转换的对象 + * @return 对象的格式化 JSON 字符串表示,如果对象为 null 返回 null + */ + public static String toJsonStringPretty(Object object) { + if (object == null) { + return null; + } + try { + return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 将 JSON 字符串解析为指定类型的对象。 + * + * @param + * 目标对象的类型 + * @param text + * JSON 字符串 + * @param clazz + * 目标对象的类 + * @return 解析后的对象,如果解析失败返回 null + */ + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 使用类型引用将 JSON 字符串解析为对象。 + * + * @param + * 目标对象的类型 + * @param text + * JSON 字符串 + * @param typeReference + * 类型引用 + * @return 解析后的对象,如果解析失败返回 null + */ + public static T parseObject(String text, TypeReference typeReference) { + if (isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 将 JSON 字符串解析为带泛型参数的对象。 + * + * @param + * 目标对象的类型 + * @param text + * JSON 字符串 + * @param parametrized + * 目标对象的类 + * @param parameterClasses + * 泛型参数类 + * @return 解析后的对象,如果解析失败返回 null + */ + public static T parseObject(String text, Class parametrized, Class... parameterClasses) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructParametricType(parametrized, parameterClasses)); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 将 JSON 字符串转换为 Map 对象。 + * + * @param jsonString + * JSON 字符串 + * @return 包含键值对的 Map,如果解析失败抛出异常 + */ + public static Map jsonToMap(String jsonString) { + try { + return OBJECT_MAPPER.readValue(jsonString, new TypeReference>() { + }); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 将 JSON 字符串解析为指定类型的列表。 + * + * @param + * 列表元素的类型 + * @param text + * JSON 字符串 + * @param clazz + * 列表元素的类 + * @return 解析后的列表,如果解析失败返回空列表 + */ + public static List parseArray(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 使用类型引用将 JSON 字符串解析为列表。 + * + * @param + * 列表元素的类型 + * @param text + * JSON 字符串 + * @param typeReference + * 类型引用 + * @return 解析后的列表,如果解析失败返回空列表 + */ + public static List parseArray(String text, TypeReference> typeReference) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/PageUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/PageUtils.java new file mode 100644 index 0000000..dae4e80 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/PageUtils.java @@ -0,0 +1,136 @@ +package com.sz.core.util; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.mybatisflex.core.paginate.Page; +import com.sz.core.common.entity.PageQuery; +import com.sz.core.common.entity.PageResult; +import com.sz.core.datascope.SimpleDataScopeHelper; + +import java.util.List; + +/** + * 工具类:提供基于列表构建 PageResult 对象的各种方法。 用于分页处理,兼容不同的数据源和需求。 + * + * @author sz + * @since 2022/8/25 + */ +public class PageUtils { + + // 私有构造函数防止实例化 + private PageUtils() { + throw new IllegalStateException("PageUtils class Illegal"); + } + + /** + * 使用 PageHelper 构建 PageResult 对象。 + * + * @param list + * 数据列表 + * @param + * 列表中元素的类型 + * @return 包含分页信息的 PageResult 对象 + */ + public static PageResult getPageResult(List list) { + PageInfo pageInfo = new PageInfo<>(list); + return new PageResult<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getPages(), pageInfo.getTotal(), pageInfo.getList()); + } + + /** + * 使用 PageHelper 构建 PageResult 对象,并替换结果列表。 + * + * @param list + * 原始数据列表 + * @param replaceList + * 替换后的数据列表 + * @param + * 原始列表中元素的类型 + * @param + * 替换列表中元素的类型 + * @return 包含分页信息的 PageResult 对象,列表被替换为 replaceList + */ + public static PageResult getPageResult(List list, List replaceList) { + PageInfo pageInfo = new PageInfo<>(list); + return new PageResult<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getPages(), pageInfo.getTotal(), replaceList); + } + + /** + * 根据当前页、每页条数、数据列表和总记录数构建 PageResult 对象。 + * + * @param current + * 当前页 + * @param limit + * 每页展示的最大条数 + * @param list + * 数据列表 + * @param total + * 总记录数 + * @param + * 列表中元素的类型 + * @return 包含分页信息的 PageResult 对象 + */ + public static PageResult getPageResult(int current, int limit, List list, int total) { + int totalPage = getTotalPage(total, limit); + return new PageResult<>(current, limit, totalPage, total, list); + } + + /** + * 根据分页查询对象构建 Page 对象。 + * + * @param query + * 分页查询对象 + * @param + * 分页中记录的类型 + * @return Page 对象,包含分页信息 + */ + public static Page getPage(PageQuery query) { + Page page = Page.of(query.getPage(), query.getLimit()); + if (SimpleDataScopeHelper.isDataScope()) + page.setOptimizeCountQuery(false); // 数据权限时,关闭优化查询。 + return page; + } + + /** + * 将 Page 对象转换为 PageResult 对象。 + * + * @param page + * Page 对象 + * @param + * 页中记录的类型 + * @return 包含分页信息的 PageResult 对象 + */ + public static PageResult getPageResult(Page page) { + return new PageResult<>(page.getPageNumber(), page.getPageSize(), page.getTotalPage(), page.getTotalRow(), page.getRecords()); + } + + /** + * 计算总页数。 + * + * @param total + * 总记录数 + * @param limit + * 每页记录数 + * @return 总页数 + */ + public static int getTotalPage(int total, int limit) { + int page = 0; + if (total > 0) { + page = total / limit; + if (total % limit != 0) { + page += 1; + } + } + return page; + } + + /** + * 设置分页参数,用于分页查询。 + * + * @param dto + * 包含分页信息的查询对象 + */ + public static void toPage(PageQuery dto) { + PageHelper.startPage(dto.getPage(), dto.getLimit()); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/SlidePuzzleUtil.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SlidePuzzleUtil.java new file mode 100644 index 0000000..c309358 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SlidePuzzleUtil.java @@ -0,0 +1,294 @@ +package com.sz.core.util; + +import com.sz.core.common.entity.PointVO; +import com.sz.core.common.entity.SliderPuzzle; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.SecureRandom; +import java.util.Base64; + +@Slf4j +public class SlidePuzzleUtil { + + private SlidePuzzleUtil() { + throw new IllegalStateException("Utility class"); + } + + private static final SecureRandom RANDOM = new SecureRandom(); + + private static final Integer BIG_WIDTH = 320; + + private static final Integer BIG_HEIGHT = 160; + + private static final Integer SMALL_WIDTH = 50; + + private static final Integer SMALL_HEIGHT = 50; + + private static final Integer SMALL_CIRCLE = 10; + + private static final Integer SMALL_CIRCLE_R_1 = 2; + + public static SliderPuzzle createImage(InputStream input, HttpServletRequest request) { + SliderPuzzle sliderPuzzle = new SliderPuzzle(); + try { + String requestId = Utils.generateSha256Id(Utils.generateAgentRequestId(request)); + + BufferedImage originalImage = ImageIO.read(input); + BufferedImage bigImage = resizeImage(originalImage, BIG_WIDTH, BIG_HEIGHT, true); + + String watermark = SysConfigUtils.getConfValue("sys.captcha.waterText"); // 水印文字 + String waterState = SysConfigUtils.getConfValue("sys.captcha.waterEnable"); // 是否启用水印 + String waterFont = SysConfigUtils.getConfValue("sys.captcha.waterFont"); // 是否启用水印 + + if ("true".equals(waterState)) { + // Add watermark + Graphics2D g2d = bigImage.createGraphics(); + Font font = new Font(waterFont, Font.BOLD, 20); // 要注意服务器是否有此字体,如果商用要考虑字体版权问题。 + g2d.setFont(font); + g2d.setColor(Color.WHITE); + FontMetrics fontMetrics = g2d.getFontMetrics(); + int x = bigImage.getWidth() - fontMetrics.stringWidth(watermark) - 10; + int y = bigImage.getHeight() - fontMetrics.getHeight() + 20; + g2d.drawString(watermark, x, y); + g2d.dispose(); + } + + String secretKey = AESUtil.getRandomString(16); + PointVO jigsawPoint = generateJigsawPoint(BIG_WIDTH, BIG_HEIGHT, SMALL_WIDTH, SMALL_HEIGHT, secretKey); + int randomX = jigsawPoint.getX(); + int randomY = jigsawPoint.getY(); + + BufferedImage smallImage = new BufferedImage(SMALL_WIDTH, SMALL_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR); + int[][] slideTemplateData = getSlideTemplateData(); + cutByTemplate(bigImage, smallImage, slideTemplateData, randomX, randomY); + + sliderPuzzle.setRequestId(requestId); + sliderPuzzle.setPosX(randomX); + sliderPuzzle.setPosY(randomY); + sliderPuzzle.setBigWidth(BIG_WIDTH); + sliderPuzzle.setBigHeight(BIG_HEIGHT); + sliderPuzzle.setBigImageBase64(getImageBASE64(bigImage)); + sliderPuzzle.setSmallWidth(SMALL_WIDTH); + sliderPuzzle.setSmallHeight(SMALL_HEIGHT); + sliderPuzzle.setSmallImageBase64(getImageBASE64(smallImage)); + sliderPuzzle.setSecretKey(jigsawPoint.getSecretKey()); + return sliderPuzzle; + } catch (Exception e) { + log.error("生成验证码异常: {}", e.getMessage()); + return null; + } + } + + private static PointVO generateJigsawPoint(int originalWidth, int originalHeight, int jigsawWidth, int jigsawHeight, String secretKey) { + int widthDifference = originalWidth - jigsawWidth; + int heightDifference = originalHeight - jigsawHeight; + int x, y; + + if (widthDifference <= 0) { + x = 5; + } else { + x = RANDOM.nextInt(widthDifference - 100) + 100 + RANDOM.nextInt(20) - 10; // Adding variability + } + + if (heightDifference <= 0) { + y = 5; + } else { + y = RANDOM.nextInt(heightDifference) + 5 + RANDOM.nextInt(20) - 10; // Adding variability + } + + return new PointVO(x, y, secretKey); + } + + private static int[][] getSlideTemplateData() { + int[][] data = new int[SMALL_WIDTH][SMALL_HEIGHT]; + + // 计算常量 + double xBlank = (double) SMALL_WIDTH - SMALL_CIRCLE - SMALL_CIRCLE_R_1; + double yBlank = (double) SMALL_HEIGHT - SMALL_CIRCLE - SMALL_CIRCLE_R_1; + double rxa = xBlank / 2.0; + double ryb = (double) SMALL_HEIGHT - SMALL_CIRCLE; + double rPow = Math.pow(SMALL_CIRCLE, 2); + + for (int i = 0; i < SMALL_WIDTH; i++) { + for (int j = 0; j < SMALL_HEIGHT; j++) { + // 显式类型转换 + double topR = Math.pow(i - rxa, 2) + Math.pow(j - 2.0, 2); + double downR = Math.pow(i - rxa, 2) + Math.pow(j - ryb, 2); + double rightR = Math.pow(i - ryb, 2) + Math.pow(j - rxa, 2); + + if ((j <= yBlank && topR <= rPow) || (j >= yBlank && downR >= rPow) || (i >= xBlank && rightR >= rPow)) { + data[i][j] = 0; + } else { + data[i][j] = 1; + } + } + } + return data; + } + + private static void cutByTemplate(BufferedImage bigImage, BufferedImage smallImage, int[][] slideTemplateData, int x, int y) { + int[][] martrix = new int[3][3]; + int[] values = new int[9]; + int yBlank = SMALL_HEIGHT - SMALL_CIRCLE - SMALL_CIRCLE_R_1; + + Graphics2D g2dBig = bigImage.createGraphics(); + Graphics2D g2dSmall = smallImage.createGraphics(); + g2dBig.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2dSmall.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + for (int i = 0; i < smallImage.getWidth(); i++) { + for (int j = 0; j < smallImage.getHeight(); j++) { + if (x + i >= bigImage.getWidth() || y + j >= bigImage.getHeight() || x + i < 0 || y + j < 0) { + continue; // Skip if out of bounds + } + int rgbOri = bigImage.getRGB(x + i, y + j); + int rgb = slideTemplateData[i][j]; + if (rgb == 1) { + smallImage.setRGB(i, j, rgbOri); + readPixel(bigImage, x + i, y + j, values); + fillMatrix(martrix, values); + bigImage.setRGB(x + i, y + j, avgMatrix(martrix)); + + Color white = new Color(255, 255, 255); + if (j < yBlank) { + bigImage.setRGB(x, y + j, white.getRGB()); + smallImage.setRGB(0, j, white.getRGB()); + } + } else { + smallImage.setRGB(i, j, rgbOri & 0x00ffffff); + } + } + } + + // Enhance the contour by making it thicker and white for both big and small + // images + for (int i = 0; i < smallImage.getWidth(); i++) { + for (int j = 0; j < smallImage.getHeight(); j++) { + if (x + i >= bigImage.getWidth() || y + j >= bigImage.getHeight() || x + i < 0 || y + j < 0) { + continue; // Skip if out of bounds + } + if (slideTemplateData[i][j] == 0) { + if (i > 0 && slideTemplateData[i - 1][j] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + if (i < smallImage.getWidth() - 1 && slideTemplateData[i + 1][j] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + if (j > 0 && slideTemplateData[i][j - 1] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + if (j < smallImage.getHeight() - 1 && slideTemplateData[i][j + 1] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + // Additional checks for diagonal neighbors + if (i > 0 && j > 0 && slideTemplateData[i - 1][j - 1] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + if (i > 0 && j < smallImage.getHeight() - 1 && slideTemplateData[i - 1][j + 1] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + if (i < smallImage.getWidth() - 1 && j > 0 && slideTemplateData[i + 1][j - 1] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + if (i < smallImage.getWidth() - 1 && j < smallImage.getHeight() - 1 && slideTemplateData[i + 1][j + 1] == 1) { + bigImage.setRGB(x + i, y + j, Color.white.getRGB()); + smallImage.setRGB(i, j, Color.white.getRGB()); + } + } + } + } + + g2dBig.dispose(); + g2dSmall.dispose(); + } + + public static String getImageBASE64(BufferedImage image) throws IOException { + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + ImageIO.write(image, "png", bao); + byte[] imagedata = bao.toByteArray(); + return Base64.getEncoder().encodeToString(imagedata); + } + + public static BufferedImage resizeImage(final Image image, int width, int height, boolean type) { + BufferedImage bufferedImage; + if (type) { + bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + } else { + bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + } + final Graphics2D graphics2D = bufferedImage.createGraphics(); + graphics2D.setComposite(AlphaComposite.Src); + graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.drawImage(image, 0, 0, width, height, null); + graphics2D.dispose(); + return bufferedImage; + } + + private static void readPixel(BufferedImage img, int x, int y, int[] pixels) { + int xStart = x - 1; + int yStart = y - 1; + int current = 0; + for (int i = xStart; i < 3 + xStart; i++) { + for (int j = yStart; j < 3 + yStart; j++) { + int tx = i; + if (tx < 0) { + tx = -tx; + } else if (tx >= img.getWidth()) { + tx = x; + } + int ty = j; + if (ty < 0) { + ty = -ty; + } else if (ty >= img.getHeight()) { + ty = y; + } + pixels[current++] = img.getRGB(tx, ty); + } + } + } + + private static void fillMatrix(int[][] matrix, int[] values) { + int filled = 0; + for (int[] x : matrix) { + for (int j = 0; j < x.length; j++) { + x[j] = values[filled++]; + } + } + } + + private static int avgMatrix(int[][] matrix) { + int r = 0; + int g = 0; + int b = 0; + for (int i = 0; i < matrix.length; i++) { + int[] x = matrix[i]; + for (int j = 0; j < x.length; j++) { + if (j == 1) { + continue; + } + Color c = new Color(x[j]); + r += c.getRed(); + g += c.getGreen(); + b += c.getBlue(); + } + } + return new Color(r / 8, g / 8, b / 8).getRGB(); + } + +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/SocketUtil.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SocketUtil.java new file mode 100644 index 0000000..abaa0cf --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SocketUtil.java @@ -0,0 +1,25 @@ +package com.sz.core.util; + +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; + +import java.util.List; + +/** + * @author sz + * @since 2023/9/6 17:27 + */ +public class SocketUtil { + + public static String transferMessage(SocketMessage bean) { + return JsonUtils.toJsonString(bean); + } + + public static TransferMessage pubTransferMessage(SocketMessage sb, List usernames) { + TransferMessage transferMessage = new TransferMessage(); + transferMessage.setMessage(sb); + transferMessage.setToUsers(usernames); + return transferMessage; + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/SpringApplicationContextUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SpringApplicationContextUtils.java new file mode 100644 index 0000000..68a1757 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SpringApplicationContextUtils.java @@ -0,0 +1,126 @@ +package com.sz.core.util; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * Spring 工具类:用于在非 Spring 管理的环境中获取 Bean,方便在非 Spring IoC 中使用。 提供获取 Bean、注册 + * Bean、环境配置等实用功能。 + */ +@Component +public class SpringApplicationContextUtils implements BeanFactoryPostProcessor, ApplicationContextAware { + + private ConfigurableListableBeanFactory beanFactory; + + private ApplicationContext applicationContext; + + private static final String[] localEnv = {"dev", "local"}; + + private SpringApplicationContextUtils() { + // 私有构造函数防止实例化 + } + + private static class Holder { + + private static final SpringApplicationContextUtils INSTANCE = new SpringApplicationContextUtils(); + } + + public static SpringApplicationContextUtils getInstance() { + return Holder.INSTANCE; + } + + @Override + public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException { + SpringApplicationContextUtils.getInstance().beanFactory = beanFactory; + } + + @Override + public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { + SpringApplicationContextUtils.getInstance().applicationContext = applicationContext; + } + + public T getBean(String name) throws BeansException { + return (T) beanFactory.getBean(name); + } + + public T getBean(Class clz) throws BeansException { + return beanFactory.getBean(clz); + } + + public boolean containsBean(String name) { + return beanFactory.containsBean(name); + } + + public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return beanFactory.isSingleton(name); + } + + public Class getType(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getType(name); + } + + public String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return beanFactory.getAliases(name); + } + + public T getAopProxy(T invoker) { + return (T) AopContext.currentProxy(); + } + + public String[] getActiveProfiles() { + return applicationContext.getEnvironment().getActiveProfiles(); + } + + public T registerBean(String beanName, Class clazz, Function function) { + BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz); + AbstractBeanDefinition beanDefinition = function.apply(beanDefinitionBuilder); + BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) this.beanFactory; + if (isNotBlank(beanName) && !containsBean(beanName)) { + beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition); + return getBean(beanName); + } else { + String name = BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, beanDefinitionRegistry); + return getBean(name); + } + } + + public T registerBean(String beanName, Class clazz, List args, Map property) { + return registerBean(beanName, clazz, beanDefinitionBuilder -> { + if (!CollectionUtils.isEmpty(args)) { + args.forEach(beanDefinitionBuilder::addConstructorArgValue); + } + if (!CollectionUtils.isEmpty(property)) { + property.forEach(beanDefinitionBuilder::addPropertyValue); + } + return beanDefinitionBuilder.getBeanDefinition(); + }); + } + + public String getActive() { + return applicationContext.getEnvironment().getActiveProfiles()[0]; + } + + public boolean isLocalEnv() { + List localEnvArr = Arrays.asList(localEnv); + return localEnvArr.contains(getActive()); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/StreamUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/StreamUtils.java new file mode 100644 index 0000000..ce3a822 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/StreamUtils.java @@ -0,0 +1,52 @@ +package com.sz.core.util; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author sz + * @since 2023/12/27 8:39 + */ +public class StreamUtils { + + private StreamUtils() { + throw new IllegalStateException("StreamUtils class Illegal"); + } + + /** + * 将Collection转化为map(value类型与collection的泛型不同)
+ * {@code Collection -----> Map } + * + * @param collection + * 需要转化的集合 + * @param key + * E类型转化为K类型的lambda方法 + * @param value + * E类型转化为V类型的lambda方法 + * @param + * collection中的泛型 + * @param + * map中的key类型 + * @param + * map中的value类型 + * @return 转化后的map + */ + public static Map toMap(Collection collection, Function key, Function value) { + if (collection == null || collection.isEmpty()) { + return new HashMap<>(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l)); + } + + public static String listToStr(Collection collection) { + if (collection == null || collection.isEmpty()) { + return ""; + } + return String.join(",", collection); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/StringUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/StringUtils.java new file mode 100644 index 0000000..b760682 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/StringUtils.java @@ -0,0 +1,683 @@ +package com.sz.core.util; + +import org.springframework.util.AntPathMatcher; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.apache.commons.lang3.StringUtils.containsIgnoreCase; +import static org.apache.commons.lang3.StringUtils.isBlank; + +/** + * @author sz + * @since 2021/9/7 8:02 + */ +public class StringUtils { + + private StringUtils() { + throw new IllegalStateException("Utility class"); + } + + /** + * 空字符串 + */ + private static final String NULL_STR = ""; + + /** + * 下划线 + */ + private static final char SEPARATOR = '_'; + + /** + * 将字符串的首字母转换为小写。 + * + * @param s + * 要转换的字符串 + * @return 首字母小写的字符串,如果首字母已是小写,则返回原字符串 + * @author sz + * @since 2021-09-15 + */ + public static String toLowerCaseFirstOne(String s) { + if (Character.isLowerCase(s.charAt(0))) { + return s; + } else { + return Character.toLowerCase(s.charAt(0)) + s.substring(1); + } + } + + /** + * 将字符串的首字母转换为大写。 + * + * @param s + * 要转换的字符串 + * @return 首字母大写的字符串,如果首字母已是大写,则返回原字符串 + * @author sz + * @since 2021-09-15 + */ + public static String toUpperCaseFirstOne(String s) { + if (Character.isUpperCase(s.charAt(0))) { + return s; + } else { + return Character.toUpperCase(s.charAt(0)) + s.substring(1); + } + } + + /** + * 使用正则表达式替换字符串中的匹配部分。 + * + * @param str + * 源字符串 + * @param pattern + * 正则表达式 + * @param replaceArrValue + * 替换值的数组,按顺序应用 + * @return 替换后的字符串 + * @since 2021-11-25 14:19:50 + */ + public static String getRealKey(String str, String pattern, String[] replaceArrValue) { + Matcher match = Pattern.compile(pattern).matcher(str); + List matchList = new ArrayList<>(); + while (match.find()) { + matchList.add(match.group(1)); + } + try { + for (int i = 0; i < replaceArrValue.length; i++) { + String replacement = replaceArrValue[i] == null ? "" : replaceArrValue[i]; + str = str.replace(matchList.get(i), replacement); + } + return str; + } catch (Exception e) { + System.err.println("getRealKey error, str: " + str + ", pattern: " + pattern + ", matchList: " + matchList + ", replaceArrValue: " + + Arrays.toString(replaceArrValue)); + e.printStackTrace(); + throw e; + } + } + + public static String getRealKey(String sourceKey, String... replaceArrValue) { + String pattern = "(\\$\\{\\w+\\})"; + return getRealKey(sourceKey, pattern, replaceArrValue); + } + + public static String replacePlaceholders(String input, String... args) { + // 编译一个正则表达式模式,用于匹配 ${...} 形式的占位符 + Pattern pattern = Pattern.compile("\\$\\{([^}]+)}"); + Matcher matcher = pattern.matcher(input); + + // 使用StringBuilder来构建最终的字符串,它比StringBuffer更高效 + StringBuilder result = new StringBuilder(); + + // 用于跟踪args参数的索引 + int index = 0; + + // 使用Matcher的find和appendReplacement方法来逐步替换占位符 + while (matcher.find()) { + // 检查是否有足够的参数来替换占位符 + String replacement = (index < args.length) ? args[index] : matcher.group(); + matcher.appendReplacement(result, Matcher.quoteReplacement(replacement)); + index++; + } + + // 追加未替换部分的尾部到结果中 + matcher.appendTail(result); + + // 返回最终构建的字符串 + return result.toString(); + } + + public static String subWithLength(String str, int start, int length) { + // 防止索引越界 + if (start < 0) { + start = 0; + } + if (start >= str.length()) { + return ""; + } + + // 计算截取的结束索引 + int end = Math.min(start + length, str.length()); + + return str.substring(start, end); + } + + public static String toSnakeCase(String camelCase) { + if (camelCase == null || camelCase.isEmpty()) { + return camelCase; + } + + StringBuilder result = new StringBuilder(); + result.append(camelCase.substring(0, 1).toLowerCase()); // 将首字母转小写并添加到结果 + + for (int i = 1; i < camelCase.length(); i++) { + char c = camelCase.charAt(i); + if (Character.isUpperCase(c)) { + // 如果当前字符是大写字母,添加下划线并转换为小写 + result.append("_").append(Character.toLowerCase(c)); + } else { + // 否则,直接添加当前字符 + result.append(c); + } + } + return result.toString(); + } + + /** + * 获取参数不为空值 + * + * @param value + * defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll + * 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll + * 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects + * 要判断的对象数组 * @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects + * 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map + * 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map + * 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str + * String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return isNull(str) || NULL_STR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str + * String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object + * Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object + * Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object + * 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str + * 字符串 + * @param start + * 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + if (str == null) { + return NULL_STR; + } + + if (start < 0) { + start = str.length() + start; + } + + if (start < 0) { + start = 0; + } + if (start > str.length()) { + return NULL_STR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str + * 字符串 + * @param start + * 开始 + * @param end + * 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + if (str == null) { + return NULL_STR; + } + + if (end < 0) { + end = str.length() + end; + } + if (start < 0) { + start = str.length() + start; + } + + if (end > str.length()) { + end = str.length(); + } + + if (start > end) { + return NULL_STR; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 字符串转set + * + * @param str + * 字符串 + * @param sep + * 分隔符 + * @return set集合 + */ + public static Set str2Set(String str, String sep) { + return new HashSet<>(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str + * 字符串 + * @param sep + * 分隔符 + * @param filterBlank + * 过滤纯空白 + * @param trim + * 去掉首尾空白 + * @return list集合 + */ + public static List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList<>(); + if (StringUtils.isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && isBlank(string)) { + continue; + } + if (trim) { + string = string.trim(); + } + list.add(string); + } + + return list; + } + + /** + * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value + * + * @param collection + * 给定的集合 + * @param array + * 给定的数组 + * @return boolean 结果 + */ + public static boolean containsAny(Collection collection, String... array) { + if (isEmpty(collection) || isEmpty(array)) { + return false; + } else { + for (String str : array) { + if (collection.contains(str)) { + return true; + } + } + return false; + } + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs + * 指定字符串 + * @param searchCharSequences + * 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + if (isEmpty((Collection) cs) || isEmpty(searchCharSequences)) { + return false; + } + for (CharSequence testStr : searchCharSequences) { + if (containsIgnoreCase(cs, testStr)) { + return true; + } + } + return false; + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) { + if (str == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase; + // 当前字符是否大写 + boolean curreCharIsUpperCase; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (i > 0) { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } else { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { + sb.append(SEPARATOR); + } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str + * 验证字符串 + * @param strs + * 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + if (str != null && strs != null) { + for (String s : strs) { + if (str.equalsIgnoreCase(trim(s))) { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 + * 例如:HELLO_WORLD->HelloWorld + * + * @param name + * 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) { + // 没必要转换 + return ""; + } else if (!name.contains("_")) { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + if (s == null) { + return null; + } + if (s.indexOf(SEPARATOR) == -1) { + return s; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str + * 指定字符串 + * @param strs + * 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: ? 表示单个字符; * 表示一层路径内的任意字符串,不可跨层级; ** 表示任意层路径; + * + * @param pattern + * 匹配规则 + * @param url + * 需要匹配的url + * @return 是否匹配 + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) { + return (T) obj; + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num + * 数字对象 + * @param size + * 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static String padl(final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s + * 原始字符串 + * @param size + * 字符串指定长度 + * @param c + * 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static String padl(final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + for (int i = size - len; i > 0; i--) { + sb.append(c); + } + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + for (int i = size; i > 0; i--) { + sb.append(c); + } + } + return sb.toString(); + } + + public static String extractAndLowercase(String input) { + if (input == null || input.isEmpty()) { + return ""; + } + + int underscoreIndex = input.indexOf('_'); + if (underscoreIndex != -1) { + // If underscore exists, extract substring before the first underscore + return input.substring(0, underscoreIndex).toLowerCase(); + } else { + // If no underscore, use the entire string and convert to lowercase + return input.toLowerCase(); + } + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/SysConfigUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SysConfigUtils.java new file mode 100644 index 0000000..d8c8e8e --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/SysConfigUtils.java @@ -0,0 +1,41 @@ +package com.sz.core.util; + +import com.sz.core.common.service.ConfService; + +/** + * 工具类,用于获取系统配置信息。 + * + * @since 2024-01-10 + * @version 1.0 + */ +public class SysConfigUtils { + + private SysConfigUtils() { + throw new IllegalStateException("SysConfigUtils class Illegal"); + } + + /** + * 根据指定的键获取配置信息的值。 + * + * @param key + * 配置项的键 + * @return 配置项的值 + */ + public static String getConfValue(String key) { + ConfService confService = SpringApplicationContextUtils.getInstance().getBean(ConfService.class); + return confService.getConfValue(key); + } + + /** + * 检查指定的配置项是否存在。 + * + * @param key + * 配置项的键 + * @return 如果配置项存在,则返回 true;否则返回 false + */ + public static boolean hasConf(String key) { + ConfService confService = SpringApplicationContextUtils.getInstance().getBean(ConfService.class); + return confService.hasConfKey(key); + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/TreeUtils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/TreeUtils.java new file mode 100644 index 0000000..3a993f3 --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/TreeUtils.java @@ -0,0 +1,166 @@ +package com.sz.core.util; + +import com.sz.core.common.service.Treeable; + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +/** + * 工具类,用于构建以 ID 和 PID 为关联标识的树形结构。 + * + * @since 2024-03-22 + * @version 1.0 + */ +public class TreeUtils { + + private TreeUtils() { + throw new IllegalStateException("Utility class"); + } + + /** + * 构建树形结构。 + * + * @param allDepts + * 所有部门列表 + * @param root + * 自定义根节点 + * @param + * 树节点类型 + * @return 树形结构列表 + */ + public static > List buildTree(List allDepts, T root) { + List trees = new ArrayList<>(); + // 构建树形结构 + constructTreeRecursive(root, allDepts); + trees.add(root); + return trees; + } + + /** + * 构建树形结构,支持排除指定节点。 + * + * @param allDepts + * 所有部门列表 + * @param excludeNodeId + * 排除的节点 ID + * @param root + * 自定义根节点 + * @param + * 树节点类型 + * @return 树形结构列表 + */ + public static > List buildTree(List allDepts, T root, Object excludeNodeId) { + List trees = new ArrayList<>(); + // 构建树形结构 + if (excludeNodeId != null) { + constructTreeRecursiveExcludeNode(root, allDepts, excludeNodeId); + } else { + constructTreeRecursive(root, allDepts); + } + trees.add(root); + return trees; + } + + /** + * 构建树形结构(不需要自定义根节点)。 自动查找所有顶级节点(pid == null 或 pid == -1),并递归构建树。 + * + * @param allDepts + * 所有部门列表 + * @param + * 树节点类型 + * @return 树形结构列表 + */ + public static > List buildTree(List allDepts, Object startNodeId) { + List roots = new ArrayList<>(); + if (allDepts == null || allDepts.isEmpty()) { + return roots; + } + for (T node : allDepts) { + Object pid = node.getPid(); + if (pid == null || String.valueOf(startNodeId).equals(String.valueOf(pid))) { + constructTreeRecursive(node, allDepts); + roots.add(node); + } + } + return roots; + } + + /** + * 递归构建树形结构。 + * + * @param parent + * 父节点 + * @param allDepts + * 所有部门列表 + * @param + * 树节点类型 + */ + private static > void constructTreeRecursive(T parent, List allDepts) { + for (T dept : allDepts) { + if (parent.getChildren() == null) { + parent.setChildren(new ArrayList<>()); + } + // 类型兼容比较 + if (parent.getId() != null && dept.getPid() != null && String.valueOf(dept.getPid()).equals(String.valueOf(parent.getId()))) { + // 递归构建子部门的子部门 + constructTreeRecursive(dept, allDepts); + // 将子部门添加��父部门的子级列表中 + parent.getChildren().add(dept); + } + } + } + + /** + * 递归构建树形结构,支持排除指定节点。 + * + * @param parent + * 父节点 + * @param allDepts + * 所有部门列表 + * @param excludeNodeId + * 排除的节点 ID + * @param + * 树节点类型 + */ + private static > void constructTreeRecursiveExcludeNode(T parent, List allDepts, Object excludeNodeId) { + for (T dept : allDepts) { + if (parent.getChildren() == null) { + parent.setChildren(new ArrayList<>()); + } + // 类型兼容比较 + if (parent.getId() != null && dept.getPid() != null && String.valueOf(dept.getPid()).equals(String.valueOf(parent.getId())) + && !String.valueOf(dept.getId()).equals(String.valueOf(excludeNodeId))) { + // 递归构建子部门的子部门 + constructTreeRecursiveExcludeNode(dept, allDepts, excludeNodeId); + + // 将子部门添加到父部门的子级列表中 + parent.getChildren().add(dept); + } + } + } + + /** + * 获取树的根节点。 + * + * @param clazz + * 树节点类型 + * @param + * 树节点类型 + * @return 根节点 + */ + public static > T getRoot(Class clazz) { + try { + T root = clazz.getDeclaredConstructor().newInstance(); + clazz.getMethod("setId", Long.class).invoke(root, 0L); + clazz.getMethod("setPid", Long.class).invoke(root, -1L); + return root; + } catch (InstantiationException | IllegalAccessException e) { + // 处理异常 + return null; + } catch (InvocationTargetException | NoSuchMethodException e) { + throw new IllegalArgumentException(e); + } + } + +} diff --git a/sz-common/sz-common-core/src/main/java/com/sz/core/util/Utils.java b/sz-common/sz-common-core/src/main/java/com/sz/core/util/Utils.java new file mode 100644 index 0000000..fec097b --- /dev/null +++ b/sz-common/sz-common-core/src/main/java/com/sz/core/util/Utils.java @@ -0,0 +1,155 @@ +package com.sz.core.util; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.util.DigestUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +/** + * @author sz + * @since 2022/8/23 10:20 + */ +public class Utils { + + private static final String UNKNOWN = "null"; + + private Utils() { + throw new IllegalStateException("Utils class Illegal"); + } + + public static String generateUUIDs() { + return UUID.randomUUID().toString().replace("-", ""); + } + + public static boolean isNotNull(String str) { + return str != null && !str.trim().isEmpty(); + } + + public static boolean isNotNull(Integer str) { + return str != null; + } + + public static boolean isNotNull(Boolean str) { + return str != null; + } + + public static boolean isNotNull(Double str) { + return str != null; + } + + public static boolean isNotNull(MultipartFile file) { + return file != null && !file.isEmpty(); + } + + public static boolean isNotNull(Object obj) { + return obj != null && !"".equals(obj) && !obj.toString().trim().isEmpty(); + } + + public static boolean isNotNull(Map map) { + return map != null && !map.isEmpty(); + } + + public static boolean isNotNull(Collection collection) { + return collection != null && !collection.isEmpty(); + } + + public static Integer getIntVal(Object obj) { + return (isNotNull(obj) && !(UNKNOWN).equals(obj)) ? (Integer.valueOf(obj.toString())) : 0; + } + + public static Long getLongVal(Object obj) { + return (isNotNull(obj) && !(UNKNOWN).equals(obj)) ? (Long.valueOf(obj.toString())) : 0L; + } + + public static String getStringVal(Object obj) { + if (isNotNull(obj) && !(UNKNOWN).equals(obj)) { + return obj.toString(); + } else { + return ""; + } + } + + public static String getTraceId() { + return generateUUIDs(); + } + + public static String md5(String str) { + return DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8)); + } + + public static Field[] getFields(Class clazz) { + List fieldList = new ArrayList<>(); + while (clazz != null) { + Field[] declaredFields = clazz.getDeclaredFields(); + for (Field field : declaredFields) { + // Do not increase accessibility + if (java.lang.reflect.Modifier.isPublic(field.getModifiers())) { + fieldList.add(field); + } + } + clazz = clazz.getSuperclass(); + } + return fieldList.toArray(new Field[0]); + } + + public static Object invokeGetter(Object obj, String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + String getterName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); + Method getter = obj.getClass().getMethod(getterName); + return getter.invoke(obj); + } + + /** + * 生成用于接口防抖的RequestId + * + * @param request + * HttpServletRequest对象 + * @return 接口防抖用的RequestId + */ + public static String generateDebounceRequestId(HttpServletRequest request) { + String ip = HttpReqResUtil.getIpAddress(request); + String uri = request.getRequestURI(); + String method = request.getMethod(); + String userAgent = request.getHeader("User-Agent"); + String queryString = request.getQueryString(); + return ip + ":" + method + ":" + uri + ":" + queryString + ":" + userAgent; + } + + /** + * 生成用于用户验证码的RequestId + * + * @param request + * HttpServletRequest对象 + * @return 用户验证码用的RequestId + */ + public static String generateAgentRequestId(HttpServletRequest request) { + String ip = HttpReqResUtil.getIpAddress(request); + String userAgent = request.getHeader("User-Agent"); + return ip + ":" + userAgent; + } + + public static String generateSha256Id(String input) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] digest = md.digest(input.getBytes()); + return bytesToHex(digest); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException(e); + } + } + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + +} diff --git a/sz-common/sz-common-core/src/test/java/com/sz/core/common/enums/ResponseEnumConcurrentTest.java b/sz-common/sz-common-core/src/test/java/com/sz/core/common/enums/ResponseEnumConcurrentTest.java new file mode 100644 index 0000000..997a61d --- /dev/null +++ b/sz-common/sz-common-core/src/test/java/com/sz/core/common/enums/ResponseEnumConcurrentTest.java @@ -0,0 +1,41 @@ +package com.sz.core.common.enums; + +import com.sz.core.common.exception.common.BusinessExceptionCustomAssert; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CountDownLatch; + +public class ResponseEnumConcurrentTest { + + /** + * CommonResponseEnum.EXISTS.message() 并发问题测试 + */ + + @Test + public void testConcurrentMessage() throws InterruptedException { + int threadCount = 10; + CountDownLatch latch = new CountDownLatch(threadCount); + String[] results = new String[threadCount]; + + for (int i = 0; i < threadCount; i++) { + final int idx = i; + new Thread(() -> { + // 每个线程自定义不同的消息 + String customMsg = "msg-" + idx; + System.out.println("Thread " + idx + " custom message: " + customMsg); + BusinessExceptionCustomAssert custom = CommonResponseEnum.EXISTS.message(customMsg); + results[idx] = custom.getMessage(); + latch.countDown(); + }).start(); + } + + latch.await(); + + // 检查每个线程拿到的消息是否正确 + for (int i = 0; i < threadCount; i++) { + System.out.println("Thread " + i + " message: " + results[i]); + Assertions.assertEquals("msg-" + i, results[i]); + } + } +} diff --git a/sz-common/sz-common-core/src/test/java/com/sz/core/util/StringUtilsTest.java b/sz-common/sz-common-core/src/test/java/com/sz/core/util/StringUtilsTest.java new file mode 100644 index 0000000..ed4e73a --- /dev/null +++ b/sz-common/sz-common-core/src/test/java/com/sz/core/util/StringUtilsTest.java @@ -0,0 +1,31 @@ +package com.sz.core.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * StringUtilsTest + * + * @author sz + * @since 2024/6/20 15:28 + * @version 1.0 + */ +class StringUtilsTest { + + @Test + void toSnakeCase() { + String str = StringUtils.toSnakeCase("TeacherStatics"); + assertEquals("teacher_statics", str); + } + + @Test + void toCamelCase() { + assertEquals("teacherStatics", StringUtils.toCamelCase("teacher_statics")); + assertEquals("teacherstatics", StringUtils.toCamelCase("teacherstatics")); + assertEquals("teacherStatics", StringUtils.toCamelCase("teacher__Statics")); + assertEquals("teacherStatics", StringUtils.toCamelCase("teacher_Statics")); + assertEquals("teacherStatics", StringUtils.toCamelCase("TEACHER_STATICS")); + } + +} \ No newline at end of file diff --git a/sz-common/sz-common-db-mongodb/pom.xml b/sz-common/sz-common-db-mongodb/pom.xml new file mode 100644 index 0000000..c7bf613 --- /dev/null +++ b/sz-common/sz-common-db-mongodb/pom.xml @@ -0,0 +1,14 @@ + + + + sz-common + com.sz + ${revision} + + 4.0.0 + + sz-common-db-mongodb + + \ No newline at end of file diff --git a/sz-common/sz-common-db-mysql/pom.xml b/sz-common/sz-common-db-mysql/pom.xml new file mode 100644 index 0000000..fa1d125 --- /dev/null +++ b/sz-common/sz-common-db-mysql/pom.xml @@ -0,0 +1,66 @@ + + + + sz-common + com.sz + ${revision} + + 4.0.0 + + sz-common-db-mysql + + + + com.sz + sz-common-log + ${revision} + provided + true + + + com.mysql + mysql-connector-j + + + com.zaxxer + HikariCP + + + com.github.pagehelper + pagehelper + + + com.mybatis-flex + mybatis-flex-spring-boot3-starter + + + com.mybatis-flex + mybatis-flex-processor + + + cn.dev33 + sa-token-spring-boot3-starter + provided + true + + + + com.sz + sz-common-core + ${revision} + provided + true + + + com.sz + sz-common-security + ${revision} + provided + true + + + + + \ No newline at end of file diff --git a/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/DataScopeProperties.java b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/DataScopeProperties.java new file mode 100644 index 0000000..dad4bda --- /dev/null +++ b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/DataScopeProperties.java @@ -0,0 +1,22 @@ +package com.sz.mysql; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@Configuration +@ConfigurationProperties(prefix = "sz.data-scope") +public class DataScopeProperties { + + @Schema(description = "数据权限开关") + private boolean enabled = true; + + @Schema(description = "最小查询单位") + private String logicMinUnit = "user"; + + @Schema(description = "是否允许查看管理员创建的数据") + private boolean allowAdminView = false; + +} diff --git a/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/EntityChangeListener.java b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/EntityChangeListener.java new file mode 100644 index 0000000..dfa4616 --- /dev/null +++ b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/EntityChangeListener.java @@ -0,0 +1,103 @@ +package com.sz.mysql; + +import cn.dev33.satoken.exception.NotWebContextException; +import cn.dev33.satoken.stp.StpUtil; +import com.mybatisflex.annotation.InsertListener; +import com.mybatisflex.annotation.SetListener; +import com.mybatisflex.annotation.UpdateListener; +import com.sz.core.common.entity.LoginUser; +import com.sz.security.core.util.LoginUtils; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 数据表变更事件处理器。 + *

+ * 约定:数据表必须包含以下字段: + *

    + *
  • `create_id` - int 类型,创建者 ID
  • + *
  • `create_time` - datetime 类型,创建时间
  • + *
  • `update_id` - int 类型,更新者 ID
  • + *
  • `update_time` - datetime 类型,更新时间
  • + *
+ * + * @since 2023-12-08 + * @version 1.0 + */ +@Slf4j +public class EntityChangeListener implements InsertListener, UpdateListener, SetListener { + + @Override + public void onInsert(Object o) { + setPropertyIfPresent(o, "createTime", LocalDateTime.now()); + setPropertyIfPresent(o, "updateTime", LocalDateTime.now()); + if (isNotLogin()) { + return; + } + setPropertyIfPresent(o, "createId", StpUtil.getLoginIdAsLong()); + setPropertyIfPresent(o, "updateId", StpUtil.getLoginIdAsLong()); + LoginUser loginUser = LoginUtils.getLoginUser(); + List deptOptions = loginUser.getDepts(); + if (deptOptions.isEmpty()) + return; + setPropertyIfPresent(o, "deptScope", deptOptions); + } + + @Override + public void onUpdate(Object o) { + setPropertyIfPresent(o, "updateTime", LocalDateTime.now()); + if (isNotLogin()) + return; + setPropertyIfPresent(o, "updateId", StpUtil.getLoginIdAsLong()); + } + + @Override + public Object onSet(Object entity, String property, Object value) { + return value; + } + + private void setPropertyIfPresent(Object object, String propertyName, Object propertyValue) { + try { + Class clazz = object.getClass(); + String setterName = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); + Method setterMethod = null; + + // 遍历所有方法,寻找匹配的 setter + for (Method method : clazz.getDeclaredMethods()) { + if (method.getName().equals(setterName) && method.getParameterCount() == 1) { + Class parameterType = method.getParameterTypes()[0]; + if (parameterType.isAssignableFrom(propertyValue.getClass())) { + setterMethod = method; + break; + } + } + } + + if (setterMethod != null) { + setterMethod.invoke(object, propertyValue); + } else { + log.warn("Failed to set property '{}': Setter method not found or type mismatch.", propertyName); + } + } catch (IllegalAccessException | InvocationTargetException e) { + log.warn(" Fill EntityChangeField failed; Error accessing property {}: {}", propertyName, e.getMessage()); + } + } + + private boolean isNotLogin() { + try { + return !StpUtil.isLogin(); + } catch (NotWebContextException e) { + // 处理非 Web 环境异常,返回未登录 + return true; + } catch (Exception e) { + // 记录所有其他异常,并返回未登录 + log.error("[EntityChangeListener] Unexpected error during login check: {}", e.getMessage(), e); + return true; + } + } + +} diff --git a/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/EntityLogicDeleteListener.java b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/EntityLogicDeleteListener.java new file mode 100644 index 0000000..eab6a3b --- /dev/null +++ b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/EntityLogicDeleteListener.java @@ -0,0 +1,63 @@ +package com.sz.mysql; + +import cn.dev33.satoken.exception.NotWebContextException; +import cn.dev33.satoken.stp.StpUtil; +import com.mybatisflex.core.dialect.IDialect; +import com.mybatisflex.core.logicdelete.impl.DefaultLogicDeleteProcessor; +import com.mybatisflex.core.table.TableInfo; +import com.sz.security.core.util.LoginUtils; +import lombok.extern.slf4j.Slf4j; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import static com.mybatisflex.core.constant.SqlConsts.EQUALS; + +/** + * 逻辑删除处理: 填充删除人、 删除时间 + */ +@Slf4j +public class EntityLogicDeleteListener extends DefaultLogicDeleteProcessor { + + private static final String FIELD_DELETE_TIME = "delete_time"; + + private static final String FIELD_DELETE_ID = "delete_id"; + + @Override + public String buildLogicDeletedSet(String logicColumn, TableInfo tableInfo, IDialect iDialect) { + StringBuilder sqlBuilder = new StringBuilder(); + sqlBuilder.append(iDialect.wrap(logicColumn)).append(EQUALS).append(prepareValue(getLogicDeletedValue())); + + List columns = Arrays.asList(tableInfo.getAllColumns()); + + if (columns.contains(FIELD_DELETE_TIME)) { + sqlBuilder.append(", ").append(iDialect.wrap(FIELD_DELETE_TIME)).append(EQUALS).append("now()"); + } + + if (isLogin() && columns.contains(FIELD_DELETE_ID)) { + sqlBuilder.append(", ").append(iDialect.wrap(FIELD_DELETE_ID)).append(EQUALS) + .append(Objects.requireNonNull(LoginUtils.getLoginUser()).getUserInfo().getId()); + } + + return sqlBuilder.toString(); + } + + private static Object prepareValue(Object value) { + return (!(value instanceof Number) && !(value instanceof Boolean)) ? "'" + value + "'" : value; + } + + private boolean isLogin() { + try { + return StpUtil.isLogin(); + } catch (NotWebContextException e) { + // 处理非 Web 环境异常,返回未登录 + return false; + } catch (Exception e) { + // 记录所有其他异常,并返回未登录 + log.error("[EntityLogicDeleteListener] Unexpected error during login check: {}", e.getMessage(), e); + return false; + } + } + +} diff --git a/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/MybatisFlexConfiguration.java b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/MybatisFlexConfiguration.java new file mode 100644 index 0000000..fde67dc --- /dev/null +++ b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/MybatisFlexConfiguration.java @@ -0,0 +1,48 @@ +package com.sz.mysql; + +import com.github.pagehelper.PageInterceptor; +import com.mybatisflex.core.FlexGlobalConfig; +import com.mybatisflex.core.dialect.DbType; +import com.mybatisflex.core.dialect.DialectFactory; +import com.mybatisflex.core.logicdelete.LogicDeleteProcessor; +import com.mybatisflex.core.query.QueryColumnBehavior; +import com.mybatisflex.spring.boot.MyBatisFlexCustomizer; +import com.sz.logger.PrintSQL; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author sz + * @since 2024/5/11 14:58 + */ +@Configuration +public class MybatisFlexConfiguration implements MyBatisFlexCustomizer { + + @Resource + private DataScopeProperties dataScopeProperties; + + public MybatisFlexConfiguration() { + QueryColumnBehavior.setIgnoreFunction(QueryColumnBehavior.IGNORE_NONE);// 关闭全局null参数忽略设置 + PrintSQL.print(); + } + + @Bean + public PageInterceptor pageInterceptor() { + return new PageInterceptor(); + } + + @Bean + public LogicDeleteProcessor logicDeleteProcessor() { + return new EntityLogicDeleteListener(); + } + + @Override + public void customize(FlexGlobalConfig flexGlobalConfig) { + if (dataScopeProperties.isEnabled()) { + // 注册查询权限监听方言 + DialectFactory.registerDialect(DbType.MYSQL, new SimplePermissionDialect()); + } + } + +} diff --git a/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/SimplePermissionDialect.java b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/SimplePermissionDialect.java new file mode 100644 index 0000000..ee9ceeb --- /dev/null +++ b/sz-common/sz-common-db-mysql/src/main/java/com/sz/mysql/SimplePermissionDialect.java @@ -0,0 +1,320 @@ +package com.sz.mysql; + +import cn.dev33.satoken.stp.StpUtil; +import com.mybatisflex.annotation.Table; +import com.mybatisflex.core.dialect.OperateType; +import com.mybatisflex.core.dialect.impl.CommonsDialectImpl; +import com.mybatisflex.core.query.*; +import com.sz.core.common.entity.ControlPermissions; +import com.sz.core.common.entity.LoginUser; +import com.sz.core.common.entity.RoleMenuScopeVO; +import com.sz.core.datascope.ControlThreadLocal; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.core.util.StringUtils; +import com.sz.core.util.Utils; +import com.sz.security.core.util.LoginUtils; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 自定义方言 -- 数据权限 + */ +@Slf4j +public class SimplePermissionDialect extends CommonsDialectImpl { + + private static final String FIELD_CREATE_ID = "create_id"; + + private static final String FIELD_DEPT_SCOPE = "dept_scope"; + + private static final String SEPARATOR_STR = "$"; // 分隔符常量 + + @Override + public void prepareAuth(QueryWrapper queryWrapper, OperateType operateType) { + // 需要跳过的情况 + if (isSkipDataScope(operateType)) { + super.prepareAuth(queryWrapper, operateType); + return; + } + // 防止误触 && MybatisFlex Relation 多对多映射问题 + String tableName = getTableName(SimpleDataScopeHelper.get()); + if (!isTargetTable(queryWrapper, tableName)) { + super.prepareAuth(queryWrapper, operateType); + return; + } + + try { + if (!initializeContext(queryWrapper, operateType)) { + return; + } + + ControlPermissions permissions = ControlThreadLocal.get(); + LoginUser loginUser = LoginUtils.getLoginUser(); + if (permissions == null || loginUser == null) { + log.error("PermissionDialect prepareAuth error: permissions or loginUser is null."); + return; + } + String[] btnPermissions = permissions.getPermissions(); + Map permissionMap = loginUser.getPermissionAndMenuIds(); + Map scopeMap = loginUser.getDataScope(); + String firstPermission = (btnPermissions != null && btnPermissions.length > 0) ? btnPermissions[0] : ""; + String menuId = permissionMap.get(firstPermission); // 根据 权限标识获取菜单ID + RoleMenuScopeVO scope = menuId == null ? null : scopeMap.get(menuId); + // !如果没有配置数据权限,默认只看自己的数据 + if (scope == null || permissionMap.isEmpty()) { + Set userIds = new HashSet<>(); + Set deptIds = new HashSet<>(); + // 添加当前操作用户 + userIds.add(loginUser.getUserInfo().getId()); + buildSql(queryWrapper, tableName, deptIds, userIds, SimpleDataScopeHelper.get()); + return; + } + + String dataScopeCd = scope.getDataScopeCd(); + switch (dataScopeCd) { + case "1006005" -> { // 自定义 + RoleMenuScopeVO.CustomScope customScope = scope.getCustomScope(); + Set deptIds = new HashSet<>(); + Set userIds = new HashSet<>(); + if (customScope != null) { + if (Utils.isNotNull(customScope.getDeptIds())) { + deptIds.addAll(customScope.getDeptIds()); + } + if (Utils.isNotNull(customScope.getUserIds())) { + userIds.addAll(customScope.getUserIds()); + } + } + // 添加当前操作用户 + userIds.add(loginUser.getUserInfo().getId()); + buildSql(queryWrapper, tableName, deptIds, userIds, SimpleDataScopeHelper.get()); + } + case "1006001", "1006002", "1006003", "1006004" -> { + applyDataScopeRules(queryWrapper, operateType, dataScopeCd, tableName, SimpleDataScopeHelper.get()); + } + } + + } catch (Exception e) { + log.error("PermissionDialect Exception: {}", e.getMessage()); + } finally { + super.prepareAuth(queryWrapper, operateType); + } + } + + /** + * 检查是否跳过数据权限控制 + */ + private boolean isSkipDataScope(OperateType operateType) { + return !SimpleDataScopeHelper.isDataScope() || !StpUtil.isLogin() || operateType != OperateType.SELECT; + } + + /** + * 验证当前查询是否是目标表 + * + * @param queryWrapper + * wrapper + * @param table + * 表名称 + * @return boolean + */ + private boolean isTargetTable(QueryWrapper queryWrapper, String table) { + List queryTables = CPI.getQueryTables(queryWrapper); + if (queryTables == null || queryTables.isEmpty()) { + return false; + } + for (QueryTable queryTable : queryTables) { + if (table.equals(queryTable.getName())) { + return true; + } + if (queryTable instanceof SelectQueryTable selectQueryTable) { + if (isTargetTable(selectQueryTable.getQueryWrapper(), table)) { + return true; + } + } + } + return false; + } + + /** + * 初始化上下文 + * + * @param queryWrapper + * wrapper + * @param operateType + * 操作类型 + * @return 是否初始化成功 + */ + private boolean initializeContext(QueryWrapper queryWrapper, OperateType operateType) { + List queryTables = CPI.getQueryTables(queryWrapper); + List joinTables = CPI.getJoinTables(queryWrapper); + if (queryTables == null || queryTables.isEmpty()) { + return false; + } + LoginUser loginUser = LoginUtils.getLoginUser(); + if (loginUser == null || !ControlThreadLocal.hasLocal() || LoginUtils.isSuperAdmin()) { + super.prepareAuth(queryWrapper, operateType); + return false; + } + for (QueryTable queryTable : queryTables) { + if (queryTable instanceof SelectQueryTable) { + prepareAuth(((SelectQueryTable) queryTable).getQueryWrapper(), operateType); + } + } + + boolean isJoin = CPI.getJoins(queryWrapper) != null && !CPI.getJoins(queryWrapper).isEmpty(); + Map tableMap = buildTableMap(queryTables, isJoin, joinTables); + + return !tableMap.isEmpty(); + } + + private static Map buildTableMap(List queryTables, boolean isJoin, List joinTables) { + Map tableMap = new HashMap<>(); + for (QueryTable queryTable : queryTables) { + if (queryTable.getName() == null || queryTable.getName().trim().isEmpty()) { + return Collections.emptyMap(); + } + tableMap.put(queryTable.getName(), queryTable); + } + if (isJoin) { + for (QueryTable joinTable : joinTables) { + if (joinTable.getName() != null && !joinTable.getName().trim().isEmpty()) { + tableMap.put(joinTable.getName(), joinTable); + } + } + } + return tableMap; + } + + private String getTableName(Class clazz) { + Table anno = clazz.getAnnotation(Table.class); + return (anno == null) ? StringUtils.toSnakeCase(clazz.getSimpleName()) : anno.value(); + } + + /** + * 应用数据权限规则 + * + * @param queryWrapper + * wrapper + * @param operateType + * 类型 + * @param rule + * 规则 + * @param table + * table表 + * @param tableClazz + * class + */ + private void applyDataScopeRules(QueryWrapper queryWrapper, OperateType operateType, String rule, String table, Class tableClazz) { + LoginUser loginUser = LoginUtils.getLoginUser(); + assert loginUser != null; + // 如果有全部数据的查询权限,直接返回 + if ("1006001".equals(rule)) { + super.prepareAuth(queryWrapper, operateType); + return; + } + // 初始化部门和用户集合 + Set deptList = new HashSet<>(); + Set userList = new HashSet<>(); + // 根据规则添加部门 + switch (rule) { + case "1006002" -> deptList.addAll(loginUser.getDeptAndChildren()); // 本部门及以下 + case "1006003" -> deptList.addAll(loginUser.getDepts()); // 仅本部门 + } + // 添加当前操作用户 + userList.add(loginUser.getUserInfo().getId()); + buildSql(queryWrapper, table, deptList, userList, tableClazz); + } + + private boolean isFieldExists(Class clazz, String fieldName) { + try { + clazz.getDeclaredField(fieldName); + return true; + } catch (NoSuchFieldException e) { + log.error(" [DataScope]: Entity `{}` Filed `{}` not found.", clazz.getSimpleName(), fieldName); + } + return false; + } + + /** + * 根据条件拼装sql + * + * @param queryWrapper + * wrapper + * @param table + * 表名 + * @param deptList + * 部门集合 + * @param userList + * 用户集合 + * @param tableClazz + * class + */ + private void buildSql(QueryWrapper queryWrapper, String table, Collection deptList, Collection userList, Class tableClazz) { + DataScopeProperties properties = SpringApplicationContextUtils.getInstance().getBean(DataScopeProperties.class); + String unit = properties.getLogicMinUnit(); + boolean allowAdminView = properties.isAllowAdminView(); + + String field = "user".equals(unit) ? FIELD_CREATE_ID : FIELD_DEPT_SCOPE; + if (!isFieldExists(tableClazz, StringUtils.toCamelCase(field))) { + return; + } + + StringBuilder sb = new StringBuilder(); + boolean isFirstAppend = true; + + // 构建用户或部门为单元的SQL + if ("user".equals(unit) && !deptList.isEmpty()) { // 以用户为最小单元 + String sqlParams = appendCollection(deptList); + sb.append(" EXISTS ( SELECT 1 FROM `sys_user_dept` ").append("JOIN `sys_dept` ON `sys_user_dept`.`dept_id` = `sys_dept`.`id` ") + .append("WHERE `sys_user_dept`.`dept_id` IN ").append(sqlParams).append(" AND `sys_dept`.`del_flag` = 'F' ").append("AND `").append(table) + .append("`.`").append(field).append("` = `sys_user_dept`.`user_id`) "); + isFirstAppend = false; + } else { // 以部门为最小单元 + if (!deptList.isEmpty()) { + for (Long dept : deptList) { + if (!isFirstAppend) { + sb.append(" OR "); + } + sb.append(" JSON_CONTAINS(").append("`").append(table).append("`").append(".").append("`").append(field).append("`").append(", '") + .append(dept).append("', '").append(SEPARATOR_STR).append("')"); + isFirstAppend = false; + } + } + } + + // 允许其他用户查看超管产生的数据 + if (allowAdminView) { + if (!isFirstAppend) { + sb.append(" OR "); + } + sb.append(" EXISTS (SELECT 1 FROM `sys_user` WHERE `sys_user`.`id` = `").append(table).append("`.`").append(FIELD_CREATE_ID) + .append("` AND `sys_user`.`user_tag_cd` = '1001002' AND `del_flag` = 'F')"); + isFirstAppend = false; + + } + + // 自定义用户条件 + if (!userList.isEmpty()) { + if (!isFirstAppend) + sb.append(" OR "); + if (userList.size() == 1) { + sb.append(" `").append(table).append("`.`").append(FIELD_CREATE_ID).append("` = ").append(userList.iterator().next()); + } else { + sb.append(" `").append(table).append("`.`").append(FIELD_CREATE_ID).append("` IN ").append(appendCollection(userList)); + } + } + + // 避免重复拼装 + String fieldFlag = "customScopeContext"; + Object context = CPI.getContext(queryWrapper, fieldFlag); + if (context == null || Boolean.FALSE.equals(context)) { + queryWrapper.where("(" + sb + ")"); + CPI.putContext(queryWrapper, fieldFlag, true); + } + } + + private String appendCollection(Collection collection) { + return collection.stream().map(String::valueOf).collect(Collectors.joining(", ", "(", ")")); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-db-redis/pom.xml b/sz-common/sz-common-db-redis/pom.xml new file mode 100644 index 0000000..96b2f30 --- /dev/null +++ b/sz-common/sz-common-db-redis/pom.xml @@ -0,0 +1,37 @@ + + + + sz-common + com.sz + ${revision} + + 4.0.0 + + sz-common-db-redis + + + + org.springframework.boot + spring-boot-starter-data-redis + + + com.fasterxml.jackson.core + jackson-annotations + + + com.sz + sz-common-core + ${revision} + provided + true + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + \ No newline at end of file diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/CommonKeyConstants.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/CommonKeyConstants.java new file mode 100644 index 0000000..59cfa16 --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/CommonKeyConstants.java @@ -0,0 +1,60 @@ +package com.sz.redis; + +/** + * 公用 Redis Key 常量类 + *

+ * 该类包含了用于 Redis 操作的常量 Redis Key,方便在整个项目中统一使用和管理。 + * + * @author sz + * @since 2023/12/12 9:37 + * @since 2023-12-12 + */ +public class CommonKeyConstants { + + private CommonKeyConstants() { + throw new IllegalStateException("Utility class"); + } + + /** + * 字典信息 + */ + public static final String SYS_DICT = "sys_dict"; + + /** + * 系统参数信息 + */ + public static final String SYS_CONFIG = "sys_config"; + + /** + * 前端配置信息 + */ + public static final String FRONTEND_CONFIG = "frontend_config"; + + /** + * sa-token token信息 + */ + public static final String TOKEN_SESSION = "Authorization:login:token-session:${token}"; + + /** + * 系统用户登录密码失败次数 + */ + public static final String SYS_PWD_ERR_CNT = "err:pwd-cnt:${username}"; + + /** + * 验证码 + */ + public static final String CAPTCHA_REQUEST_ID = "captcha:slide:${requestId}"; + + /** + * 验证码请求次数限制 + */ + public static final String CAPTCHA_REQUEST_LIMIT = "captcha:request-limit:${requestId}"; + + public static final String LOGIN_REQUEST_ID = "login:request:${requestId}"; + + /** + * 登录请求次数限制 + */ + public static final String LOGIN_REQUEST_LIMIT = "login:request-limit:${requestId}"; + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisCache.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisCache.java new file mode 100644 index 0000000..9ac006a --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisCache.java @@ -0,0 +1,251 @@ +package com.sz.redis; + +import com.sz.core.common.entity.DictVO; +import com.sz.core.common.entity.PointVO; +import com.sz.core.util.StringUtils; +import com.sz.core.util.Utils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * @author sz + * @since 2024/1/8 15:38 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class RedisCache { + + private final RedisTemplate redisTemplate; + + // ---------------sys_dict相关---------------- + public void setDict(String dictType, List list) { + redisTemplate.opsForHash().put(CommonKeyConstants.SYS_DICT, dictType, list); + redisTemplate.expire(CommonKeyConstants.SYS_DICT, 2, TimeUnit.HOURS); + } + + public void putAllDict(Map> dictMap) { + redisTemplate.opsForHash().putAll(CommonKeyConstants.SYS_DICT, dictMap); + redisTemplate.expire(CommonKeyConstants.SYS_DICT, 2, TimeUnit.HOURS); + } + + public Map> getAllDict() { + return redisTemplate.>opsForHash().entries(CommonKeyConstants.SYS_DICT); + } + + public List getDictByType(String dictType) { + if (hasHashKey(dictType)) { + List result = redisTemplate.>opsForHash().get(CommonKeyConstants.SYS_DICT, dictType); + return result != null ? result : new ArrayList<>(); + } else { + return new ArrayList<>(); + } + } + + public boolean hasKey() { + // 检查 redisTemplate 是否为 null + if (redisTemplate == null) { + log.error("RedisTemplate is null, cannot check key existence"); + return false; + } + + // 调用 hasKey 方法并检查返回值是否为 null + Boolean hasKey = redisTemplate.hasKey(CommonKeyConstants.SYS_DICT); + return Boolean.TRUE.equals(hasKey); + } + + public boolean hasHashKey(String dictType) { + return redisTemplate.opsForHash().hasKey(CommonKeyConstants.SYS_DICT, dictType); + } + + public void clearDict(String dictType) { + redisTemplate.opsForHash().delete(CommonKeyConstants.SYS_DICT, dictType); + } + + public void clearDictAll() { + redisTemplate.delete(CommonKeyConstants.SYS_DICT); + } + + // ---------------sys_config相关---------------- + public boolean hasConfKey(String key) { + return redisTemplate.opsForHash().hasKey(CommonKeyConstants.SYS_CONFIG, key); + } + + public String getConfValue(String key) { + return (String) redisTemplate.opsForHash().get(CommonKeyConstants.SYS_CONFIG, key); + } + + public void putConf(String key, String value) { + redisTemplate.opsForHash().put(CommonKeyConstants.SYS_CONFIG, key, value); + redisTemplate.expire(CommonKeyConstants.SYS_CONFIG, 2, TimeUnit.HOURS); + } + + public void clearConf(String key) { + redisTemplate.opsForHash().delete(CommonKeyConstants.SYS_CONFIG, key); + } + + // ---------------sys_user用户认证相关---------------- + + public Long countPwdErr(String username, long timeout) { + String key = RedisUtils.getKey(CommonKeyConstants.SYS_PWD_ERR_CNT, username); + Long increment = redisTemplate.opsForValue().increment(key, 1); + redisTemplate.expire(key, timeout, TimeUnit.MINUTES); + return increment; + } + + public String getUserInfoKey(String username) { + return StringUtils.replacePlaceholders(CommonKeyConstants.TOKEN_SESSION, username); + } + + public void clearUserInfo(String username) { + redisTemplate.delete(getUserInfoKey(username)); + } + + public void putCaptcha(String requestId, PointVO vo, long timeout) { + String key = StringUtils.getRealKey(CommonKeyConstants.CAPTCHA_REQUEST_ID, requestId); + redisTemplate.opsForValue().set(key, vo); + redisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + + public PointVO getCaptcha(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.CAPTCHA_REQUEST_ID, requestId); + if (existCaptcha(requestId)) { + return (PointVO) redisTemplate.opsForValue().get(key); + } else { + return null; + } + } + + public void clearCaptcha(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.CAPTCHA_REQUEST_ID, requestId); + redisTemplate.opsForValue().getOperations().delete(key); + } + + public boolean existCaptcha(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.CAPTCHA_REQUEST_ID, requestId); + + // 检查 redisTemplate 是否为 null + if (redisTemplate == null) { + log.error("RedisTemplate is null, cannot check key existence"); + return false; + } + + Boolean hasKey = redisTemplate.hasKey(key); + // 检查 hasKey 是否为 null + return Boolean.TRUE.equals(hasKey); + } + + /** + * 初始化验证码请求限制 + * + * @param requestId + * 请求ID + * @param timeout + * 过期时间(分钟) + */ + public void initializeCaptchaRequestLimit(String requestId, long timeout) { + String key = StringUtils.getRealKey(CommonKeyConstants.CAPTCHA_REQUEST_LIMIT, requestId); + redisTemplate.opsForValue().setIfAbsent(key, 0, timeout, TimeUnit.MINUTES); + } + + public Long countCaptchaRequestLimit(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.CAPTCHA_REQUEST_LIMIT, requestId); + Object o = redisTemplate.opsForValue().get(key); + return Utils.getLongVal(o); + } + + public Long limitCaptcha(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.CAPTCHA_REQUEST_LIMIT, requestId); + return redisTemplate.opsForValue().increment(key); + } + + /** + * 初始化登录次数请求限制 + */ + public void initializeLoginRequestLimit(String requestId, long timeout) { + String key = StringUtils.getRealKey(CommonKeyConstants.LOGIN_REQUEST_LIMIT, requestId); + redisTemplate.opsForValue().setIfAbsent(key, 0, timeout, TimeUnit.MINUTES); + } + + public Long countLoginRequestLimit(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.LOGIN_REQUEST_LIMIT, requestId); + Object o = redisTemplate.opsForValue().get(key); + return Utils.getLongVal(o); + } + + public Long limitLoginRequest(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.LOGIN_REQUEST_LIMIT, requestId); + return redisTemplate.opsForValue().increment(key); + } + + public void clearLoginSecret(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.LOGIN_REQUEST_ID, requestId); + redisTemplate.opsForValue().getOperations().delete(key); + } + + public void putLoginSecret(String requestId, String secretKey, long timeout) { + String key = StringUtils.getRealKey(CommonKeyConstants.LOGIN_REQUEST_ID, requestId); + redisTemplate.opsForValue().set(key, secretKey); + redisTemplate.expire(key, timeout, TimeUnit.SECONDS); + } + + public String getLoginSecret(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.LOGIN_REQUEST_ID, requestId); + + if (LoginSecret(requestId)) { + return (String) redisTemplate.opsForValue().get(key); + } else { + return null; + } + } + + public boolean LoginSecret(String requestId) { + String key = StringUtils.getRealKey(CommonKeyConstants.LOGIN_REQUEST_ID, requestId); + + // 检查 redisTemplate 是否为 null + if (redisTemplate == null) { + log.error("RedisTemplate is null, cannot check key existence"); + return false; + } + + Boolean hasKey = redisTemplate.hasKey(key); + // 检查 hasKey 是否为 null + return Boolean.TRUE.equals(hasKey); + } + + // ---------------FRONTEND_CONFIG相关---------------- + + public Map getFrontendConfig() { + return redisTemplate.opsForHash().entries(CommonKeyConstants.FRONTEND_CONFIG); + } + + public boolean hasFrontendKey() { + if (redisTemplate == null) { + return false; + } + return redisTemplate.hasKey(CommonKeyConstants.FRONTEND_CONFIG); + } + + public void putFrontendConfig(String key, String value) { + redisTemplate.opsForHash().put(CommonKeyConstants.FRONTEND_CONFIG, key, value); + redisTemplate.expire(CommonKeyConstants.FRONTEND_CONFIG, 2, TimeUnit.HOURS); + + } + + public void putAllFrontendConfig(Map configMap) { + redisTemplate.opsForHash().putAll(CommonKeyConstants.FRONTEND_CONFIG, configMap); + redisTemplate.expire(CommonKeyConstants.FRONTEND_CONFIG, 2, TimeUnit.HOURS); + } + + public void deleteFrontendConfig(String key) { + redisTemplate.opsForHash().delete(CommonKeyConstants.FRONTEND_CONFIG, key); + } + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisConfiguration.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisConfiguration.java new file mode 100644 index 0000000..4e9768c --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisConfiguration.java @@ -0,0 +1,56 @@ +package com.sz.redis; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * @author sz + * @since 2022/6/4 11:01 + */ +@Configuration +public class RedisConfiguration { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(redisConnectionFactory); + // 使用Jackson2JsonRedisSerialize 替换默认序列化 + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = initJacksonSerializer(); + // 设置value的序列化规则和 key的序列化规则 + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(jackson2JsonRedisSerializer); + // 设置hash的序列化规则 + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(jackson2JsonRedisSerializer); + + template.afterPropertiesSet(); + return template; + } + + /** + * 处理redis序列化问题 + * + * @return Jackson2JsonRedisSerializer + */ + private Jackson2JsonRedisSerializer initJacksonSerializer() { + + ObjectMapper om = new ObjectMapper(); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL); + // bugFix Jackson2反序列化数据处理LocalDateTime类型时出错 + om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS); + // java8 时间支持 + om.registerModule(new JavaTimeModule()); + return new Jackson2JsonRedisSerializer<>(om, Object.class); + } + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisMessageConfiguration.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisMessageConfiguration.java new file mode 100644 index 0000000..b994848 --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisMessageConfiguration.java @@ -0,0 +1,51 @@ +package com.sz.redis; + +import com.sz.core.common.constant.GlobalConstant; +import com.sz.redis.listener.ServiceToWsListener; +import com.sz.redis.listener.UserPermissionChangeListener; +import com.sz.redis.listener.WsToServiceListener; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.listener.PatternTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.stereotype.Component; + +/** + * 消息订阅配置 + * + * @author sz + * @since 2023/9/8 15:13 + */ +@Component +@RequiredArgsConstructor +@ConditionalOnProperty(name = "redis.listener.enable", havingValue = "true") +public class RedisMessageConfiguration { + + private final RedisConnectionFactory redisConnectionFactory; + + private final WsToServiceListener wsToServiceListener; + + private final ServiceToWsListener serviceToWsListener; + + private final UserPermissionChangeListener userPermissionChangeListener; + + /** + * 配置订阅关系 + */ + @Bean + public RedisMessageListenerContainer container() { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(redisConnectionFactory); + // 订阅的channel + PatternTopic patternTopic1 = new PatternTopic(GlobalConstant.WS_TO_SERVICE); + container.addMessageListener(wsToServiceListener, patternTopic1); + PatternTopic patternTopic2 = new PatternTopic(GlobalConstant.SERVICE_TO_WS); + container.addMessageListener(serviceToWsListener, patternTopic2); + PatternTopic patternTopic3 = new PatternTopic(GlobalConstant.CHANGE_PERMISSIONS_SIGNAL); + container.addMessageListener(userPermissionChangeListener, patternTopic3); + return container; + } + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisTemplateClient.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisTemplateClient.java new file mode 100644 index 0000000..1556bab --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisTemplateClient.java @@ -0,0 +1,12 @@ +package com.sz.redis; + +import org.springframework.data.redis.core.RedisTemplate; + +/** + * @author sz + * @since 2024/2/29 9:47 + */ +public interface RedisTemplateClient { + + RedisTemplate getTemplate(); +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisUtils.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisUtils.java new file mode 100644 index 0000000..933cb88 --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/RedisUtils.java @@ -0,0 +1,75 @@ +package com.sz.redis; + +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.core.util.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.concurrent.TimeUnit; + +/** + * @author sz + * @since 2024/2/29 9:28 + */ +@Slf4j +public class RedisUtils { + + private RedisUtils() { + throw new IllegalStateException("Utility class"); + } + + private static final RedisTemplate TEMPLATE = SpringApplicationContextUtils.getInstance().getBean(RedisTemplateClient.class).getTemplate(); + + public static String getKey(String constant, String... value) { + return StringUtils.getRealKey(constant, value); + } + + // 检查完整键是否存在 + public static boolean hasKey(String constant, String... value) { + // 获取完整的键 + String key = getKey(constant, value); + return hasKey(key); + } + + // 检查键是否存在 + public static boolean hasKey(String key) { + // 检查 redisTemplate 是否为 null + if (TEMPLATE == null) { + log.error("RedisTemplate is null, cannot check key existence"); + return false; + } + + // 调用 hasKey 方法并检查返回值是否为 null + Boolean hasKey = TEMPLATE.hasKey(key); + return Boolean.TRUE.equals(hasKey); + } + + public static void removeKey(String key) { + TEMPLATE.delete(key); + } + + public static void removeKey(String constant, String... value) { + TEMPLATE.delete(getKey(constant, value)); + } + + public static void expire(String constant, long timeout, TimeUnit unit, String... value) { + TEMPLATE.expire(getKey(constant, value), timeout, unit); + } + + public static void expire(String key, long timeout, TimeUnit unit) { + TEMPLATE.expire(key, timeout, unit); + } + + public static Object getValue(String constant, String... value) { + return TEMPLATE.opsForValue().get(getKey(constant, value)); + } + + public static Object getValue(String key) { + return TEMPLATE.opsForValue().get(key); + } + + public static RedisTemplate getRestTemplate() { + return TEMPLATE; + } + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/WebsocketRedisService.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/WebsocketRedisService.java new file mode 100644 index 0000000..6c162ef --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/WebsocketRedisService.java @@ -0,0 +1,246 @@ +package com.sz.redis; + +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.TransferMessage; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * websocket 用户管理工具 + * + * @author sz + * @since 2023/9/5 14:05 + */ +@Service +@RequiredArgsConstructor +public class WebsocketRedisService { + + public static final String WEBSOCKET_ONLINE_SID = "socket:online:sid"; + + public static final String WEBSOCKET_ONLINE_USER = "socket:online:user"; + + private final RedisTemplate redisTemplate; + + /** + * 用户上线 + * + * @param loginId + * 用户id + */ + public void addUserToOnlineChat(String sessionId, String loginId) { + String onlineUserKey = WEBSOCKET_ONLINE_USER; + + // 检查用户名是否已存在于在线用户哈希表中 + if (redisTemplate.opsForHash().hasKey(onlineUserKey, loginId)) { + // 如果存在,获取sid列表并更新 + List sids = redisTemplate.>opsForHash().get(onlineUserKey, loginId); + assert sids != null; + sids.add(sessionId); + redisTemplate.opsForHash().put(onlineUserKey, loginId, sids); + } else { + // 如果不存在,创建一个包含当前sid的新列表 + List sids = new ArrayList<>(1); + sids.add(sessionId); + redisTemplate.opsForHash().put(onlineUserKey, loginId, sids); + } + + // 更新sid映射 + redisTemplate.opsForHash().put(WEBSOCKET_ONLINE_SID, sessionId, loginId); + } + + /** + * 用户下线 + * + * @param sessionId + * sessionId + * @param loginId + * 用户id + */ + public void removeUser(String sessionId, String loginId) { + String onlineUserKey = WEBSOCKET_ONLINE_USER; + + // 检查用户名是否存在于在线用户哈希表中 + if (redisTemplate.opsForHash().hasKey(onlineUserKey, loginId)) { + // 如果存在,获取sid列表并移除当前sessionId + List sids = redisTemplate.>opsForHash().get(onlineUserKey, loginId); + assert sids != null; + sids.remove(sessionId); + + // 如果用户不再有任何会话,则从在线用户列表中删除 + if (sids.isEmpty()) { + redisTemplate.opsForHash().delete(onlineUserKey, loginId); + } else { + redisTemplate.opsForHash().put(onlineUserKey, loginId, sids); + } + } + + // 删除sessionId映射 + redisTemplate.opsForHash().delete(WEBSOCKET_ONLINE_SID, sessionId); + } + + /** + * 用户下线 - 根据sessionId + * + * @param sessionId + * sessionId + */ + public void removeUserBySessionId(String sessionId) { + // 查找sessionId对应的用户名 + String loginId = (String) redisTemplate.opsForHash().get(WEBSOCKET_ONLINE_SID, sessionId); + if (loginId != null) { + // 从在线用户列表中删除sessionId + if (redisTemplate.opsForHash().hasKey(WEBSOCKET_ONLINE_USER, loginId)) { + List sids = redisTemplate.>opsForHash().get(WEBSOCKET_ONLINE_USER, loginId); + System.out.println("sids ==" + sids); + assert sids != null; + sids.remove(sessionId); + + // 如果用户不再有任何会话,则从在线用户列表中删除该用户 + if (sids.isEmpty()) { + redisTemplate.opsForHash().delete(WEBSOCKET_ONLINE_USER, loginId); + } else { + redisTemplate.opsForHash().put(WEBSOCKET_ONLINE_USER, loginId, sids); + } + } + + // 删除sessionId映射 + redisTemplate.opsForHash().delete(WEBSOCKET_ONLINE_SID, sessionId); + } + } + + /** + * 用户下线 + * + * @param loginId + * 用户id + */ + public void removeUserByUsername(String loginId) { + String onlineUserKey = WEBSOCKET_ONLINE_USER; + + // 检查用户名是否存在于在线用户哈希表中 + if (redisTemplate.opsForHash().hasKey(onlineUserKey, loginId)) { + // 获取该用户的所有连接sessionId + List sids = redisTemplate.>opsForHash().get(onlineUserKey, loginId); + + // 从在线用户列表中删除该用户 + redisTemplate.opsForHash().delete(onlineUserKey, loginId); + + // 删除与该用户相关的所有sessionId映射 + assert sids != null; + for (String sid : sids) { + redisTemplate.opsForHash().delete(WEBSOCKET_ONLINE_SID, sid); + } + } + } + + /** + * 根据sessionId查询loginId + * + * @param sessionId + * sessionId + */ + public String getUserBySessionId(String sessionId) { + // 查找sessionId对应的用户名 + return (String) redisTemplate.opsForHash().get(WEBSOCKET_ONLINE_SID, sessionId); + } + + /** + * 查询在线用户数 + * + * @return 数量 + */ + public long getOnlineUserCount() { + + // 获取在线用户列表的大小,即在线用户数 + + return redisTemplate.opsForHash().size(WEBSOCKET_ONLINE_USER); + } + + /** + * 查询websocket连接数 + * + * @return 数量 + */ + public long getConnectionCount() { + // 获取在线连接数,即sessionId映射的数量 + return redisTemplate.opsForHash().size(WEBSOCKET_ONLINE_SID); + } + + /** + * 查询某个用户的连接数(在几处登陆) + * + * @param loginId + * 用户id + * @return 数量 + */ + public long getUserConnectionCount(String loginId) { + String onlineUserKey = WEBSOCKET_ONLINE_USER; + + // 检查用户名是否存在于在线用户哈希表中 + if (redisTemplate.opsForHash().hasKey(onlineUserKey, loginId)) { + // 如果存在,获取该用户的连接数 + List sids = redisTemplate.>opsForHash().get(onlineUserKey, loginId); + assert sids != null; + return sids.size(); + } else { + // 如果用户不存在或没有连接,返回 0 + return 0; + } + } + + /** + * 获取所有在线用户名列表 + * + * @return 用户名列表 + */ + public List getAllOnlineUsernames() { + Set loginIds = redisTemplate.opsForHash().keys(WEBSOCKET_ONLINE_USER); + return loginIds.stream().map(Object::toString).collect(Collectors.toList()); + } + + /** + * 获取用户的所有连接 sessionId 列表 + * + * @param loginId + * 用户id + * @return 列表 + */ + public List getUserSessionIds(String loginId) { + String onlineUserKey = WEBSOCKET_ONLINE_USER; + + if (redisTemplate.opsForHash().hasKey(onlineUserKey, loginId)) { + List sids = redisTemplate.>opsForHash().get(onlineUserKey, loginId); + assert sids != null; + return new ArrayList<>(sids); + } else { + return new ArrayList<>(); + } + } + + /** + * 透传 websocket 给 service 服务 + * + * @param transferMessage + * 透传消息 + */ + public void sendWsToService(TransferMessage transferMessage) { + redisTemplate.convertAndSend(GlobalConstant.WS_TO_SERVICE, transferMessage); + } + + /** + * 透传 service 给 websocket服务 + * + * @param transferMessage + * 透传消息 + */ + public void sendServiceToWs(TransferMessage transferMessage) { + redisTemplate.convertAndSend(GlobalConstant.SERVICE_TO_WS, transferMessage); + } + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/ServiceToWsMsgHandler.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/ServiceToWsMsgHandler.java new file mode 100644 index 0000000..32387dc --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/ServiceToWsMsgHandler.java @@ -0,0 +1,15 @@ +package com.sz.redis.handler; + +import com.sz.core.common.entity.TransferMessage; +/** + * 服务端到 WebSocket 方向的消息监听接口,允许具体业务实现此接口以进行消息的处理。 + *

+ * 该接口为服务端向 WebSocket 客户端推送消息提供了基础的监听机制,业务可以通过实现该接口, 自定义如何处理接收到的 WebSocket 消息。 + * + * @since 2023-12-08 + */ + +public interface ServiceToWsMsgHandler { + + void handleTransferMessage(TransferMessage transferMessage); +} \ No newline at end of file diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/UserPermissionChangeMsgHandler.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/UserPermissionChangeMsgHandler.java new file mode 100644 index 0000000..204d0b2 --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/UserPermissionChangeMsgHandler.java @@ -0,0 +1,8 @@ +package com.sz.redis.handler; + +import com.sz.core.common.entity.UserPermissionChangeMessage; + +public interface UserPermissionChangeMsgHandler { + + void handlerMsg(UserPermissionChangeMessage message); +} \ No newline at end of file diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/WsToServiceMsgHandler.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/WsToServiceMsgHandler.java new file mode 100644 index 0000000..e51cfbb --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/handler/WsToServiceMsgHandler.java @@ -0,0 +1,16 @@ +package com.sz.redis.handler; + +import com.sz.core.common.entity.TransferMessage; + +/** + * WebSocket 到服务端方向的消息监听接口,允许具体业务实现此接口以进行消息的处理。 + *

+ * 该接口为 WebSocket 客户端向服务端发送消息提供了基础的监听机制,业务可以通过实现该接口, 自定义如何处理接收到的 WebSocket 消息。 + * + * @since 2023-12-08 + */ + +public interface WsToServiceMsgHandler { + + void handlerMsg(TransferMessage transferMessage); +} \ No newline at end of file diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/ServiceToWsListener.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/ServiceToWsListener.java new file mode 100644 index 0000000..5db2ee8 --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/ServiceToWsListener.java @@ -0,0 +1,41 @@ +package com.sz.redis.listener; + +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.util.JsonUtils; +import com.sz.redis.handler.ServiceToWsMsgHandler; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * redis消息listener, 用于service to websocket 消息的推送 + * + * @author sz + * @since 2023/9/8 10:12 + */ +@Component +@Slf4j +@RequiredArgsConstructor +public class ServiceToWsListener implements MessageListener { + + private final List serviceToWsMsgHandlers; + + private final RedisTemplate redisTemplate; + + @Override + public void onMessage(Message message, byte[] pattern) { + System.out.println("订阅到的消息"); + TransferMessage tm = (TransferMessage) redisTemplate.getValueSerializer().deserialize(message.getBody()); + log.info(" [service-to-ws] tm = {}", JsonUtils.toJsonString(tm)); + // 调用所有实现了TransferMessageHandler接口的处理器 + for (ServiceToWsMsgHandler handler : serviceToWsMsgHandlers) { + handler.handleTransferMessage(tm); + } + } + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/UserPermissionChangeListener.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/UserPermissionChangeListener.java new file mode 100644 index 0000000..129b7c1 --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/UserPermissionChangeListener.java @@ -0,0 +1,40 @@ +package com.sz.redis.listener; + +import com.sz.core.common.entity.UserPermissionChangeMessage; +import com.sz.core.util.JsonUtils; +import com.sz.redis.handler.UserPermissionChangeMsgHandler; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * redis消息listener, 用于监听 用户permission change + * + * @author sz + * @since 2023/9/8 10:12 + */ +@Component +@Slf4j +@RequiredArgsConstructor +public class UserPermissionChangeListener implements MessageListener { + + private final List messageHandlers; + + private final RedisTemplate redisTemplate; + + @Override + public void onMessage(Message message, byte[] pattern) { + UserPermissionChangeMessage upcm = (UserPermissionChangeMessage) redisTemplate.getValueSerializer().deserialize(message.getBody()); + log.info(" [user change permission ] tm = {}", JsonUtils.toJsonString(upcm)); + // 调用所有实现了TransferMessageHandler接口的处理器 + for (UserPermissionChangeMsgHandler handler : messageHandlers) { + handler.handlerMsg(upcm); + } + } + +} diff --git a/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/WsToServiceListener.java b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/WsToServiceListener.java new file mode 100644 index 0000000..480e8f4 --- /dev/null +++ b/sz-common/sz-common-db-redis/src/main/java/com/sz/redis/listener/WsToServiceListener.java @@ -0,0 +1,40 @@ +package com.sz.redis.listener; + +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.util.JsonUtils; +import com.sz.redis.handler.WsToServiceMsgHandler; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * redis消息listener, 用于监听websocket to service消息的推送 + * + * @author sz + * @since 2023/9/8 10:12 + */ +@Component +@Slf4j +@RequiredArgsConstructor +public class WsToServiceListener implements MessageListener { + + private final List messageHandlers; + + private final RedisTemplate redisTemplate; + + @Override + public void onMessage(Message message, byte[] pattern) { + TransferMessage tm = (TransferMessage) redisTemplate.getValueSerializer().deserialize(message.getBody()); + log.info(" [ws-to-service] tm = {}", JsonUtils.toJsonString(tm)); + // 调用所有实现了TransferMessageHandler接口的处理器 + for (WsToServiceMsgHandler handler : messageHandlers) { + handler.handlerMsg(tm); + } + } + +} diff --git a/sz-common/sz-common-excel/pom.xml b/sz-common/sz-common-excel/pom.xml new file mode 100644 index 0000000..67bc2df --- /dev/null +++ b/sz-common/sz-common-excel/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + + com.sz + sz-common + ${revision} + + + com.sz.excel + sz-common-excel + + + + org.springframework.boot + spring-boot-starter-web + provided + true + + + com.sz + sz-common-core + ${revision} + provided + true + + + cn.idev.excel + fastexcel + + + org.apache.poi + poi-ooxml + + + + + + org.apache.poi + poi-ooxml + 5.4.0 + + + + \ No newline at end of file diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/annotation/CellMerge.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/annotation/CellMerge.java new file mode 100644 index 0000000..f3c3532 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/annotation/CellMerge.java @@ -0,0 +1,18 @@ +package com.sz.excel.annotation; + +import java.lang.annotation.*; + +/** + * excel 单元格合并(针对列相同项) + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CellMerge { + + /** + * col index + */ + int index() default -1; + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/annotation/DictFormat.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/annotation/DictFormat.java new file mode 100644 index 0000000..88ba62f --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/annotation/DictFormat.java @@ -0,0 +1,50 @@ +package com.sz.excel.annotation; + +import com.sz.excel.core.ExcelDynamicSelect; + +import java.lang.annotation.*; + +/** + * 字典,下拉处理 + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface DictFormat { + + /** + * 如果是字典类型,请设置字典的type值 (如: account_status) + */ + String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + String separator() default ","; + + /** + * (导出时)是否作为下拉项 + * + * @return boolean + */ + boolean isSelected() default false; + + /** + * 动态下拉内容( 适用于导出模版的场景) + */ + Class[] sourceClass() default {}; + + /** + * 字典是否使用别名 (为true时将使用alias而非id做映射) + * + * @return boolean + */ + boolean useAlias() default false; + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/AbstractExcelDictConvert.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/AbstractExcelDictConvert.java new file mode 100644 index 0000000..08e4456 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/AbstractExcelDictConvert.java @@ -0,0 +1,113 @@ +package com.sz.excel.convert; + +import cn.idev.excel.converters.Converter; +import cn.idev.excel.enums.CellDataTypeEnum; +import cn.idev.excel.metadata.GlobalConfiguration; +import cn.idev.excel.metadata.data.ReadCellData; +import cn.idev.excel.metadata.data.WriteCellData; +import cn.idev.excel.metadata.property.ExcelContentProperty; +import com.sz.core.common.entity.DictVO; +import com.sz.core.util.StreamUtils; +import com.sz.core.util.Utils; +import com.sz.excel.annotation.DictFormat; +import com.sz.excel.utils.ExcelUtils; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNoneBlank; + +public abstract class AbstractExcelDictConvert implements Converter { + + protected Map> dictmap; + + protected AbstractExcelDictConvert(Map> dictmap) { + this.dictmap = dictmap; + } + + protected String getLabelFromDict(String dictType, String dictValue, DictFormat anno) { + // 处理特殊情况,dictType为空且readConverterExp非空时直接返回转换结果 + if (isBlank(dictType) && isNoneBlank(anno.readConverterExp())) { + return ExcelUtils.convertByExp(dictValue, anno.readConverterExp(), anno.separator()); + } + + // 获取字典列表 + List dictLists = dictmap.get(dictType); + if (dictLists == null || dictLists.isEmpty()) { + return ""; + } + + // 根据是否使用Alias构造字典映射 + Map map = StreamUtils.toMap(dictLists, vo -> anno.useAlias() && vo.getAlias() != null ? vo.getAlias() : vo.getId(), + vo -> vo.getCodeName() != null ? vo.getCodeName() : ""); + + // 返回对应的标签,找不到时返回空字符串 + return map.getOrDefault(dictValue, ""); + } + + protected T getValueFromExcelData(ReadCellData cellData, DictFormat anno, String dictType) { + String dictLabel = cellData.getStringValue(); + String value; + if (isBlank(dictType) && isNoneBlank(anno.readConverterExp())) { + value = ExcelUtils.reverseByExp(dictLabel, anno.readConverterExp(), anno.separator()); + } else { + List dictLists = dictmap.get(dictType); + Map map; + if (anno.useAlias()) { + map = StreamUtils.toMap(dictLists, DictVO::getCodeName, vo -> vo.getAlias() == null ? "" : vo.getAlias()); + } else { + map = StreamUtils.toMap(dictLists, DictVO::getCodeName, DictVO::getId); + } + value = map.getOrDefault(dictLabel, ""); + } + return convertToJava(value); + } + + protected abstract T convertToJava(String value); + + protected abstract WriteCellData createWriteCellData(T object); + + @Override + public Class supportJavaTypeKey() { + return getJavaTypeClass(); + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public T convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (contentProperty == null) { + return convertToJava(cellData.getStringValue()); + } + Field field = contentProperty.getField(); + DictFormat anno = field.getAnnotation(DictFormat.class); + if (anno == null) { + return convertToJava(cellData.getStringValue()); + } + String dictType = anno.dictType(); + return getValueFromExcelData(cellData, anno, dictType); + } + + @Override + public WriteCellData convertToExcelData(T object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (contentProperty == null) { + return createWriteCellData(object); + } + Field field = contentProperty.getField(); + DictFormat anno = field.getAnnotation(DictFormat.class); + if (anno == null) { + return createWriteCellData(object); + } + String dictType = anno.dictType(); + String dictValue = Utils.getStringVal(object); + String label = getLabelFromDict(dictType, dictValue, anno); + return new WriteCellData<>(label); + } + + protected abstract Class getJavaTypeClass(); +} \ No newline at end of file diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomIntegerStringConvert.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomIntegerStringConvert.java new file mode 100644 index 0000000..1776b03 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomIntegerStringConvert.java @@ -0,0 +1,40 @@ +package com.sz.excel.convert; + +import cn.idev.excel.metadata.data.WriteCellData; +import com.sz.core.common.entity.DictVO; +import com.sz.core.util.Utils; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; + +/** + * Excel Integer 类型转换器 + */ +@Getter +@Setter +@Slf4j +public class CustomIntegerStringConvert extends AbstractExcelDictConvert { + + public CustomIntegerStringConvert(Map> dictmap) { + super(dictmap); + } + + @Override + protected Integer convertToJava(String value) { + return Utils.getIntVal(value); + } + + @Override + protected WriteCellData createWriteCellData(Integer object) { + return new WriteCellData<>(String.valueOf(object)); + } + + @Override + protected Class getJavaTypeClass() { + return Integer.class; + } + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomLongStringConvert.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomLongStringConvert.java new file mode 100644 index 0000000..1665a11 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomLongStringConvert.java @@ -0,0 +1,54 @@ +package com.sz.excel.convert; + +import cn.idev.excel.enums.CellDataTypeEnum; +import cn.idev.excel.metadata.data.WriteCellData; +import com.sz.core.common.entity.DictVO; +import com.sz.core.util.Utils; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +/** + * Excel Long 类型转换器 + */ +@Getter +@Setter +@Slf4j +public class CustomLongStringConvert extends AbstractExcelDictConvert { + + public CustomLongStringConvert(Map> dictmap) { + super(dictmap); + } + + @Override + protected Long convertToJava(String value) { + return Utils.getLongVal(value); + } + + @Override + protected WriteCellData createWriteCellData(Long object) { + return formatLongNumber(object); + } + + @Override + protected Class getJavaTypeClass() { + return Long.class; + } + + private static WriteCellData formatLongNumber(Long object) { + String str = Utils.getStringVal(object); + if (str.length() > 15) { + return new WriteCellData<>(str); + } else { + WriteCellData cellData = new WriteCellData<>(); + cellData.setType(CellDataTypeEnum.NUMBER); + cellData.setNumberValue(new BigDecimal(object)); + return cellData; + } + } + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomStringStringConvert.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomStringStringConvert.java new file mode 100644 index 0000000..25fed2e --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/convert/CustomStringStringConvert.java @@ -0,0 +1,38 @@ +package com.sz.excel.convert; + +import cn.idev.excel.metadata.data.WriteCellData; +import com.sz.core.common.entity.DictVO; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.Map; + +/** + * Excel String 类型转换器 + */ +@Getter +@Setter +@Slf4j +public class CustomStringStringConvert extends AbstractExcelDictConvert { + + public CustomStringStringConvert(Map> dictmap) { + super(dictmap); + } + + @Override + protected String convertToJava(String value) { + return value; + } + + @Override + protected WriteCellData createWriteCellData(String object) { + return new WriteCellData<>(object); + } + + @Override + protected Class getJavaTypeClass() { + return String.class; + } +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/CellMergeStrategy.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/CellMergeStrategy.java new file mode 100644 index 0000000..6565131 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/CellMergeStrategy.java @@ -0,0 +1,132 @@ +package com.sz.excel.core; + +import cn.idev.excel.annotation.ExcelProperty; +import cn.idev.excel.metadata.Head; +import cn.idev.excel.write.merge.AbstractMergeStrategy; +import com.sz.core.util.Utils; +import com.sz.excel.annotation.CellMerge; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 列值重复合并策略 + * + * @author sz + */ +@Slf4j +public class CellMergeStrategy extends AbstractMergeStrategy { + + private final List cellList; + + /** + * 是否有标题 + */ + private final boolean hasTitle; + + /** + * 开始行号,从0开始(第一行),如果有要忽略的(标题行)需要设置非0 + */ + private int rowIndex; + + public CellMergeStrategy(List list, boolean hasTitle) { + this.hasTitle = hasTitle; + // 行合并开始下标 + this.rowIndex = hasTitle ? 1 : 0; + this.cellList = handle(list, hasTitle); + } + + public CellMergeStrategy(List list, int rowIndex) { + boolean hasTitleBool; + hasTitleBool = rowIndex > 0; + this.hasTitle = hasTitleBool; + this.rowIndex = rowIndex; + this.cellList = handle(list, hasTitle); + } + + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + // 如果 cellList 不为空,并且当前单元格是第一列的第一行,则合并单元格 + if (!cellList.isEmpty() && cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) { + for (CellRangeAddress item : cellList) { + sheet.addMergedRegion(item); + } + } + } + + @SneakyThrows + private List handle(List list, boolean hasTitle) { + List localCellList = new ArrayList<>(); // Local variables should not shadow class fields + if (list.isEmpty()) { + return localCellList; + } + + // 获取字段信息并初始化合并字段 + List mergeFields = new ArrayList<>(); + List mergeFieldsIndex = new ArrayList<>(); + int startRowIndex = initializeMergeFields(list.getFirst().getClass(), mergeFields, mergeFieldsIndex, hasTitle); + + // 处理合并逻辑 + Map prevRowValues = new HashMap<>(); + for (int i = 1; i < list.size(); i++) { + boolean merged = false; + for (int j = 0; j < mergeFields.size(); j++) { + Field field = mergeFields.get(j); + Object currentValue = Utils.invokeGetter(list.get(i), field.getName()); + Object prevValue = prevRowValues.get(field); + + if (prevValue != null && prevValue.equals(currentValue)) { + if (!merged) { + int colNum = mergeFieldsIndex.get(j) - 1; + localCellList.add(new CellRangeAddress(i - 1 + startRowIndex, i + startRowIndex, colNum, colNum)); + merged = true; + } + } else { + prevRowValues.put(field, currentValue); + } + } + } + + return localCellList; + } + + private int initializeMergeFields(Class clazz, List mergeFields, List mergeFieldsIndex, boolean hasTitle) { + Field[] fields = Utils.getFields(clazz); + int startRowIndex = 0; + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); + mergeFields.add(field); + mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); + + if (hasTitle) { + ExcelProperty property = field.getAnnotation(ExcelProperty.class); + startRowIndex = Math.max(startRowIndex, property.value().length); + } + } + } + + return startRowIndex; + } + + @Data + @AllArgsConstructor + static class RepeatCell { + + private Object value; + + private int current; + + } + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/DefaultExcelListener.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/DefaultExcelListener.java new file mode 100644 index 0000000..592c2aa --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/DefaultExcelListener.java @@ -0,0 +1,149 @@ +package com.sz.excel.core; + +import cn.idev.excel.annotation.ExcelProperty; +import cn.idev.excel.context.AnalysisContext; +import cn.idev.excel.event.AnalysisEventListener; +import cn.idev.excel.exception.ExcelAnalysisException; +import cn.idev.excel.exception.ExcelDataConvertException; +import cn.idev.excel.metadata.CellExtra; +import com.sz.core.util.JsonUtils; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +/** + * @author sz + * @since 2023/12/26 14:43 + */ +@Slf4j +@Data +@EqualsAndHashCode(callSuper = false) +public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener { + + /** + * 是否Validator检验,默认为是 + */ + private boolean validateHeader = true; + + /** + * excel 表头数据 + */ + private Map headMap; + + private ParameterizedType type; + + private Class clazz; + + /** + * 导入回执 + */ + private ExcelResult excelResult; + + public DefaultExcelListener(boolean validateHeader, Class clazz) { + this.excelResult = new DefaultExcelResult<>(); + this.validateHeader = validateHeader; + this.clazz = clazz; + } + + @Override + public void invoke(T data, AnalysisContext analysisContext) { + excelResult.getList().add(data); + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("解析表头数据: {}", JsonUtils.toJsonString(headMap)); + // 校验表头 + if (validateHeader) { + // 获取所有字段 + Field[] fields = clazz.getDeclaredFields(); + Map expectedHeadMap = new TreeMap<>(); + for (Field field : fields) { + // 检查字段是否有@ExcelProperty注解 + if (field.isAnnotationPresent(ExcelProperty.class)) { + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + expectedHeadMap.put(expectedHeadMap.size(), excelProperty.value()[0]); + } + } + if (headMap.isEmpty()) { + throw new ExcelAnalysisException("无效的表头"); + } else if (!headMap.equals(expectedHeadMap)) { + String expectedHeaders = String.join(", ", expectedHeadMap.values()); + String actualHeaders = String.join(", ", headMap.values()); + String errMsg = String.format("表头校验失败:

期望:
[%s];

实际:
[%s];", expectedHeaders, actualHeaders); + throw new ExcelAnalysisException(errMsg); + } else { + log.debug("表头一致"); + } + } + } + + /** + * 处理发生的异常。 + * + * 该方法用于处理在处理过程中出现的异常,根据异常类型和上下文信息提供适当的处理逻辑。 + * + * @param exception + * 发生的异常 + * @param context + * 异常发生时的上下文信息,提供额外的处理依据 + */ + + @Override + public void onException(Exception exception, AnalysisContext context) { + String errMsg; + if (exception instanceof ExcelDataConvertException excelDataConvertException) { + // 如果是某一个单元格的转换异常 能获取到具体行号 + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = String.format("第%d行-第%d列-表头 [%s]: 解析异常
", rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + log.error(errMsg); + } else if (exception instanceof ConstraintViolationException constraintViolationException) { + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = ""; + if (constraintViolations != null && !constraintViolations.isEmpty()) { + constraintViolationsMsg = constraintViolations.stream().map(ConstraintViolation::getMessage).filter(Objects::nonNull) + .collect(Collectors.joining(", ")); + } + errMsg = String.format("第%d行数据校验异常: %s", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + log.error(errMsg); + } else { + errMsg = exception.getMessage(); + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void extra(CellExtra extra, AnalysisContext context) { + super.extra(extra, context); + } + + /** + * 数据解析完毕 + * + * @param analysisContext + * 解析上下文 + */ + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + + } + + @Override + public boolean hasNext(AnalysisContext context) { + return super.hasNext(context); + } + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/DefaultExcelResult.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/DefaultExcelResult.java new file mode 100644 index 0000000..43cd018 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/DefaultExcelResult.java @@ -0,0 +1,60 @@ +package com.sz.excel.core; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author sz + * @since 2023/12/26 14:37 + */ +@Data +public class DefaultExcelResult implements ExcelResult { + + // 数据list + private List list; + + // 错误信息列表 + private List errorList; + + public DefaultExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefaultExcelResult(List list, List errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefaultExcelResult(ExcelResult excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return errorList; + } + + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorCount == 0) { + return String.format("恭喜您,全部读取成功!共%d条", successCount); + } else { + return ""; + } + } + } +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelDownHandler.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelDownHandler.java new file mode 100644 index 0000000..c065306 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelDownHandler.java @@ -0,0 +1,219 @@ +package com.sz.excel.core; + +import cn.idev.excel.metadata.FieldCache; +import cn.idev.excel.metadata.FieldWrapper; +import cn.idev.excel.util.ClassUtils; +import cn.idev.excel.write.handler.SheetWriteHandler; +import cn.idev.excel.write.metadata.holder.WriteSheetHolder; +import cn.idev.excel.write.metadata.holder.WriteWorkbookHolder; +import com.sz.core.common.dict.DictService; +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.core.util.StringUtils; +import com.sz.excel.annotation.DictFormat; +import com.sz.excel.utils.ExcelUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.ss.util.WorkbookUtil; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * excel下拉项 + * + * @author sz + * @since 2023/12/28 13:32 + */ +@Slf4j +public class ExcelDownHandler implements SheetWriteHandler { + + /** + * Excel表格中的列名英文 仅为了解析列英文,禁止修改 + */ + private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + /** + * 单选数据Sheet名 + */ + private static final String OPTIONS_SHEET_NAME = "options"; + + /** + * 当前单选进度 + */ + private int currentOptionsColumnIndex; + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + final Sheet sheet = writeSheetHolder.getSheet(); + final DataValidationHelper helper = sheet.getDataValidationHelper(); + final Workbook workbook = writeWorkbookHolder.getWorkbook(); + final FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder); + + for (Map.Entry entry : fieldCache.getSortedFieldMap().entrySet()) { + final Integer index = entry.getKey(); + final FieldWrapper wrapper = entry.getValue(); + final Field field = wrapper.getField(); + + if (field.isAnnotationPresent(DictFormat.class)) { + final DictFormat dictFormat = field.getDeclaredAnnotation(DictFormat.class); + if (dictFormat.isSelected()) { + processDictFormat(helper, workbook, sheet, index, dictFormat); + } + } + } + + SheetWriteHandler.super.afterSheetCreate(writeWorkbookHolder, writeSheetHolder); + } + + private void processDictFormat(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer index, DictFormat dictFormat) { + try { + final List options = getOptions(dictFormat); + if (!options.isEmpty()) { + dropDownWithSheet(helper, workbook, sheet, index, options); + } + } catch (Exception e) { + log.error("处理 DictFormat 失败", e); + } + } + + private List getOptions(DictFormat dictFormat) + throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { + List options = new ArrayList<>(); + final String dictType = dictFormat.dictType(); + final String converterExp = dictFormat.readConverterExp(); + final String separator = dictFormat.separator(); + final Class[] classes = dictFormat.sourceClass(); + + if (classes.length > 0) { + options = getDynamicSelectOptions(classes); + } else if (isNotBlank(dictType)) { + options = getDictTypeOptions(dictType); + } else if (isNotBlank(converterExp)) { + options = ExcelUtils.listByExp(converterExp, separator); + } + + return options; + } + + private List getDynamicSelectOptions(Class[] classes) + throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { + List options = new ArrayList<>(); + final ExcelDynamicSelect excelDynamicSelect = classes[0].getDeclaredConstructor().newInstance(); + final List dynamicSelectSource = excelDynamicSelect.getSource(); + if (dynamicSelectSource != null && !dynamicSelectSource.isEmpty()) { + options.addAll(dynamicSelectSource); + } + return options; + } + + private List getDictTypeOptions(String dictType) { + List options = new ArrayList<>(); + final DictService dictService = SpringApplicationContextUtils.getInstance().getBean(DictService.class); + final Map allDictByDictType = dictService.getAllDictByType(dictType); + if (allDictByDictType != null && !allDictByDictType.isEmpty()) { + options.addAll(allDictByDictType.keySet()); + } + return options; + } + + private void dropDownWithSheet(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer celIndex, List value) { + // 创建下拉数据表 + Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))) + .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))); + // 将下拉表隐藏 + workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true); + // 完善纵向的一级选项数据表 + for (int i = 0; i < value.size(); i++) { + int finalI = i; + // 获取每一选项行,如果没有则创建 + Row row = Optional.ofNullable(simpleDataSheet.getRow(i)).orElseGet(() -> simpleDataSheet.createRow(finalI)); + // 获取本级选项对应的选项列,如果没有则创建 + Cell cell = Optional.ofNullable(row.getCell(currentOptionsColumnIndex)).orElseGet(() -> row.createCell(currentOptionsColumnIndex)); + // 设置值 + cell.setCellValue(value.get(i)); + } + + // 创建名称管理器 + Name name = workbook.createName(); + // 设置名称管理器的别名 + String nameName = String.format("%s_%d", OPTIONS_SHEET_NAME, celIndex); + name.setNameName(nameName); + // 以纵向第一列创建一级下拉拼接引用位置 + String function = String.format("%s!$%s$1:$%s$%d", OPTIONS_SHEET_NAME, getExcelColumnName(currentOptionsColumnIndex), + getExcelColumnName(currentOptionsColumnIndex), value.size()); + // 设置名称管理器的引用位置 + name.setRefersToFormula(function); + // 设置数据校验为序列模式,引用的是名称管理器中的别名 + this.markOptionsToSheet(helper, sheet, celIndex, helper.createFormulaListConstraint(nameName)); + currentOptionsColumnIndex++; + } + + /** + * 挂载下拉的列,仅限一级选项 + */ + private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex, DataValidationConstraint constraint) { + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 应用数据校验 + */ + private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet, DataValidationConstraint constraint, CellRangeAddressList addressList) { + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, addressList); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + // 数据校验 + dataValidation.setSuppressDropDownArrow(true); + // 错误提示 + dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP); + dataValidation.createErrorBox("提示", "此值与单元格定义数据不一致"); + dataValidation.setShowErrorBox(true); + // 选定提示 + dataValidation.createPromptBox("填写说明:", "填写内容只能为下拉中数据,其他数据将导致导入失败"); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + *

依据列index获取列名英文

依据列index转换为Excel中的列名英文 + *

+ * 例如第1列,index为0,解析出来为A列 + *

+ * 第27列,index为26,解析为AA列 + *

+ * 第28列,index为27,解析为AB列 + *

+ * + * @param columnIndex + * 列index + * @return 列index所在得英文名 + */ + private String getExcelColumnName(int columnIndex) { + // 26一循环的次数 + int columnCircleCount = columnIndex / 26; + // 26一循环内的位置 + int thisCircleColumnIndex = columnIndex % 26; + // 26一循环的次数大于0,则视为栏名至少两位 + String columnPrefix = columnCircleCount == 0 ? "" : StringUtils.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1); + // 从26一循环内取对应的栏位名 + String columnNext = StringUtils.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1); + // 将二者拼接即为最终的栏位名 + return columnPrefix + columnNext; + } + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelDynamicSelect.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelDynamicSelect.java new file mode 100644 index 0000000..cb075bc --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelDynamicSelect.java @@ -0,0 +1,17 @@ +package com.sz.excel.core; + +import java.util.List; + +/** + * @author sz + * @since 2023/12/28 13:22 + */ +public interface ExcelDynamicSelect { + + /** + * 获取动态生成的下拉框可选数据 + * + * @return 动态生成的下拉框可选数据 + */ + List getSource(); +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelExceptionHandler.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelExceptionHandler.java new file mode 100644 index 0000000..109d2ec --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelExceptionHandler.java @@ -0,0 +1,26 @@ +package com.sz.excel.core; + +import cn.idev.excel.exception.ExcelAnalysisException; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BusinessExceptionCustomAssert; +import org.springframework.core.annotation.Order; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * @author sz + * @since 2024/12/27 16:21 + */ +@Order(Integer.MIN_VALUE) +@RestControllerAdvice +public class ExcelExceptionHandler { + + @ExceptionHandler(value = ExcelAnalysisException.class) + public ApiResult handlerNotPermissionException(ExcelAnalysisException e) { + BusinessExceptionCustomAssert message = CommonResponseEnum.EXCEL_IMPORT_ERROR.message(e.getMessage()); + // e.printStackTrace(); // 调试时可打开 + return ApiResult.error(message); + } + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelListener.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelListener.java new file mode 100644 index 0000000..7bb711a --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelListener.java @@ -0,0 +1,13 @@ +package com.sz.excel.core; + +import cn.idev.excel.read.listener.ReadListener; + +/** + * Excel 导入监听 + * + */ +public interface ExcelListener extends ReadListener { + + ExcelResult getExcelResult(); + +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelListenerFactory.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelListenerFactory.java new file mode 100644 index 0000000..2ae5dc8 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelListenerFactory.java @@ -0,0 +1,15 @@ +package com.sz.excel.core; + +import org.springframework.stereotype.Component; + +/** + * @author sz + * @since 2024/12/27 16:12 + */ +@Component +public class ExcelListenerFactory { + + public DefaultExcelListener createListener(boolean validateHeader, Class clazz) { + return new DefaultExcelListener<>(validateHeader, clazz); + } +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelResult.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelResult.java new file mode 100644 index 0000000..de60b90 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/core/ExcelResult.java @@ -0,0 +1,25 @@ +package com.sz.excel.core; + +import java.util.List; + +/** + * excel返回对象 + * + */ +public interface ExcelResult { + + /** + * 对象列表 + */ + List getList(); + + /** + * 错误列表 + */ + List getErrorList(); + + /** + * 导入回执 + */ + String getAnalysis(); +} diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/strategy/DefaultCellStyleStrategy.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/strategy/DefaultCellStyleStrategy.java new file mode 100644 index 0000000..63b5c20 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/strategy/DefaultCellStyleStrategy.java @@ -0,0 +1,74 @@ +package com.sz.excel.strategy; + +import cn.idev.excel.metadata.data.WriteCellData; +import cn.idev.excel.write.handler.context.CellWriteHandlerContext; +import cn.idev.excel.write.metadata.style.WriteCellStyle; +import cn.idev.excel.write.metadata.style.WriteFont; +import cn.idev.excel.write.style.HorizontalCellStyleStrategy; +import lombok.Getter; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; + +import java.util.List; + +/** + * 设置表头和填充内容的样式 + */ + +public class DefaultCellStyleStrategy extends HorizontalCellStyleStrategy { + + private final WriteCellStyle headWriteCellStyle; + + private final WriteCellStyle contentWriteCellStyle; + + @Getter + private final List columnIndexes; + + public DefaultCellStyleStrategy(List columnIndexes, WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) { + this.columnIndexes = columnIndexes; + this.headWriteCellStyle = headWriteCellStyle; + this.contentWriteCellStyle = contentWriteCellStyle; + } + + // 设置头样式 + @Override + protected void setHeadCellStyle(CellWriteHandlerContext context) { + // 获取字体实例 + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontName("宋体"); + + headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); + headWriteFont.setFontHeightInPoints((short) 14); + headWriteFont.setBold(false); + headWriteFont.setFontName("宋体"); + + headWriteCellStyle.setWriteFont(headWriteFont); + if (stopProcessing(context)) { + return; + } + WriteCellData cellData = context.getFirstCellData(); + WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle()); + } + + // 设置填充数据样式 + @Override + protected void setContentCellStyle(CellWriteHandlerContext context) { + WriteFont contentWriteFont = new WriteFont(); + contentWriteFont.setFontName("宋体"); + contentWriteFont.setFontHeightInPoints((short) 12); + // 设置数据填充后的实线边框 + contentWriteCellStyle.setWriteFont(contentWriteFont); + contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); + contentWriteCellStyle.setBorderTop(BorderStyle.THIN); + contentWriteCellStyle.setBorderRight(BorderStyle.THIN); + contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); + contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); + contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中 + WriteCellData cellData = context.getFirstCellData(); + WriteCellStyle.merge(contentWriteCellStyle, cellData.getOrCreateStyle()); + } + +} \ No newline at end of file diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/strategy/DefaultColumnWidthStyleStrategy.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/strategy/DefaultColumnWidthStyleStrategy.java new file mode 100644 index 0000000..ea0c234 --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/strategy/DefaultColumnWidthStyleStrategy.java @@ -0,0 +1,79 @@ +package com.sz.excel.strategy; + +import cn.idev.excel.enums.CellDataTypeEnum; +import cn.idev.excel.metadata.Head; +import cn.idev.excel.metadata.data.WriteCellData; +import cn.idev.excel.util.MapUtils; +import cn.idev.excel.write.metadata.holder.WriteSheetHolder; +import cn.idev.excel.write.style.column.AbstractColumnWidthStyleStrategy; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DefaultColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy { + + private static final int MAX_COLUMN_WIDTH = 255; + + private final Map> cache = MapUtils.newHashMapWithExpectedSize(8); + + @Override + protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, + Boolean isHead) { + boolean needSetWidth = isHead || !CollectionUtils.isEmpty(cellDataList); + if (!needSetWidth) { + return; + } + Map maxColumnWidthMap = cache.computeIfAbsent(writeSheetHolder.getSheetNo(), key -> new HashMap<>(16, 0.75f)); + Integer columnWidth = getColumnWidth(cellDataList, cell, isHead); + if (columnWidth < 0) { + return; + } + if (columnWidth > MAX_COLUMN_WIDTH) { + columnWidth = MAX_COLUMN_WIDTH; + } + Integer maxColumnWidth = maxColumnWidthMap.get(cell.getColumnIndex()); + if (maxColumnWidth == null || columnWidth > maxColumnWidth) { + maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth); + writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), columnWidth * 256); + } + } + + private Integer getColumnWidth(List> cellDataList, Cell cell, Boolean isHead) { + if (isHead) { + return cell.getStringCellValue().getBytes().length; + } + WriteCellData cellData = cellDataList.get(0); + CellDataTypeEnum type = cellData.getType(); + if (type == null) { + return -1; + } + switch (type) { + case STRING : + return getStringWidth(cellData.getStringValue()); + case BOOLEAN : + return cellData.getBooleanValue().toString().getBytes().length + 10; + case NUMBER : + return cellData.getNumberValue().toString().getBytes().length + 10; + case DATE : + return cellData.getDateValue().toString().getBytes().length + 10; + default : + return -1; + } + } + + private int getStringWidth(String str) { + if (str == null) { + return 0; + } + int width = str.length(); + for (char ch : str.toCharArray()) { + if (ch >= 0x4E00 && ch <= 0x9FA5) { // 中文字符 + width++; + } + } + return width + 5; // Add extra padding for better readability + } +} \ No newline at end of file diff --git a/sz-common/sz-common-excel/src/main/java/com/sz/excel/utils/ExcelUtils.java b/sz-common/sz-common-excel/src/main/java/com/sz/excel/utils/ExcelUtils.java new file mode 100644 index 0000000..a464a2d --- /dev/null +++ b/sz-common/sz-common-excel/src/main/java/com/sz/excel/utils/ExcelUtils.java @@ -0,0 +1,169 @@ +package com.sz.excel.utils; + +import cn.idev.excel.FastExcelFactory; +import cn.idev.excel.write.builder.ExcelWriterSheetBuilder; +import cn.idev.excel.write.metadata.style.WriteCellStyle; +import com.sz.core.common.entity.DictVO; +import com.sz.core.common.dict.DictService; +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.excel.convert.CustomIntegerStringConvert; +import com.sz.excel.convert.CustomLongStringConvert; +import com.sz.excel.convert.CustomStringStringConvert; +import com.sz.excel.core.*; +import com.sz.excel.strategy.DefaultCellStyleStrategy; +import com.sz.excel.strategy.DefaultColumnWidthStyleStrategy; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * Excel工具类 + * + * @author sz + * @since 2023/12/26 15:16 + */ +public class ExcelUtils { + + private ExcelUtils() { + throw new IllegalStateException("ExcelUtils class Illegal"); + } + + /** + * 异步导入 Excel 数据并同步返回结果。 + *

+ * 该方法从输入流中读取 Excel 文件,使用指定的类进行解析,并在解析过程中提供自定义字典转换。 可选择验证 Excel + * 文件的表头格式。解析完成后,返回包含解析结果的对象。 + * + * @param is + * Excel 文件的输入流 + * @param clazz + * 用于映射 Excel 数据的类类型 + * @param validateHeader + * 是否验证表头格式 + * @param + * 解析结果的类型 + * @return 包含解析结果的 ExcelResult 对象 + */ + + public static ExcelResult importExcel(InputStream is, Class clazz, boolean validateHeader) { + // 在这里获取字典传递给cover,减轻redis压力 + Map> dictmap = getDictList(); + ExcelListenerFactory listenerFactory = SpringApplicationContextUtils.getInstance().getBean(ExcelListenerFactory.class); + DefaultExcelListener listener = listenerFactory.createListener(validateHeader, clazz); + FastExcelFactory.read(is, clazz, listener).registerConverter(new CustomStringStringConvert(dictmap)) + .registerConverter(new CustomIntegerStringConvert(dictmap)).registerConverter(new CustomLongStringConvert(dictmap)).sheet().doRead(); + return listener.getExcelResult(); + } + + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os) { + // 在这里获取字典传递给cover,减轻redis压力 + Map> dictmap = getDictList(); + ExcelWriterSheetBuilder builder = FastExcelFactory.write(os, clazz).autoCloseStream(false) + // 列宽自动适配 + .registerWriteHandler(new DefaultColumnWidthStyleStrategy()) + // 表格样式 + .registerWriteHandler(new DefaultCellStyleStrategy(Arrays.asList(0, 1), new WriteCellStyle(), new WriteCellStyle())) + // 自定义cover处理器 + .registerConverter(new CustomStringStringConvert(dictmap)).registerConverter(new CustomIntegerStringConvert(dictmap)) + .registerConverter(new CustomLongStringConvert(dictmap)).sheet(sheetName); + // 添加下拉框操作 + builder.registerWriteHandler(new ExcelDownHandler()); + builder.doWrite(list); + } + + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os, boolean isMerge) { + // 在这里获取字典传递给cover,减轻redis压力 + Map> dictmap = getDictList(); + ExcelWriterSheetBuilder builder = FastExcelFactory.write(os, clazz).autoCloseStream(false) + // 列宽自动适配 + .registerWriteHandler(new DefaultColumnWidthStyleStrategy()) + // 表格样式 + .registerWriteHandler(new DefaultCellStyleStrategy(Arrays.asList(0, 1), new WriteCellStyle(), new WriteCellStyle())) + // 自定义cover处理器 + .registerConverter(new CustomStringStringConvert(dictmap)).registerConverter(new CustomIntegerStringConvert(dictmap)) + .registerConverter(new CustomLongStringConvert(dictmap)).sheet(sheetName); + if (isMerge) { + builder.registerWriteHandler(new CellMergeStrategy(list, 1)); + } + + // 添加下拉框操作 + builder.registerWriteHandler(new ExcelDownHandler()); + builder.doWrite(list); + } + + /** + * 解析值(import方向) 男=0,女=1,未知=2 禁言=1000003,禁用=1000002,正常=1000001 + * + * @param propertyValue + * 参数值 + * @param converterExp + * 翻译注解 + * @param separator + * 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + String[] convertSource = converterExp.split(separator); + for (String item : convertSource) { + String[] itemArray = item.split("="); // ["禁言","1000003"] + if (itemArray[0].equals(propertyValue)) { // propertyValue = 禁言 + return itemArray[1]; + } + } + return ""; + } + + /** + * 解析值(export方向) 禁言=1000003,禁用=1000002,正常=1000001 + * + * @param propertyValue + * 参数值 + * @param converterExp + * 翻译注解 + * @param separator + * 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + String[] convertSource = converterExp.split(separator); + for (String item : convertSource) { + String[] itemArray = item.split("="); // ["禁言", "1000003"] + if (itemArray[1].equals(propertyValue)) { // propertyValue = 1000003 + return itemArray[0]; + } + } + return ""; + } + + /** + * 将表达式转换为列表。 + *

+ * 该方法根据指定的分隔符,将字符串表达式转换为字符串列表。 + * + * @param converterExp + * 要转换的字符串表达式 + * @param separator + * 用于分隔表达式的分隔符 + * @return 转换后的字符串列表 + */ + + public static List listByExp(String converterExp, String separator) { + List list = new ArrayList<>(); + String[] convertSource = converterExp.split(separator); + for (String item : convertSource) { + String[] itemArray = item.split("="); // ["禁言", "1000003"] + list.add(itemArray[0]); + } + return list; + } + + private static Map> getDictList() { + DictService dictService = SpringApplicationContextUtils.getInstance().getBean(DictService.class); + return dictService.getAllDict(); + } + +} diff --git a/sz-common/sz-common-generator/pom.xml b/sz-common/sz-common-generator/pom.xml new file mode 100644 index 0000000..e6b4c1e --- /dev/null +++ b/sz-common/sz-common-generator/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + com.sz + sz-common + ${revision} + + + com.sz.generator + sz-common-generator + + + + org.springframework.boot + spring-boot-starter-web + provided + true + + + + com.sz + sz-common-core + ${revision} + provided + true + + + + com.sz + sz-common-db-mysql + ${revision} + provided + true + + + + com.sz + sz-common-security + ${revision} + provided + true + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/controller/GeneratorTableController.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/controller/GeneratorTableController.java new file mode 100644 index 0000000..b5ee00c --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/controller/GeneratorTableController.java @@ -0,0 +1,120 @@ +package com.sz.generator.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.util.FileUtils; +import com.sz.generator.pojo.dto.DbTableQueryDTO; +import com.sz.generator.pojo.dto.ImportTableDTO; +import com.sz.generator.pojo.dto.SelectTablesDTO; +import com.sz.generator.pojo.po.GeneratorTable; +import com.sz.generator.pojo.vo.GenCheckedInfoVO; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import com.sz.generator.pojo.vo.GeneratorPreviewVO; +import com.sz.generator.service.GeneratorTableService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.apache.commons.io.IOUtils; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +/** + *

+ * 代码生成业务表 前端控制器 + *

+ * + * @author sz + * @since 2023-11-27 + */ +@Tag(name = "代码生成") +@RestController +@RequestMapping("/generator") +@RequiredArgsConstructor +public class GeneratorTableController { + + private final GeneratorTableService generatorTableService; + + @SaCheckPermission(value = "generator.import", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "导入指定表") + @PostMapping("import") + public ApiResult importTables(@RequestBody ImportTableDTO dto) { + generatorTableService.importTable(dto); + return ApiResult.success(); + } + + @SaCheckPermission(value = "generator.import", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "查询要导入的表列表(排除已经导入的表)") + @GetMapping("schema/list") + public ApiResult> schemaList(DbTableQueryDTO dto) { + return ApiPageResult.success(generatorTableService.selectDbTableNotInImport(dto)); + } + + @SaCheckPermission(value = "generator.import", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "查询已经导入的表列表") + @GetMapping("list") + public ApiResult> list(DbTableQueryDTO dto) { + return ApiPageResult.success(generatorTableService.selectDbTableByImport(dto)); + } + + @Operation(summary = "代码生成参数详情") + @GetMapping("/{tableName}") + public ApiResult detail(@PathVariable String tableName) { + return ApiResult.success(generatorTableService.detail(tableName)); + } + + @SaCheckPermission(value = "generator.update", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "更新代码生成配置") + @PutMapping() + public ApiResult updateGenerator(@RequestBody GeneratorDetailVO dto) { + generatorTableService.updateGeneratorSetting(dto); + return ApiResult.success(); + } + + @SaCheckPermission(value = "generator.generator", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "代码生成") + @PostMapping("generator/{tableName}") + public ApiResult> generator(@PathVariable String tableName) throws IOException { + return ApiResult.success(generatorTableService.generator(tableName)); + } + + @SaCheckPermission(value = "generator.remove", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "删除导入的表") + @DeleteMapping + public ApiResult remove(@RequestBody SelectTablesDTO dto) { + generatorTableService.remove(dto); + return ApiResult.success(); + } + + @SaCheckPermission(value = "generator.zip", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "zip下载") + @PostMapping("zip") + public void downloadZip(@RequestBody SelectTablesDTO dto, HttpServletResponse response) throws IOException { + byte[] data = generatorTableService.downloadZip(dto); + OutputStream outputStream = FileUtils.getOutputStream(response, "sz-admin-" + dto.getTableNames() + ".zip", data.length); + // 将字节数组写入输出流 + IOUtils.write(data, outputStream); + response.flushBuffer(); + } + + @SaCheckPermission(value = "generator.preview", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "预览") + @GetMapping("preview/{tableName}") + public ApiResult> preview(@PathVariable String tableName) throws IOException { + return ApiResult.success(generatorTableService.preview(tableName)); + } + + @SaCheckPermission(value = "generator.generator", orRole = GlobalConstant.SUPER_ROLE) + @Operation(summary = "验证磁盘") + @GetMapping("check/{tableName}") + public ApiResult check(@PathVariable String tableName) { + return ApiResult.success(generatorTableService.checkDist(tableName)); + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/AbstractCodeGenerationTemplate.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/AbstractCodeGenerationTemplate.java new file mode 100644 index 0000000..3273717 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/AbstractCodeGenerationTemplate.java @@ -0,0 +1,162 @@ +package com.sz.generator.core; + +import com.sz.generator.pojo.vo.CodeGenTempResult; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/15 15:51 + */ +@Slf4j +public abstract class AbstractCodeGenerationTemplate { + + private final FreeMarkerConfigurer configurer; + + private final String rootPath; + + @Getter + private final GeneratorDetailVO detailVO; + + private final Map model; + + protected AbstractCodeGenerationTemplate(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + this.configurer = configurer; + this.rootPath = rootPath; + this.detailVO = detailVO; + this.model = model; + } + + // 模板名 + protected abstract String getTemplateFileName(); + + // 输出文件名 + protected abstract String getOutputFileName(Map model); + + // 开发环境对应的前缀路径 如 java 的 src/main/java + protected abstract String getProjectPrefix(); + + // 文件扩展名 + protected abstract String getExtension(); + + // 别名 + protected abstract String alias(); + + protected abstract String language(); + + // zip要存储的目录 + protected abstract String getZipParentPackage(); + + protected abstract String getOutputPackage(Map model); + + public CodeGenTempResult buildTemplate(boolean isSaveToLocal) throws IOException { + Template template = configurer.getConfiguration().getTemplate(getTemplateFileName()); + String outputPackage = getOutputPackage(model); + String outputClassName = getOutputFileName(model); + String zipPath = buildRelativeOutputFilePath(outputPackage, outputClassName, getExtension()); + + String outputMsg = ""; + // 本地环境,保存代码到指定目录下 + if (isSaveToLocal) { + String outputPath = buildAbsoluteOutputFilePath(rootPath, getProjectPrefix(), zipPath); + outputMsg = saveToFile(outputPath, template, model); + } else { + if (getZipParentPackage() != null && !getZipParentPackage().trim().isEmpty()) { + zipPath = Paths.get(getZipParentPackage(), zipPath).toString(); + } + } + return new CodeGenTempResult(template, zipPath, getExtension(), alias(), language(), outputMsg); + } + + /** + * 构建绝对路径(完整路径)。 + * + * 该方法根据提供的根路径、项目前缀和压缩文件路径,生成完整的绝对路径字符串。 + * + * @param rootPath + * 根路径,通常为文件系统的基础路径 + * @param projectPrefix + * 项目前缀,用于区分不同项目的路径 + * @param zipPath + * 压缩文件的相对路径 + * @return 生成的完整绝对路径字符串 + */ + private static String buildAbsoluteOutputFilePath(String rootPath, String projectPrefix, String zipPath) { + return Paths.get(rootPath, projectPrefix, zipPath).toString(); + } + + /** + * 构建相对路径(用于存储 ZIP 文件的路径)。 + * + * 该方法根据输出包路径、输出类名和文件扩展名,生成用于存储 ZIP 文件的相对路径。 + * + * @param outputPackage + * 输出包路径,表示文件所在的包结构 + * @param outputClassName + * 输出类名,用于构成文件名的一部分 + * @param extension + * 文件扩展名,例如 ".zip" 或其他文件类型 + * @return 生成的 ZIP 文件存储的相对路径字符串 + */ + private static String buildRelativeOutputFilePath(String outputPackage, String outputClassName, String extension) { + return Paths.get(outputPackage.replace(".", File.separator), outputClassName + extension).toString(); + } + + /** + * 生成文件。 + * + * 该方法根据提供的模板和数据模型,生成文件并保存到指定的输出路径。 + * + * @param outputPath + * 文件的输出路径,指定生成的文件保存的位置 + * @param template + * 使用的模板,用于生成文件的内容 + * @param model + * 数据模型,填充模板中的占位符 + */ + private static String saveToFile(String outputPath, Template template, Map model) { + try { + Path path = Paths.get(outputPath); + // Get the parent directory of the output file + Path parentDirectory = path.getParent(); + // Check if the parent directory exists, create it if not + if (!Files.exists(parentDirectory)) { + Files.createDirectories(parentDirectory); + } + + // Check if the file already exists + if (Files.exists(path)) { + // File already exists, handle accordingly (e.g., change filename, throw + // exception) + String info = "File already exists: " + outputPath; + log.error(info); + return info; // Do nothing or throw an exception based on your requirement + } + + // Write the template content to the file + try (Writer writer = new FileWriter(outputPath)) { + template.process(model, writer); + log.info("Output Path: {}", outputPath); + return "Output Path: " + outputPath; + } + + } catch (IOException | TemplateException e) { + log.error("saveToFile err", e); + return "Output Err: " + outputPath; + } + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/CodeModelBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/CodeModelBuilder.java new file mode 100644 index 0000000..1eb00cd --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/CodeModelBuilder.java @@ -0,0 +1,214 @@ +package com.sz.generator.core; + +import com.sz.core.util.DateUtils; +import com.sz.core.util.JsonUtils; +import com.sz.core.util.Utils; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import lombok.Getter; + +import java.io.File; +import java.nio.file.Paths; +import java.util.*; + +/** + * @author sz + * @since 2024/1/15 15:10 + */ +@Getter +public class CodeModelBuilder { + + private final Map model = new HashMap<>(); + + // vue 文件夹路径分隔符 + public static final String SEPARATOR = "/"; + + public CodeModelBuilder builderBaseInfo(GeneratorDetailVO detailVO) { + String className = detailVO.getBaseInfo().getClassName(); + String packageName = detailVO.getGeneratorInfo().getPackageName(); + String router = getRouter(detailVO); // 路由名 + String tableName = detailVO.getBaseInfo().getTableName(); // 表名,例如sys_user + String functionName = detailVO.getGeneratorInfo().getFunctionName(); // 方法名或业务名,例如:教师统计 + String businessName = detailVO.getGeneratorInfo().getBusinessName(); + + List columns = detailVO.getColumns(); + model.put("packageName", packageName); + model.put("tableComment", detailVO.getBaseInfo().getTableComment()); + model.put("author", detailVO.getBaseInfo().getFunctionAuthor()); + model.put("datetime", DateUtils.getDefaultDate()); + model.put("tableName", tableName); + model.put("className", className); + model.put("columns", columns); + model.put("camelClassName", detailVO.getBaseInfo().getCamelClassName()); + model.put("functionName", functionName); + model.put("businessName", businessName); + model.put("GeneratorInfo", detailVO.getGeneratorInfo()); + model.put("router", router); + model.put("dictTypes", detailVO.getDictTypes()); + + return this; + } + + public CodeModelBuilder builderImportPackage(GeneratorDetailVO detailVO) { + List columns = detailVO.getColumns(); + Set importPackages = new TreeSet<>(); + boolean hasUniqueValidField = false; + boolean hasDateFormat = false; + for (GeneratorDetailVO.Column column : columns) { + String javaTypePackage = column.getJavaTypePackage(); + if (Utils.isNotNull(javaTypePackage)) { + String[] split = javaTypePackage.split(","); + Collections.addAll(importPackages, split); + // importPackages.add(javaTypePackage); + } + if (("LocalDateTime").equals(column.getJavaType())) { + hasDateFormat = true; + } + if (("1").equals(column.getIsUniqueValid())) { + hasUniqueValidField = true; + } + if (column.getJavaType().startsWith("List")) { + importPackages.add("java.util.List"); + } + } + System.out.println("importPackages ==" + JsonUtils.toJsonString(importPackages)); + model.put("importPackages", importPackages); + model.put("hasUniqueValidField", hasUniqueValidField); + model.put("hasDateFormat", hasDateFormat); + return this; + } + + public CodeModelBuilder builderDynamicsParam(GeneratorDetailVO detailVO) { + String idType = ""; + String pkName = ""; + boolean hasDict = false; + boolean hasSelect = false; + boolean hasExcel = false; + List pkColumns = new ArrayList<>(); + List columns = detailVO.getColumns(); + + boolean hasGenExcel = ("1").equals(detailVO.getGeneratorInfo().getHasImport()) || ("1").equals(detailVO.getGeneratorInfo().getHasExport()); + + for (GeneratorDetailVO.Column column : columns) { + if (hasGenExcel && (("1").equals(column.getIsImport()) || ("1").equals(column.getIsExport()))) { + hasExcel = true; + } + + if (("1").equals(column.getIsPk())) { + idType = column.getTsType(); + pkName = column.getJavaField(); + } + if (Utils.isNotNull(column.getDictType())) { + hasDict = true; + } + if (("select").equals(column.getHtmlType()) || ("radio").equals(column.getHtmlType())) { + hasSelect = true; + } + if (column.getIsPk().equals("1")) { + pkColumns.add(column); + } + } + model.put("pkName", pkName); + model.put("hasDict", hasDict); + model.put("hasSelect", hasSelect); + model.put("hasExcel", hasExcel); + model.put("idType", idType); + model.put("pkColumns", pkColumns); + return this; + } + + public CodeModelBuilder builderPojo(GeneratorDetailVO detailVO) { + String packageGroup = detailVO.getGeneratorInfo().getModuleName(); + String poPkg = buildPackagePath(detailVO, packageGroup, "pojo" + File.separator + "po"); + String mapperPkg = buildPackagePath(detailVO, packageGroup, "mapper"); + String servicePkg = buildPackagePath(detailVO, packageGroup, "service"); + String serviceImplPkg = buildPackagePath(detailVO, packageGroup, "service" + File.separator + "impl"); + String controllerPkg = buildPackagePath(detailVO, packageGroup, "controller"); + String mapperXmlPkg = Paths.get("mapper", packageGroup).toString(); + String dtoPkg = buildPackagePath(detailVO, packageGroup, "pojo" + File.separator + "dto"); + String voPkg = buildPackagePath(detailVO, packageGroup, "pojo" + File.separator + "vo"); + + model.put("poPkg", poPkg); + model.put("mapperPkg", mapperPkg); + model.put("servicePkg", servicePkg); + model.put("serviceImplPkg", serviceImplPkg); + model.put("controllerPkg", controllerPkg); + model.put("mapperXmlPkg", mapperXmlPkg); + model.put("dtoPkg", dtoPkg); + model.put("voPkg", voPkg); + + model.put("poClassName", detailVO.getBaseInfo().getClassName()); + model.put("mapperClassName", detailVO.getBaseInfo().getClassName() + "Mapper"); + model.put("serviceClassName", detailVO.getBaseInfo().getClassName() + "Service"); + model.put("serviceImplClassName", detailVO.getBaseInfo().getClassName() + "ServiceImpl"); + model.put("controllerClassName", detailVO.getBaseInfo().getClassName() + "Controller"); + model.put("dtoCreateClassName", detailVO.getBaseInfo().getClassName() + "CreateDTO"); + model.put("dtoUpdateClassName", detailVO.getBaseInfo().getClassName() + "UpdateDTO"); + model.put("dtoListClassName", detailVO.getBaseInfo().getClassName() + "ListDTO"); + model.put("dtoImportClassName", detailVO.getBaseInfo().getClassName() + "ImportDTO"); + model.put("voClassName", detailVO.getBaseInfo().getClassName() + "VO"); + + return this; + } + + public CodeModelBuilder builderVue(GeneratorDetailVO detailVO) { + String className = detailVO.getBaseInfo().getClassName(); + String interfacePkg = SEPARATOR + "api" + SEPARATOR + "interface" + SEPARATOR + detailVO.getGeneratorInfo().getModuleName(); + model.put("interfacePkg", interfacePkg); + model.put("interfaceClassName", detailVO.getGeneratorInfo().getBusinessName()); + model.put("interfaceNamespace", detailVO.getBaseInfo().getClassName()); + + String typePkg = SEPARATOR + "api" + SEPARATOR + "types" + SEPARATOR + detailVO.getGeneratorInfo().getModuleName(); + model.put("typePkg", typePkg); + model.put("typeClassName", detailVO.getGeneratorInfo().getBusinessName()); + + String modulesPkg = SEPARATOR + "api" + SEPARATOR + "modules" + SEPARATOR + detailVO.getGeneratorInfo().getModuleName(); + model.put("modulesPkg", modulesPkg); + model.put("modulesClassName", detailVO.getGeneratorInfo().getBusinessName()); + + String indexPkg = SEPARATOR + "views" + SEPARATOR + detailVO.getGeneratorInfo().getModuleName() + SEPARATOR + + detailVO.getGeneratorInfo().getBusinessName(); + model.put("indexPkg", indexPkg); + model.put("indexClassName", "index"); + + String formPkg = indexPkg + SEPARATOR + "components"; + model.put("formPkg", formPkg); + model.put("formClassName", detailVO.getBaseInfo().getClassName() + "Form"); + + model.put("funGetList", "get" + className + "ListApi"); + model.put("funCreate", "create" + className + "Api"); + model.put("funUpdate", "update" + className + "Api"); + model.put("funDetail", "get" + className + "DetailApi"); + model.put("funRemove", "remove" + className + "Api"); + model.put("funImport", "import" + className + "ExcelApi"); + model.put("funExport", "export" + className + "ExcelApi"); + + // permission标识 + String permissionHeader = getRouter(detailVO).replace("-", "."); + String createPermission = permissionHeader + ".create"; + String updatePermission = permissionHeader + ".update"; + String removePermission = permissionHeader + ".remove"; + String importPermission = permissionHeader + ".import"; + String exportPermission = permissionHeader + ".export"; + String listPermission = permissionHeader + ".query_table"; + + model.put("createPermission", createPermission); + model.put("updatePermission", updatePermission); + model.put("removePermission", removePermission); + model.put("importPermission", importPermission); + model.put("exportPermission", exportPermission); + model.put("listPermission", listPermission); + model.put("indexDefineOptionsName", className + "View"); // vue index DefineOptionsName + return this; + } + + private static String buildPackagePath(GeneratorDetailVO detailVO, String packageGroup, String subPackage) { + String basePackage = detailVO.getGeneratorInfo().getPackageName(); + return Paths.get(basePackage, packageGroup, subPackage).toString().replace(File.separator, "."); + + } + + private static String getRouter(GeneratorDetailVO detailVO) { + return detailVO.getBaseInfo().getTableName().replace("_", "-"); + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/GeneratorConstants.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/GeneratorConstants.java new file mode 100644 index 0000000..ca57d05 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/GeneratorConstants.java @@ -0,0 +1,248 @@ +package com.sz.generator.core; + +import java.io.File; + +/** + * 代码生成通用常量 + * + * @author sz + */ +public class GeneratorConstants { + + private GeneratorConstants() { + throw new IllegalStateException("Utility class"); + } + + public static final String PROJECT_JAVA_PREFIX = "src" + File.separator + "main" + File.separator + "java"; + + public static final String PROJECT_XML_PREFIX = "src" + File.separator + "main" + File.separator + "resources"; + + public static final String PROJECT_WEB_PREFIX = "src"; + + /** + * 单表(增删改查) + */ + public static final String TPL_CRUD = "crud"; + + /** + * 不需要插入的字段 + */ + public static final String[] NON_INSERTABLE_COLUMNS = {"create_id", "create_time", "del_flag", "update_id", "update_time", "delete_id", "delete_time", + "dept_scope"}; + + /** + * 页面不需要编辑字段 + */ + public static final String[] NON_EDITABLE_COLUMNS = {"id", "create_id", "create_time", "del_flag", "update_id", "update_time", "delete_id", "delete_time", + "dept_scope"}; + + /** + * 页面不需要显示的列表字段 + */ + public static final String[] NON_DISPLAYABLE_COLUMNS = {"del_flag", "delete_id", "delete_time", "dept_scope"}; + + /** + * 页面不需要导入的列表字段 + */ + public static final String[] NON_DISPLAYABLE_IMPORT_COLUMNS = {"create_id", "create_time", "del_flag", "update_id", "update_time", "delete_id", + "delete_time", "attachments", "url", "dept_scope"}; + + /** + * 页面不需要导出的列表字段 + */ + public static final String[] NON_EXPORTABLE_COLUMNS = {"del_flag", "delete_id", "delete_time", "attachments", "url", "dept_scope"}; + + /** + * 页面不需要查询字段 + */ + public static final String[] NON_QUERYABLE_COLUMNS = {"create_id", "create_time", "del_flag", "update_id", "update_time", "remark", "delete_id", + "delete_time", "attachments", "url", "dept_scope"}; + + /** + * 根据insert事件自动填充的字段 + */ + public static final String[] AUTO_FILL_ON_INSERT_COLUMNS = {"create_id", "create_time"}; + + /** + * 根据update事件自动填充的字段 + */ + public static final String[] AUTO_FILL_ON_UPDATE_COLUMNS = {"update_id", "update_time"}; + + /** + * 需要自动导入Options字典的字段 + */ + public static final String[] AUTO_FILL_OPTIONS_COLUMNS = {"create_id", "update_id"}; + + /** + * 自动上传文件字段 + */ + public static final String[] AUTO_FILE_UPLOAD_COLUMNS = {"attachments", "url"}; + + /** + * 文本框 + */ + public static final String HTML_INPUT = "input"; + + public static final String HTML_INPUT_NUMBER = "input-number"; + + /** + * 文本域 + */ + public static final String HTML_TEXTAREA = "textarea"; + + /** + * 下拉框 + */ + public static final String HTML_SELECT = "select"; + + /** + * 单选框 + */ + public static final String HTML_RADIO = "radio"; + + /** + * 复选框 + */ + public static final String HTML_CHECKBOX = "checkbox"; + + /** + * 日期控件 + */ + public static final String HTML_DATETIME = "datetime"; + + public static final String HTML_DATE = "date"; + + public static final String HTML_TIME = "time"; + + /** + * 图片上传控件 + */ + public static final String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** + * 文件上传控件 + */ + public static final String HTML_FILE_UPLOAD = "fileUpload"; + + /** + * 富文本控件 + */ + public static final String HTML_EDITOR = "jodit-editor"; + + /** + * 日期范围控件 + */ + public static final String HTML_DATE_PICKER = "date-picker"; + + /** + * 时间范围控件 + */ + public static final String HTML_TIME_PICKER = "time-picker"; + + /** + * 字符串类型 + */ + public static final String TYPE_STRING = "String"; + + /** + * 整型 + */ + public static final String TYPE_INTEGER = "Integer"; + + /** + * ts字符型 + */ + public static final String TS_TYPE_STRING = "string"; + + /** + * ts数字型 + */ + public static final String TS_TYPE_NUMBER = "number"; + + /** + * 长整型 + */ + public static final String TYPE_LONG = "Long"; + + /** + * List集合, 文件附件 + */ + public static final String TYPE_LIST_UPLOADRESULT = "List"; + + /** + * 浮点型 + */ + public static final String TYPE_DOUBLE = "Double"; + + /** + * 高精度计算类型 + */ + public static final String TYPE_BIG_DECIMAL = "BigDecimal"; + + /** + * 时间类型 + */ + public static final String TYPE_DATE = "Date"; + + /** + * 时间类型 + */ + public static final String TYPE_LOCAL_DATETIME = "LocalDateTime"; + + /** + * 时间类型 + */ + public static final String TYPE_LOCAL_DATE = "LocalDate"; + + /** + * 时间类型 + */ + public static final String TYPE_LOCALTIME = "LocalTime"; + + /** + * 模糊查询 + */ + public static final String QUERY_LIKE = "LIKE"; + + /** + * 相等查询 + */ + public static final String QUERY_EQ = "EQ"; + + /** + * 不等于 + */ + public static final String QUERY_NEQ = "NEQ"; + + /** + * 大于 + */ + public static final String QUERY_GT = "GT"; + + /** + * 小于 + */ + public static final String QUERY_LT = "LT"; + + /** + * 范围 + */ + public static final String QUERY_BETWEEN = "BETWEEN"; + + /** + * 大于等于 + */ + public static final String QUERY_GTE = "GTE"; + + /** + * 小于等于 + */ + public static final String QUERY_LTE = "LTE"; + + /** + * 需要 + */ + public static final String REQUIRE = "1"; + + public static final String NOT_REQUIRE = "0"; +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ControllerCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ControllerCodeBuilder.java new file mode 100644 index 0000000..05b5e17 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ControllerCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class ControllerCodeBuilder extends AbstractCodeGenerationTemplate { + + public ControllerCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "controller.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("controllerClassName").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String alias() { + return "controller"; + } + + @Override + protected String language() { + return "java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("controllerPkg").toString(); + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoCreateCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoCreateCodeBuilder.java new file mode 100644 index 0000000..cf4e128 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoCreateCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class DtoCreateCodeBuilder extends AbstractCodeGenerationTemplate { + + public DtoCreateCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "dtoCreate.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("dtoCreateClassName").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("dtoPkg").toString(); + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "dtoCreate"; + } + + @Override + protected String language() { + return "java"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoImportCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoImportCodeBuilder.java new file mode 100644 index 0000000..c114f90 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoImportCodeBuilder.java @@ -0,0 +1,60 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class DtoImportCodeBuilder extends AbstractCodeGenerationTemplate { + + public DtoImportCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "dtoImport.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("dtoImportClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("dtoPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "dtoImport"; + } + + @Override + protected String language() { + return "java"; + } +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoListCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoListCodeBuilder.java new file mode 100644 index 0000000..15058a2 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoListCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class DtoListCodeBuilder extends AbstractCodeGenerationTemplate { + + public DtoListCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "dtoList.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("dtoListClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("dtoPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "dtoList"; + } + + @Override + protected String language() { + return "java"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoUpdateCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoUpdateCodeBuilder.java new file mode 100644 index 0000000..865888a --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/DtoUpdateCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class DtoUpdateCodeBuilder extends AbstractCodeGenerationTemplate { + + public DtoUpdateCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "dtoUpdate.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("dtoUpdateClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("dtoPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "dtoUpdate"; + } + + @Override + protected String language() { + return "java"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/MapperCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/MapperCodeBuilder.java new file mode 100644 index 0000000..4ade84d --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/MapperCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class MapperCodeBuilder extends AbstractCodeGenerationTemplate { + + public MapperCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "mapper.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("mapperClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("mapperPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "mapper"; + } + + @Override + protected String language() { + return "java"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/MapperXmlCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/MapperXmlCodeBuilder.java new file mode 100644 index 0000000..e1c450d --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/MapperXmlCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class MapperXmlCodeBuilder extends AbstractCodeGenerationTemplate { + + public MapperXmlCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "mapper.xml.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("mapperClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("mapperXmlPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_XML_PREFIX; + } + + @Override + protected String getExtension() { + return ".xml"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "mapperXml"; + } + + @Override + protected String language() { + return "java"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/PoCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/PoCodeBuilder.java new file mode 100644 index 0000000..e573ec6 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/PoCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class PoCodeBuilder extends AbstractCodeGenerationTemplate { + + public PoCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "po.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("poClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("poPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "po"; + } + + @Override + protected String language() { + return "java"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ServiceCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ServiceCodeBuilder.java new file mode 100644 index 0000000..398db8f --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ServiceCodeBuilder.java @@ -0,0 +1,60 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class ServiceCodeBuilder extends AbstractCodeGenerationTemplate { + + public ServiceCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "service.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("serviceClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("servicePkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "service"; + } + + @Override + protected String language() { + return "java"; + } +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ServiceImplCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ServiceImplCodeBuilder.java new file mode 100644 index 0000000..32f670a --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/ServiceImplCodeBuilder.java @@ -0,0 +1,60 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class ServiceImplCodeBuilder extends AbstractCodeGenerationTemplate { + + public ServiceImplCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "serviceImpl.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("serviceImplClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("serviceImplPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "serviceImpl"; + } + + @Override + protected String language() { + return "java"; + } +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/VoCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/VoCodeBuilder.java new file mode 100644 index 0000000..714945d --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/java/VoCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.java; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class VoCodeBuilder extends AbstractCodeGenerationTemplate { + + public VoCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "api" + File.separator + "vo.java.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("voClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("voPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_JAVA_PREFIX; + } + + @Override + protected String getExtension() { + return ".java"; + } + + @Override + protected String getZipParentPackage() { + return "java"; + } + + @Override + protected String alias() { + return "vo"; + } + + @Override + protected String language() { + return "java"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/sql/MenuSqlCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/sql/MenuSqlCodeBuilder.java new file mode 100644 index 0000000..fe88b84 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/sql/MenuSqlCodeBuilder.java @@ -0,0 +1,56 @@ +package com.sz.generator.core.builder.sql; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +public class MenuSqlCodeBuilder extends AbstractCodeGenerationTemplate { + + public MenuSqlCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "sql" + File.separator + "menuInit.sql.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return "menuInit"; + } + + @Override + protected String getProjectPrefix() { + return null; + } + + @Override + protected String getExtension() { + return ".sql"; + } + + @Override + protected String alias() { + return "sql"; + } + + @Override + protected String language() { + return "sql"; + } + + @Override + protected String getZipParentPackage() { + return "sql"; + } + + @Override + protected String getOutputPackage(Map model) { + return ""; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/FormCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/FormCodeBuilder.java new file mode 100644 index 0000000..a2c1b5a --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/FormCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.vue; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class FormCodeBuilder extends AbstractCodeGenerationTemplate { + + public FormCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "vue" + File.separator + "componentForm.vue.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("formClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("formPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_WEB_PREFIX; + } + + @Override + protected String getExtension() { + return ".vue"; + } + + @Override + protected String getZipParentPackage() { + return "vue"; + } + + @Override + protected String alias() { + return "componentForm.vue"; + } + + @Override + protected String language() { + return "html"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/IndexCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/IndexCodeBuilder.java new file mode 100644 index 0000000..4800a5c --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/IndexCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.vue; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +@Deprecated +public class IndexCodeBuilder extends AbstractCodeGenerationTemplate { + + public IndexCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "vue" + File.separator + "index.vue.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("indexClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("indexPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_WEB_PREFIX; + } + + @Override + protected String getExtension() { + return ".vue"; + } + + @Override + protected String getZipParentPackage() { + return "vue"; + } + + @Override + protected String alias() { + return "index.vue"; + } + + @Override + protected String language() { + return "html"; + } +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/InterfaceCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/InterfaceCodeBuilder.java new file mode 100644 index 0000000..5d11c77 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/InterfaceCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.vue; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class InterfaceCodeBuilder extends AbstractCodeGenerationTemplate { + + public InterfaceCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "vue" + File.separator + "interface.ts.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("interfaceClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("interfacePkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_WEB_PREFIX; + } + + @Override + protected String getExtension() { + return ".ts"; + } + + @Override + protected String getZipParentPackage() { + return "vue"; + } + + @Override + protected String alias() { + return "interface.ts"; + } + + @Override + protected String language() { + return "ts"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/ModulesCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/ModulesCodeBuilder.java new file mode 100644 index 0000000..5e7a81e --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/ModulesCodeBuilder.java @@ -0,0 +1,60 @@ +package com.sz.generator.core.builder.vue; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class ModulesCodeBuilder extends AbstractCodeGenerationTemplate { + + public ModulesCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "vue" + File.separator + "modules.ts.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("modulesClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("modulesPkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_WEB_PREFIX; + } + + @Override + protected String getExtension() { + return ".ts"; + } + + @Override + protected String getZipParentPackage() { + return "vue"; + } + + @Override + protected String alias() { + return "module.ts"; + } + + @Override + protected String language() { + return "ts"; + } +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/TypeCodeBuilder.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/TypeCodeBuilder.java new file mode 100644 index 0000000..2a31317 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/builder/vue/TypeCodeBuilder.java @@ -0,0 +1,61 @@ +package com.sz.generator.core.builder.vue; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.File; +import java.util.Map; + +/** + * @author sz + * @since 2024/1/16 8:02 + */ +public class TypeCodeBuilder extends AbstractCodeGenerationTemplate { + + public TypeCodeBuilder(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, Map model) { + super(configurer, rootPath, detailVO, model); + } + + @Override + protected String getTemplateFileName() { + return File.separator + "vue" + File.separator + "type.ts.ftl"; + } + + @Override + protected String getOutputFileName(Map model) { + return model.get("typeClassName").toString(); + } + + @Override + protected String getOutputPackage(Map model) { + return model.get("typePkg").toString(); + } + + @Override + protected String getProjectPrefix() { + return GeneratorConstants.PROJECT_WEB_PREFIX; + } + + @Override + protected String getExtension() { + return ".ts"; + } + + @Override + protected String getZipParentPackage() { + return "vue"; + } + + @Override + protected String alias() { + return "type.ts"; + } + + @Override + protected String language() { + return "ts"; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/util/BuildTemplateUtils.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/util/BuildTemplateUtils.java new file mode 100644 index 0000000..2f37435 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/util/BuildTemplateUtils.java @@ -0,0 +1,88 @@ +package com.sz.generator.core.util; + +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.builder.java.*; +import com.sz.generator.core.builder.vue.*; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.util.*; + +/** + * @author sz + * @since 2023/12/18 10:21 + */ +public class BuildTemplateUtils { + + private BuildTemplateUtils() { + throw new IllegalStateException("Utility class"); + } + + /** + * 使用 Java 模板生成内容。 + * + * 该方法根据提供的模板配置、根路径和详细信息对象,生成指定的模型内容。 + * + * @param configurer + * 模板配置对象,用于设置模板生成的参数 + * @param rootPath + * 模板的根路径,指定模板文件的存放位置 + * @param detailVO + * 包含详细信息的数据对象,用于填充模板 + * @param model + * 模板中使用的数据模型 + * @return 生成的模板内容,通常为字符串或其他格式 + */ + + public static List getApiTemplates(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, + Map model) { + boolean hasImport = ("1").equals(detailVO.getGeneratorInfo().getHasImport()); + List list = new ArrayList<>(Arrays.asList(new ControllerCodeBuilder(configurer, rootPath, detailVO, model), + new ServiceImplCodeBuilder(configurer, rootPath, detailVO, model), new ServiceCodeBuilder(configurer, rootPath, detailVO, model), + new MapperCodeBuilder(configurer, rootPath, detailVO, model), new MapperXmlCodeBuilder(configurer, rootPath, detailVO, model), + new DtoCreateCodeBuilder(configurer, rootPath, detailVO, model), new DtoListCodeBuilder(configurer, rootPath, detailVO, model), + new DtoUpdateCodeBuilder(configurer, rootPath, detailVO, model))); + if (hasImport) + list.add(new DtoImportCodeBuilder(configurer, rootPath, detailVO, model)); + list.add(new PoCodeBuilder(configurer, rootPath, detailVO, model)); + list.add(new VoCodeBuilder(configurer, rootPath, detailVO, model)); + + return switch (detailVO.getGeneratorInfo().getGenerateType()) { + case "all", "server" -> list; + case "service" -> Arrays.asList(new ServiceCodeBuilder(configurer, rootPath, detailVO, model), + new ServiceImplCodeBuilder(configurer, rootPath, detailVO, model), new MapperCodeBuilder(configurer, rootPath, detailVO, model), + new MapperXmlCodeBuilder(configurer, rootPath, detailVO, model), new PoCodeBuilder(configurer, rootPath, detailVO, model)); + case "db" -> Arrays.asList(new PoCodeBuilder(configurer, rootPath, detailVO, model), new MapperCodeBuilder(configurer, rootPath, detailVO, model), + new MapperXmlCodeBuilder(configurer, rootPath, detailVO, model)); + default -> Collections.emptyList(); + }; + } + + /** + * 使用 Web 模板生成内容。 + * + * 该方法根据提供的模板配置、根路径和详细信息对象,生成指定的 Web 模板内容。 + * + * @param configurer + * 模板配置对象,用于设置模板生成的参数 + * @param rootPath + * 模板的根路径,指定模板文件的存放位置 + * @param detailVO + * 包含详细信息的数据对象,用于填充模板 + * @param model + * 模板中使用的数据模型 + * @return 生成的 Web 模板内容,通常为 HTML 字符串或其他格式 + */ + + public static List getWebTemplates(FreeMarkerConfigurer configurer, String rootPath, GeneratorDetailVO detailVO, + Map model) { + List list = new ArrayList<>( + Arrays.asList(new IndexCodeBuilder(configurer, rootPath, detailVO, model), new FormCodeBuilder(configurer, rootPath, detailVO, model), + new ModulesCodeBuilder(configurer, rootPath, detailVO, model), new TypeCodeBuilder(configurer, rootPath, detailVO, model))); + return switch (detailVO.getGeneratorInfo().getGenerateType()) { + case "all" -> list; + default -> Collections.emptyList(); + }; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/util/GeneratorUtils.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/util/GeneratorUtils.java new file mode 100644 index 0000000..f91d38e --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/core/util/GeneratorUtils.java @@ -0,0 +1,419 @@ +package com.sz.generator.core.util; + +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.core.util.Utils; +import com.sz.generator.core.GeneratorConstants; +import com.sz.generator.pojo.po.GeneratorTable; +import com.sz.generator.pojo.po.GeneratorTableColumn; +import com.sz.generator.pojo.property.GeneratorProperties; +import com.sz.generator.pojo.result.TableColumResult; +import com.sz.generator.pojo.result.TableResult; +import com.sz.core.util.StringUtils; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.apache.commons.lang3.StringUtils.*; + +/** + * @author sz + * @since 2023/11/28 16:06 + */ +public class GeneratorUtils { + + private GeneratorUtils() { + throw new IllegalStateException("GeneratorUtils class Illegal"); + } + + public static GeneratorTable initGeneratorTable(TableResult table) { + return initGeneratorTable(table, false, null); + } + + public static GeneratorTable initGeneratorTable(TableResult table, boolean ignoreTablePrefix, String[] prefixes) { + + GeneratorProperties prop = SpringApplicationContextUtils.getInstance().getBean(GeneratorProperties.class); + String author = prop.getGlobal().getAuthor(); + String packages = prop.getGlobal().getPackages(); + + String tableName = table.getTableName(); + // 如果需要将表前缀去掉 + if (ignoreTablePrefix && prefixes != null) { + for (String prefix : prefixes) { + if (tableName.startsWith(prefix)) { + tableName = tableName.replaceFirst(prefix, ""); + break; + } + } + } + + GeneratorTable generatorTable = new GeneratorTable(); + generatorTable.setTableName(table.getTableName()); + generatorTable.setTableComment(table.getTableComment()); + generatorTable.setPackageName(packages); + generatorTable.setModuleName(tableName.replace("_", "")); + generatorTable.setClassName(GeneratorUtils.toUpCase(tableName)); + generatorTable.setCamelClassName(StringUtils.toCamelCase(tableName)); + generatorTable.setTplCategory(GeneratorConstants.TPL_CRUD); + generatorTable.setBusinessName(GeneratorUtils.toCamelCase(tableName)); + generatorTable.setFunctionName(table.getTableComment()); + generatorTable.setFunctionAuthor(author); + generatorTable.setType("0"); + generatorTable.setPath("/"); + generatorTable.setParentMenuId("0"); // 默认父级菜单id设置为根目录 + + return generatorTable; + } + + public static GeneratorTableColumn initColumnField(TableColumResult column, Long tableId, int i) { + GeneratorTableColumn tableColumn = new GeneratorTableColumn(); + String dataType = getDbType(column.getColumnType()); + String columnName = column.getColumnName(); + tableColumn.setTableId(tableId); + tableColumn.setColumnName(columnName); + tableColumn.setColumnComment(column.getColumnComment()); + tableColumn.setColumnType(column.getColumnType()); + tableColumn.setJavaType(GeneratorConstants.TYPE_STRING); + tableColumn.setTsType(GeneratorConstants.TS_TYPE_STRING); + tableColumn.setJavaField(StringUtils.toCamelCase(columnName)); + tableColumn.setUpCamelField(GeneratorUtils.toUpCase(columnName)); + tableColumn.setIsPk(column.getIsPk()); + tableColumn.setIsIncrement(column.getIsIncrement()); + tableColumn.setQueryType(GeneratorConstants.QUERY_EQ); + tableColumn.setSort(i); + tableColumn.setDictType(""); + setRequiredValue(column, tableColumn); + setHtmlAndJavaType(dataType, column.getColumnType(), tableColumn); + setColumnAttributes(columnName, tableColumn); + + // 如果是主键并且是int行,将java类型设置为Long + if (!isNotPrimaryKey(tableColumn.getIsPk()) && (("int").equals(tableColumn.getColumnType()) || ("bigint").equals(tableColumn.getColumnType()))) { + tableColumn.setJavaType(GeneratorConstants.TYPE_LONG); + } + // 将bigint类型映射成long + if (("bigint").equals(tableColumn.getColumnType())) { + tableColumn.setJavaType(GeneratorConstants.TYPE_LONG); + } + // 【约定】: 使用create_id, update_id, delete_id change更新时,强制类型Long + if (("create_id").equals(columnName) || ("update_id").equals(columnName) || ("delete_id").equals(columnName)) { + tableColumn.setJavaType(GeneratorConstants.TYPE_LONG); + } + // 【约定】: 使用del_flag 作为逻辑删除标识字段 + if ("del_flag".equals(columnName)) { + tableColumn.setIsLogicDel(GeneratorConstants.REQUIRE); + } + + // 【约定】: 使用attachments 或 url 作为 附件字段,数据库类型json, java 类型使用List + if ("attachments".equals(columnName) || "url".equals(columnName)) { + tableColumn.setJavaType(GeneratorConstants.TYPE_LIST_UPLOADRESULT); + } + + if (tableColumn.getHtmlType() == null) { + tableColumn.setHtmlType(""); + } + return tableColumn; + } + + /** + * 校验数组是否包含指定值 + * + * @param arr + * 数组 + * @param targetValue + * 值 + * @return 是否包含 + */ + public static boolean arraysContains(String[] arr, String targetValue) { + return Arrays.asList(arr).contains(targetValue); + } + + /** + * 获取数据库类型字段 + * + * @param columnType + * 列类型 + * @return 截取后的列类型 + */ + public static String getDbType(String columnType) { + if (indexOf(columnType, "(") > 0) { + return substringBefore(columnType, "("); + } else { + return columnType; + } + } + + /** + * 获取字段长度 + * + * @param columnType + * 列类型 + * @return 截取后的列类型 + */ + public static Integer getColumnLength(String columnType) { + if (indexOf(columnType, "(") > 0) { + String length = substringBetween(columnType, "(", ")"); + return Integer.valueOf(length); + } else { + return 0; + } + } + + public static String toUpCase(String input) { + StringBuilder result = new StringBuilder(); + // 标记是否要将下一个字符转为大写 + boolean capitalizeNext = true; + for (char c : input.toCharArray()) { + if (Character.isLetterOrDigit(c)) { + if (capitalizeNext) { + result.append(Character.toUpperCase(c)); + capitalizeNext = false; + } else { + result.append(Character.toLowerCase(c)); + } + } else { + // 非字母数字字符后面的字母需要大写 + capitalizeNext = true; + } + } + return result.toString(); + } + + public static String toCamelCase(String input) { + StringBuilder result = new StringBuilder(); + // 标记是否要将下一个字符转为大写 + boolean capitalizeNext = false; + for (char c : input.toCharArray()) { + if (Character.isLetterOrDigit(c)) { + if (capitalizeNext) { + result.append(Character.toUpperCase(c)); + capitalizeNext = false; + } else { + result.append(Character.toLowerCase(c)); + } + } else { + // 非字母数字字符后面的字母需要大写 + capitalizeNext = true; + } + } + return result.toString(); + } + + private static void setRequiredValue(TableColumResult column, GeneratorTableColumn tableColumn) { + if (Utils.isNotNull(column.getIsRequired())) { + tableColumn.setIsRequired(column.getIsRequired()); + } else { + tableColumn.setIsRequired("0"); + } + } + + private static void setHtmlAndJavaType(String dataType, String columnType, GeneratorTableColumn tableColumn) { + switch (dataType.toUpperCase()) { + case "VARCHAR" : + case "CHAR" : + case "NVARCHAR" : + case "VARCHAR2" : + case "TEXT" : + case "TINYTEXT" : + case "MEDIUMTEXT" : + case "LONGTEXT" : + setStringTypeAttributes(columnType, tableColumn); + tableColumn.setSearchType("input"); + break; + case "TIME" : + tableColumn.setJavaType(GeneratorConstants.TYPE_LOCALTIME); + tableColumn.setHtmlType(GeneratorConstants.HTML_TIME); + tableColumn.setJavaTypePackage("java.time.LocalTime"); + tableColumn.setSearchType(GeneratorConstants.HTML_TIME_PICKER); + tableColumn.setQueryType(GeneratorConstants.QUERY_BETWEEN); + break; + case "DATE" : + tableColumn.setJavaType(GeneratorConstants.TYPE_LOCAL_DATE); + tableColumn.setHtmlType(GeneratorConstants.HTML_DATE); + tableColumn.setJavaTypePackage("java.time.LocalDate"); + tableColumn.setSearchType(GeneratorConstants.HTML_DATE_PICKER); + tableColumn.setQueryType(GeneratorConstants.QUERY_BETWEEN); + break; + case "TIMESTAMP" : + case "DATETIME" : + tableColumn.setJavaType(GeneratorConstants.TYPE_LOCAL_DATETIME); + tableColumn.setHtmlType(GeneratorConstants.HTML_DATETIME); + tableColumn.setJavaTypePackage("java.time.LocalDateTime"); + tableColumn.setSearchType(GeneratorConstants.HTML_DATE_PICKER); + tableColumn.setQueryType(GeneratorConstants.QUERY_BETWEEN); + break; + case "TINYINT" : + case "SMALLINT" : + case "MEDIUMINT" : + case "INT" : + case "NUMBER" : + case "INTEGER" : + case "BIT" : + case "BIGINT" : + case "FLOAT" : + case "DOUBLE" : + case "DECIMAL" : + tableColumn.setTsType(GeneratorConstants.TS_TYPE_NUMBER); + setNumberTypeAttributes(columnType, tableColumn); + break; + default : + // Handle other data types as needed + } + } + + private static void setStringTypeAttributes(String columnType, GeneratorTableColumn tableColumn) { + Integer columnLength = getColumnLength(columnType); + String htmlType = columnLength >= 500 ? GeneratorConstants.HTML_TEXTAREA : GeneratorConstants.HTML_INPUT; + tableColumn.setHtmlType(htmlType); + } + + private static void setNumberTypeAttributes(String columnType, GeneratorTableColumn tableColumn) { + String[] str = split(substringBetween(columnType, "(", ")"), ","); + if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) { + tableColumn.setJavaType(GeneratorConstants.TYPE_BIG_DECIMAL); + tableColumn.setJavaTypePackage("java.math.BigDecimal"); + } else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) { + tableColumn.setJavaType(GeneratorConstants.TYPE_INTEGER); + } else { + tableColumn.setJavaType(GeneratorConstants.TYPE_INTEGER); + } + tableColumn.setHtmlType(GeneratorConstants.HTML_INPUT_NUMBER); + } + + private static void setColumnAttributes(String columnName, GeneratorTableColumn tableColumn) { + boolean notPk = isNotPrimaryKey(tableColumn.getIsPk()); + setInsertAttribute(notPk, columnName, tableColumn); + setEditAttribute(notPk, columnName, tableColumn); + setListAttribute(notPk, columnName, tableColumn); + setQueryAttribute(notPk, columnName, tableColumn); + setQueryType(columnName, tableColumn); + setAutofillType(columnName, tableColumn); + setHtmlType(columnName, tableColumn); + setFillOptions(columnName, tableColumn); + setFileUploadOptions(columnName, tableColumn); + setJoditEditorOptions(columnName, tableColumn); + setImportAttribute(notPk, columnName, tableColumn); + setExportAttribute(notPk, columnName, tableColumn); + } + + private static void setQueryType(String columnName, GeneratorTableColumn tableColumn) { + if (endsWithIgnoreCase(columnName, "name")) { + tableColumn.setQueryType(GeneratorConstants.QUERY_LIKE); + } + } + + private static void setHtmlType(String columnName, GeneratorTableColumn tableColumn) { + String lowerCaseColumnName = columnName.toLowerCase(); + tableColumn.setSearchType("input"); + if (lowerCaseColumnName.contains("status")) { + tableColumn.setHtmlType(GeneratorConstants.HTML_RADIO); + tableColumn.setSearchType("select"); + } else if (lowerCaseColumnName.contains("type") || lowerCaseColumnName.contains("sex") || lowerCaseColumnName.contains("_cd")) { + tableColumn.setHtmlType(GeneratorConstants.HTML_SELECT); + tableColumn.setSearchType("select"); + } else if (lowerCaseColumnName.contains("image")) { + tableColumn.setHtmlType(GeneratorConstants.HTML_IMAGE_UPLOAD); + } else if (lowerCaseColumnName.contains("file")) { + tableColumn.setHtmlType(GeneratorConstants.HTML_FILE_UPLOAD); + } else if (lowerCaseColumnName.contains("content")) { + tableColumn.setHtmlType(GeneratorConstants.HTML_EDITOR); + } else if (lowerCaseColumnName.contains("time")) { + tableColumn.setSearchType("date-picker"); + } + } + + private static void setListAttribute(boolean notPk, String columnName, GeneratorTableColumn tableColumn) { + if (!arraysContains(GeneratorConstants.NON_DISPLAYABLE_COLUMNS, columnName) && notPk) { + tableColumn.setIsList(GeneratorConstants.REQUIRE); + } + if (!notPk) { + tableColumn.setIsList(GeneratorConstants.REQUIRE); + } + } + + private static void setImportAttribute(boolean notPk, String columnName, GeneratorTableColumn tableColumn) { + String htmlType = tableColumn.getHtmlType(); + if (!arraysContains(GeneratorConstants.NON_DISPLAYABLE_IMPORT_COLUMNS, columnName) && notPk && !GeneratorConstants.HTML_EDITOR.equals(htmlType)) { + tableColumn.setIsImport(GeneratorConstants.REQUIRE); + } + } + + private static void setExportAttribute(boolean notPk, String columnName, GeneratorTableColumn tableColumn) { + String htmlType = tableColumn.getHtmlType(); + if (!arraysContains(GeneratorConstants.NON_EXPORTABLE_COLUMNS, columnName) && notPk && !GeneratorConstants.HTML_EDITOR.equals(htmlType)) { + tableColumn.setIsExport(GeneratorConstants.REQUIRE); + } + } + + private static void setQueryAttribute(boolean notPk, String columnName, GeneratorTableColumn tableColumn) { + if (!arraysContains(GeneratorConstants.NON_QUERYABLE_COLUMNS, columnName) && notPk) { + tableColumn.setIsQuery(GeneratorConstants.REQUIRE); + } + } + + public static boolean isNotPrimaryKey(String isPk) { + return !"1".equals(isPk); + } + + private static void setEditAttribute(boolean notPk, String columnName, GeneratorTableColumn tableColumn) { + if (!arraysContains(GeneratorConstants.NON_EDITABLE_COLUMNS, columnName) && notPk) { + tableColumn.setIsEdit(GeneratorConstants.REQUIRE); + } + if (!notPk) { + tableColumn.setIsEdit(GeneratorConstants.REQUIRE); + } + } + + private static void setInsertAttribute(boolean notPk, String columnName, GeneratorTableColumn tableColumn) { + if (!arraysContains(GeneratorConstants.NON_INSERTABLE_COLUMNS, columnName) && notPk) { + tableColumn.setIsInsert(GeneratorConstants.REQUIRE); + } + } + + private static void setAutofillType(String columnName, GeneratorTableColumn tableColumn) { + if (arraysContains(GeneratorConstants.AUTO_FILL_ON_INSERT_COLUMNS, columnName)) { + tableColumn.setIsAutofill(GeneratorConstants.REQUIRE); + tableColumn.setAutofillType("FieldFill.INSERT"); + } + if (arraysContains(GeneratorConstants.AUTO_FILL_ON_UPDATE_COLUMNS, columnName)) { + tableColumn.setIsAutofill(GeneratorConstants.REQUIRE); + tableColumn.setAutofillType("FieldFill.UPDATE"); + } + } + + private static void setFillOptions(String columnName, GeneratorTableColumn tableColumn) { + if (arraysContains(GeneratorConstants.AUTO_FILL_OPTIONS_COLUMNS, columnName)) { + tableColumn.setDictType("dynamic_user_options"); // 设置[动态字典]用户信息 + tableColumn.setDictShowWay("0"); // 设置字典显示方式:唯一标识 + } + } + + private static void setFileUploadOptions(String columnName, GeneratorTableColumn tableColumn) { + String javaType = tableColumn.getJavaType(); + if (arraysContains(GeneratorConstants.AUTO_FILE_UPLOAD_COLUMNS, columnName) || GeneratorConstants.TYPE_LIST_UPLOADRESULT.equals(javaType)) { + tableColumn.setJavaType(GeneratorConstants.TYPE_LIST_UPLOADRESULT); + tableColumn.setJavaTypePackage( + "com.mybatisflex.core.handler.JacksonTypeHandler,com.sz.core.common.entity.UploadResult,java.util.List,com.mybatisflex.annotation.Column"); + tableColumn.setHtmlType(GeneratorConstants.HTML_FILE_UPLOAD); + Map options = tableColumn.getOptions() != null ? tableColumn.getOptions() : HashMap.newHashMap(8); + options.put("upload-files.dir", "tmp"); // 多文件上传组件:文件上传目录 + options.put("upload-files.accept", ""); // 多文件上传组件:允许上传的文件类型, doc,pdf,jpg等,空表示不限制 + options.put("upload-files.limit", 5); // 多文件上传组件:最多上传5个文件 + options.put("upload-files.fileSize", 3); // 多文件上传组件:单个文件最大3MB + + options.put("file-download-list.align", "left"); // 列表文件回显组件:对齐方式left/center/right + options.put("file-download-list.maxRows", 3); // 列表文件回显组件:表格内最大显示行数,超出则折叠显示 + tableColumn.setOptions(options); + } + } + + private static void setJoditEditorOptions(String columnName, GeneratorTableColumn tableColumn) { + String htmlType = tableColumn.getHtmlType(); + if (GeneratorConstants.HTML_EDITOR.equals(htmlType)) { + Map options = tableColumn.getOptions() != null ? tableColumn.getOptions() : HashMap.newHashMap(8); + options.put("uploader.dir", "editor"); // 富文本编辑器:文件上传目录 + options.put("height", "400px"); // 富文本编辑器:编辑器高度 + tableColumn.setOptions(options); + } + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/mapper/GeneratorTableColumnMapper.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/mapper/GeneratorTableColumnMapper.java new file mode 100644 index 0000000..f8d83c7 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/mapper/GeneratorTableColumnMapper.java @@ -0,0 +1,21 @@ +package com.sz.generator.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.generator.pojo.po.GeneratorTableColumn; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 代码生成业务表字段 Mapper 接口 + *

+ * + * @author sz + * @since 2023-11-27 + */ +public interface GeneratorTableColumnMapper extends BaseMapper { + + List queryAllByTableName(@Param("tableNames") List tableNames); + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/mapper/GeneratorTableMapper.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/mapper/GeneratorTableMapper.java new file mode 100644 index 0000000..aa284f2 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/mapper/GeneratorTableMapper.java @@ -0,0 +1,88 @@ +package com.sz.generator.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.generator.pojo.dto.DbTableQueryDTO; +import com.sz.generator.pojo.dto.MenuCreateDTO; +import com.sz.generator.pojo.po.GeneratorTable; +import com.sz.generator.pojo.result.SysMenuResult; +import com.sz.generator.pojo.result.TableColumResult; +import com.sz.generator.pojo.result.TableResult; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 代码生成业务表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-11-27 + */ +public interface GeneratorTableMapper extends BaseMapper { + + List selectDbTableListByNames(@Param("tableNames") List tableNames); + + /** + * 查询指定table的column列 + * + * @param tableName + * 表名 + * @return 列信息 + */ + List selectDbTableColumnsByName(@Param("tableName") String tableName); + + /** + * 根据tableName清空表记录 + * + * @param tableNames + * 表名集合 + */ + void cleanTableRecordByTableName(@Param("tableNames") List tableNames); + + /** + * 根据tableName清空字段表 + * + * @param tableNames + * 表名集合 + */ + void cleanTableColumnByTableName(@Param("tableNames") List tableNames); + + /** + * 查询未导入的表 + * + * @return 表信息 + */ + List selectDbTableNotInImport(@Param("queryDTO") DbTableQueryDTO queryDTO); + + /** + * 查询已经导入的表 + * + * @param queryDTO + * 查询条件 + * @return 表信息 + */ + List selectDbTableByImport(@Param("queryDTO") DbTableQueryDTO queryDTO); + + /** + * 根据pid 查询上级菜单 + * + * @param pid + * 上级菜单id + * @return 菜单信息 + */ + SysMenuResult selectSysMenuByPid(@Param("pid") String pid); + + void insertMenu(@Param("createDTO") MenuCreateDTO createDTO); + + int selectMenuCount(@Param("pid") String pid); + + void syncTreeHasChildren(); + + void syncTreeDeep(); + + int countMenu(@Param("name") String name, @Param("path") String path, @Param("component") String component, @Param("pid") String pid); + + int countMenuBtn(@Param("permissions") String permissions); + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/DbTableQueryDTO.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/DbTableQueryDTO.java new file mode 100644 index 0000000..c6ee8c3 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/DbTableQueryDTO.java @@ -0,0 +1,24 @@ +package com.sz.generator.pojo.dto; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2023/11/29 14:17 + */ +@Schema(description = "导入表查询") +@Data +public class DbTableQueryDTO extends PageQuery { + + @Schema(description = "表名称") + private String tableName; + + @Schema(description = "表描述") + private String tableComment; + + @Schema(description = "是否过滤系统表") + private boolean filterSys; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/ImportTableDTO.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/ImportTableDTO.java new file mode 100644 index 0000000..ddb25b4 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/ImportTableDTO.java @@ -0,0 +1,19 @@ +package com.sz.generator.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2023/11/27 11:09 + */ +@Data +@Schema(description = "导入表") +public class ImportTableDTO { + + @Schema(description = "表名") + private List tableName; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/MenuCreateDTO.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/MenuCreateDTO.java new file mode 100644 index 0000000..1816cfa --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/MenuCreateDTO.java @@ -0,0 +1,38 @@ +package com.sz.generator.pojo.dto; + +import lombok.Data; + +/** + * @author sz + * @since 2023/12/21 15:31 + */ +@Data +public class MenuCreateDTO { + + private String id; + + private String pid = "0"; + + private String path; + + private String name; + + private String title; + + private String icon; + + private String component; + + private Integer sort; + + private Integer deep; + + private String menuTypeCd; + + private String permissions; + + private String hasChildren; + + private String useDataScope = "F"; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/SelectTablesDTO.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/SelectTablesDTO.java new file mode 100644 index 0000000..6da3572 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/dto/SelectTablesDTO.java @@ -0,0 +1,19 @@ +package com.sz.generator.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2023/12/4 10:36 + */ +@Data +@Schema(description = "批量选中") +public class SelectTablesDTO { + + @Schema(description = "选中的tableName数组") + private List tableNames; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/po/GeneratorTable.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/po/GeneratorTable.java new file mode 100644 index 0000000..d560b55 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/po/GeneratorTable.java @@ -0,0 +1,161 @@ +package com.sz.generator.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 代码生成业务表 + *

+ * + * @author sz + * @since 2023-11-27 + */ +@Data +@Table(value = "generator_table", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +public class GeneratorTable implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + private Long tableId; + + /** + * 表名称 + *

+ * private String tableName; + *

+ * /** 表描述 + */ + private String tableName; + + private String tableComment; + + /** + * 实体类名称 + */ + private String className; + + /** + * camel实体类名称 + */ + private String camelClassName; + + /** + * 使用的模版 + */ + private String tplCategory; + + /** + * 生成包路径 + */ + private String packageName; + + /** + * 生成模块名 + */ + private String moduleName; + + /** + * 生成业务名 + */ + private String businessName; + + /** + * 生成功能名 + */ + private String functionName; + + /** + * 生成作者名 + */ + private String functionAuthor; + + /** + * 生成方式(0 zip压缩包;1 自定义路径) + */ + private String type; + + /** + * 其他参数 + */ + private String options; + + /** + * 上级菜单id + */ + private String parentMenuId; + + /** + * 生成路径 + */ + private String path; + + /** + * api生成路径 + */ + + private String pathApi; + + /** + * web生成路径 + */ + private String pathWeb; + + private Long createId; + + private Long updateId; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + /** + * 是否自动创建菜单路由(1 是) + */ + private String menuInitType; + + /** + * 是否自动创建按钮权限 (1 是) + */ + private String btnPermissionType; + + /** + * 是否自动创建数据权限 (1 是) + */ + private String btnDataScopeType; + + /** + * 是否支持导入(1 是) + */ + private String hasImport; + + /** + * 是否支持导出(1 是) + */ + private String hasExport; + + /** + * 生成类型 + *

+ * all 全部 server 后端 service 接口 + */ + private String generateType; + + // 是否自动填充(1 是) + private String isAutofill; + + /** + * 窗口展示类型(1 drawer 抽屉、0 dialog 对话框) + */ + private String windowShowType; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/po/GeneratorTableColumn.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/po/GeneratorTableColumn.java new file mode 100644 index 0000000..bab4abd --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/po/GeneratorTableColumn.java @@ -0,0 +1,191 @@ +package com.sz.generator.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.mysql.EntityChangeListener; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Map; + +/** + *

+ * 代码生成业务表字段 + *

+ * + * @author sz + * @since 2023-11-27 + */ +@Data +@Table(value = "generator_table_column", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +public class GeneratorTableColumn implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 编号 + */ + @Id(keyType = KeyType.Auto) + private Long columnId; + + /** + * 归属表编号 + */ + private Long tableId; + + /** + * 列名称 + */ + private String columnName; + + /** + * 列描述 + */ + private String columnComment; + + /** + * 列类型 + */ + private String columnType; + + /** + * JAVA类型 (String、Integer、Long、Double、BigDecimal、) + */ + private String javaType; + + /** + * 搜索类型(input、input-number、select、select-v2、tree-select、cascader、date-picker、time-picker、time-select、switch、slider) + */ + private String searchType; + + /** + * ts类型 (string、number、string[]) + */ + private String tsType; + + /** + * java类型包名(java), 多个使用逗号分割 + */ + private String javaTypePackage; + + /** + * JAVA字段名 + */ + private String javaField; + + /** + * get开头的驼峰字段名 + */ + private String upCamelField; + + /** + * 是否主键(1是) + */ + private String isPk; + + /** + * 是否自增(1是) + */ + private String isIncrement; + + /** + * 是否必填(1是) + */ + private String isRequired; + + /** + * 是否为插入字段(1是) + */ + private String isInsert; + + /** + * 是否编辑字段(1是) + */ + private String isEdit; + + /** + * 是否列表字段(1是) + */ + private String isList; + + /** + * 是否查询字段(1是) + */ + private String isQuery; + + /** + * 是否自动填充(1 是),通用属性的自动填充,需代码配合(create_id、create_time、update_id、update_time) + */ + private String isAutofill; + + /** + * 是否进行唯一校验(1 是),字段唯一性校验 + */ + private String isUniqueValid; + + /** + * 自动填充类型(INSERT/UPDATE/INSERT_UPDATE) + */ + private String autofillType; + + /** + * 查询方式(等于、不等于、大于、小于、范围) + */ + private String queryType; + + /** + * 显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件) + */ + private String htmlType; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 是否逻辑删除(1 是) + */ + private String isLogicDel; + + /** + * 其他设置 + */ + @Column(typeHandler = JacksonTypeHandler.class) + private Map options; + + /** + * 排序 + */ + private Integer sort; + + private Long createId; + + private Long updateId; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + /** + * 是否导入字段(1 是) + */ + private String isImport; + + /** + * 是否导出字段(1 是) + */ + private String isExport; + + /** + * 字典展示方式(0 唯一标识;1 别名) + */ + private String dictShowWay; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/property/GeneratorProperties.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/property/GeneratorProperties.java new file mode 100644 index 0000000..5cc3b66 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/property/GeneratorProperties.java @@ -0,0 +1,62 @@ +package com.sz.generator.pojo.property; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author sz + * @since 2024/1/15 8:38 + */ +@Data +@Component +@ConfigurationProperties(prefix = "sz.generator") +public class GeneratorProperties { + + // 初始值配置 + private PathProperties path; + + // 全局配置 + private GlobalProperties global; + + // 模块名 + private String moduleName = "sz-service"; + + // service 名 + private String serviceName = "sz-service-admin"; + + @Data + public static class GlobalProperties { + + // 作者 + private String author = "sz-admin"; + + // 包名 + private String packages = "com.sz.admin"; + + // 是否需要去掉前缀配置 + private IgnoreTablePrefix ignoreTablePrefix; + } + + @Data + public static class PathProperties { + + // 前端项目初始路径 + private String web; + + // 后端项目初始路径 + private String api; + } + + @Data + public static class IgnoreTablePrefix { + + // 是否开启 + private Boolean enabled = false; + + // 需要去除的前缀 + private String[] prefixes = new String[]{"t_"}; + + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/SysMenuResult.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/SysMenuResult.java new file mode 100644 index 0000000..532f1c6 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/SysMenuResult.java @@ -0,0 +1,50 @@ +package com.sz.generator.pojo.result; + +import lombok.Data; + +/** + * @author sz + * @since 2023/12/21 14:40 + */ +@Data +public class SysMenuResult { + + private String id; + + private String pid; + + private String path; + + private String name; + + private String title; + + private String icon; + + private String component; + + private String redirect; + + private Integer sort; + + private Integer deep; + + private String menuTypeCd; + + private String permissions; + + private String isHidden; + + private String hasChildren; + + private String isLink; + + private String isFull; + + private String isAffix; + + private String isKeepAlive; + + private String delFlag; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/TableColumResult.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/TableColumResult.java new file mode 100644 index 0000000..504512f --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/TableColumResult.java @@ -0,0 +1,47 @@ +package com.sz.generator.pojo.result; + +import lombok.Data; + +/** + * @author sz + * @since 2023/11/27 15:30 + */ +@Data +public class TableColumResult { + + /** + * 字段名 + */ + private String columnName; + + /** + * 是否必填 + */ + private String isRequired; + + /** + * 是否主键 + */ + private String isPk; + + /** + * 排序 + */ + private int sort; + + /** + * comment描述 + */ + private String columnComment; + + /** + * 是否自增 + */ + private String isIncrement; + + /** + * 字段类型 + */ + private String columnType; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/TableResult.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/TableResult.java new file mode 100644 index 0000000..520e648 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/result/TableResult.java @@ -0,0 +1,20 @@ +package com.sz.generator.pojo.result; + +import lombok.Data; + +/** + * @author sz + * @since 2023/11/27 13:55 + */ +@Data +public class TableResult { + + private String tableName; + + private String tableComment; + + private String createTime; + + private String updateTime; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/CodeGenTempResult.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/CodeGenTempResult.java new file mode 100644 index 0000000..0c10fab --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/CodeGenTempResult.java @@ -0,0 +1,40 @@ +package com.sz.generator.pojo.vo; + +import freemarker.template.Template; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2024/1/16 10:49 + */ +@Data +public class CodeGenTempResult { + + public CodeGenTempResult(Template template, String relativePath, String extension, String alias, String language, String outputMessage) { + this.template = template; + this.relativePath = relativePath; + this.extension = extension; + this.alias = alias; + this.language = language; + this.outputMessage = outputMessage; + } + + private Template template; + + @Schema(description = " zip path (zip存储路径)") + private String relativePath; + + @Schema(description = "扩展名") + private String extension; + + @Schema(description = "别名") + private String alias; + + @Schema(description = "语言") + private String language; + + @Schema(description = "输出信息") + private String outputMessage; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GenCheckedInfoVO.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GenCheckedInfoVO.java new file mode 100644 index 0000000..12b1983 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GenCheckedInfoVO.java @@ -0,0 +1,25 @@ +package com.sz.generator.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2024/4/16 16:11 + */ +@Data +public class GenCheckedInfoVO { + + @Schema(description = "API路径验证状态") + private Boolean checkedApiPath = true; + + @Schema(description = "Web路径验证状态") + private Boolean checkedWebPath = true; + + @Schema(description = "API路径") + private String pathApi; + + @Schema(description = "Web路径") + private String pathWeb; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GeneratorDetailVO.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GeneratorDetailVO.java new file mode 100644 index 0000000..ad8556a --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GeneratorDetailVO.java @@ -0,0 +1,209 @@ +package com.sz.generator.pojo.vo; + +import com.mybatisflex.core.handler.JacksonTypeHandler; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author sz + * @since 2023/11/29 15:25 + */ +@Schema(description = "代码生成配置详情") +@Data +public class GeneratorDetailVO { + + @Schema(description = "基本信息") + private BaseInfo baseInfo; + + @Schema(description = "生成信息") + private GeneratorInfo generatorInfo; + + @Schema(description = "column字段信息") + private List columns; + + @Schema(description = "字典类型列表") + private Set dictTypes; + + @Data + public static class BaseInfo { + + @Schema(description = "table_id") + private Long tableId; + + @Schema(description = "表名称") + private String tableName; + + @Schema(description = "表描述") + private String tableComment; + + @Schema(description = "实体类名称") + private String className; + + @Schema(description = "camel实体类名称") + private String camelClassName; + + @Schema(description = "作者") + private String functionAuthor; + + @Schema(description = "备注") + private String remark; + } + + @Data + public static class GeneratorInfo { + + @Schema(description = "模板") + private String tplCategory; + + @Schema(description = "包路径") + private String packageName; + + @Schema(description = "模块名") + private String moduleName; + + @Schema(description = "业务名") + private String businessName; + + @Schema(description = "功能名") + private String functionName; + + @Schema(description = "其他参数。如上级菜单") + private String options; + + @Schema(description = "代码生成方式") + private String type; + + @Schema(description = "上级菜单id") + private String parentMenuId; + + @Schema(description = "api生成路径") + private String pathApi; + + @Schema(description = "web生成路径") + private String pathWeb; + + @Schema(description = "是否自动创建菜单路由(1 是)") + private String menuInitType; + + @Schema(description = "是否自动创建按钮权限 (1 是)") + private String btnPermissionType; + + @Schema(description = "是否支持导入(1 是)") + private String hasImport; + + @Schema(description = "是否支持导出(1 是)") + private String hasExport; + + @Schema(description = "生成类型") + private String generateType; + + @Schema(description = "是否自动填充(1 是)") + private String isAutofill; + + @Schema(description = "是否自动创建数据权限(1 是)") + private String btnDataScopeType; + + @Schema(description = "窗口展示类型(0 dialog、1 drawer)") + private String windowShowType; + } + + @Data + public static class Column { + + @Schema(description = "column_id") + private Long columnId; + + @Schema(description = "table_id") + private Long tableId; + + @Schema(description = "列名称") + private String columnName; + + @Schema(description = "列描述") + private String columnComment; + + @Schema(description = "列类型") + private String columnType; + + @Schema(description = "JAVA类型 (String、Integer、Long、Double、BigDecimal、Date、LocalDateTime、LocalDate、LocalTime)") + private String javaType; + + @Schema(description = "ts类型") + private String tsType; + + @Schema(description = "搜索类型(input、input-number、select、select-v2、tree-select、cascader、date-picker、time-picker、time-select、switch、slider)") + private String searchType; + + @Schema(description = "JAVA类型 (引包)") + private String javaTypePackage; + + @Schema(description = "JAVA特殊包类型 (引包)") + private String specialPackages; + + @Schema(description = "JAVA字段名") + private String javaField; + + @Schema(description = "get开头的驼峰字段名") + private String upCamelField; + + @Schema(description = "是否主键(1是)") + private String isPk; + + @Schema(description = "是否自增(1是)") + private String isIncrement; + + @Schema(description = "是否必填(1是)") + private String isRequired; + + @Schema(description = "是否为插入字段(1是)") + private String isInsert; + + @Schema(description = "是否编辑字段(1是)") + private String isEdit; + + @Schema(description = "是否列表字段(1是)") + private String isList; + + @Schema(description = "是否查询字段(1是)") + private String isQuery; + + @Schema(description = "是否自动填充(1 是),通用属性的自动填充,需代码配合(create_id、create_time、update_id、update_time)") + private String isAutofill; + + @Schema(description = "是否进行唯一校验(1 是),字段唯一性校验") + private String isUniqueValid; + + @Schema(description = "查询方式(等于EQ、不等于NEQ、大于GT、小于LT、范围BETWEEN、大于等于GTE、小于等于LTE)") + private String queryType; + + @Schema(description = "显示类型(input、textarea、select、radio、checkbox、datetime、date、time、imageUpload、fileUpload、editor)") + private String htmlType; + + @Schema(description = "字典类型") + private String dictType; + + @Schema(description = "其他设置") + @com.mybatisflex.annotation.Column(typeHandler = JacksonTypeHandler.class) + private Map options; + + @Schema(description = "是否逻辑删除(1 是)") + private String isLogicDel; + + @Schema(description = "自动填充类型(FieldFill.INSERT/FieldFill.UPDATE/FieldFill.INSERT_UPDATE)") + private String autofillType; + + @Schema(description = "是否导入字段(1 是)") + private String isImport; + + @Schema(description = "是否导出字段(1 是)") + private String isExport; + + @Schema(description = "字典展示方式(0 唯一标识;1 别名)") + private String dictShowWay; + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GeneratorPreviewVO.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GeneratorPreviewVO.java new file mode 100644 index 0000000..14a34c3 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/pojo/vo/GeneratorPreviewVO.java @@ -0,0 +1,26 @@ +package com.sz.generator.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2024/1/16 16:22 + */ +@Data +@Schema(description = "preview") +public class GeneratorPreviewVO { + + @Schema(description = "文件名", example = "TestController.java") + private String name; + + @Schema(description = "代码", example = "public class TeacherStatisticsController {}") + private String code; + + @Schema(description = "语言", example = "java") + private String language; + + @Schema(description = "别名", example = "controller") + private String alias; + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/GeneratorTableColumnService.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/GeneratorTableColumnService.java new file mode 100644 index 0000000..be059aa --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/GeneratorTableColumnService.java @@ -0,0 +1,27 @@ +package com.sz.generator.service; + +import com.mybatisflex.core.service.IService; +import com.sz.generator.pojo.po.GeneratorTableColumn; + +import java.util.List; + +/** + *

+ * 代码生成业务表字段 服务类 + *

+ * + * @author sz + * @since 2023-11-27 + */ +public interface GeneratorTableColumnService extends IService { + + void batchInsert(List tableColumns); + + List getTableColumnsByTableId(Long tableId); + + List getTableColumnsByTableName(Long tableId); + + void updateBatchTableColumns(List columns); + + void remove(List tableNames); +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/GeneratorTableService.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/GeneratorTableService.java new file mode 100644 index 0000000..526be56 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/GeneratorTableService.java @@ -0,0 +1,52 @@ +package com.sz.generator.service; + +import com.mybatisflex.core.service.IService; +import com.sz.core.common.entity.PageResult; +import com.sz.generator.pojo.dto.DbTableQueryDTO; +import com.sz.generator.pojo.dto.ImportTableDTO; +import com.sz.generator.pojo.dto.SelectTablesDTO; +import com.sz.generator.pojo.po.GeneratorTable; +import com.sz.generator.pojo.vo.GenCheckedInfoVO; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import com.sz.generator.pojo.vo.GeneratorPreviewVO; +import freemarker.template.Template; +import org.springframework.transaction.annotation.Transactional; + +import java.io.IOException; +import java.util.List; + +/** + *

+ * 代码生成业务表 服务类 + *

+ * + * @author sz + * @since 2023-11-27 + */ +public interface GeneratorTableService extends IService { + + void importTable(ImportTableDTO dto); + + PageResult selectDbTableNotInImport(DbTableQueryDTO dto); + + PageResult selectDbTableByImport(DbTableQueryDTO dto); + + GeneratorDetailVO detail(String tableName); + + void updateGeneratorSetting(GeneratorDetailVO generatorDetailVO); + + List generator(String tableName) throws IOException; + + GenCheckedInfoVO checkDist(String tableName); + + byte[] downloadZip(SelectTablesDTO dto) throws IOException; + + List preview(String tableName) throws IOException; + + Template getMenuSqlTemplate() throws IOException; + + @Transactional + void remove(SelectTablesDTO dto); + + Template getDictSqlTemplate() throws IOException; +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/impl/GeneratorTableColumnServiceImpl.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/impl/GeneratorTableColumnServiceImpl.java new file mode 100644 index 0000000..068920c --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/impl/GeneratorTableColumnServiceImpl.java @@ -0,0 +1,54 @@ +package com.sz.generator.service.impl; + +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.generator.mapper.GeneratorTableColumnMapper; +import com.sz.generator.pojo.po.GeneratorTableColumn; +import com.sz.generator.pojo.po.table.GeneratorTableColumnTableDef; +import com.sz.generator.pojo.po.table.GeneratorTableTableDef; +import com.sz.generator.service.GeneratorTableColumnService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 代码生成业务表字段 服务实现类 + *

+ * + * @author sz + * @since 2023-11-27 + */ +@Service +public class GeneratorTableColumnServiceImpl extends ServiceImpl implements GeneratorTableColumnService { + + @Override + public void batchInsert(List tableColumns) { + saveBatch(tableColumns); + } + + @Override + public List getTableColumnsByTableId(Long tableId) { + QueryWrapper wrapper = QueryWrapper.create().eq(GeneratorTableColumn::getTableId, tableId).orderBy(GeneratorTableColumn::getSort).asc(); + return list(wrapper); + } + + @Override + public List getTableColumnsByTableName(Long tableId) { + return QueryChain.of(mapper).eq(GeneratorTableColumn::getTableId, tableId).orderBy(GeneratorTableColumn::getSort).asc().list(); + } + + @Override + public void updateBatchTableColumns(List columns) { + updateBatch(columns); + } + + @Override + public void remove(List tableNames) { + this.updateChain().from(GeneratorTableTableDef.GENERATOR_TABLE, GeneratorTableColumnTableDef.GENERATOR_TABLE_COLUMN) + .where(GeneratorTableColumnTableDef.GENERATOR_TABLE_COLUMN.TABLE_ID.eq(GeneratorTableTableDef.GENERATOR_TABLE.TABLE_ID)) + .where(GeneratorTableTableDef.GENERATOR_TABLE.TABLE_NAME.in(tableNames)).remove(); + } + +} diff --git a/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/impl/GeneratorTableServiceImpl.java b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/impl/GeneratorTableServiceImpl.java new file mode 100644 index 0000000..396af1f --- /dev/null +++ b/sz-common/sz-common-generator/src/main/java/com/sz/generator/service/impl/GeneratorTableServiceImpl.java @@ -0,0 +1,557 @@ +package com.sz.generator.service.impl; + +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.*; +import com.sz.generator.core.AbstractCodeGenerationTemplate; +import com.sz.generator.core.CodeModelBuilder; +import com.sz.generator.core.builder.sql.MenuSqlCodeBuilder; +import com.sz.generator.core.util.BuildTemplateUtils; +import com.sz.generator.core.util.GeneratorUtils; +import com.sz.generator.mapper.GeneratorTableMapper; +import com.sz.generator.pojo.dto.DbTableQueryDTO; +import com.sz.generator.pojo.dto.ImportTableDTO; +import com.sz.generator.pojo.dto.MenuCreateDTO; +import com.sz.generator.pojo.dto.SelectTablesDTO; +import com.sz.generator.pojo.po.GeneratorTable; +import com.sz.generator.pojo.po.GeneratorTableColumn; +import com.sz.generator.pojo.property.GeneratorProperties; +import com.sz.generator.pojo.result.SysMenuResult; +import com.sz.generator.pojo.result.TableColumResult; +import com.sz.generator.pojo.result.TableResult; +import com.sz.generator.pojo.vo.CodeGenTempResult; +import com.sz.generator.pojo.vo.GenCheckedInfoVO; +import com.sz.generator.pojo.vo.GeneratorDetailVO; +import com.sz.generator.pojo.vo.GeneratorPreviewVO; +import com.sz.generator.service.GeneratorTableColumnService; +import com.sz.generator.service.GeneratorTableService; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import static com.sz.generator.core.CodeModelBuilder.SEPARATOR; +import static com.sz.generator.pojo.po.table.GeneratorTableColumnTableDef.GENERATOR_TABLE_COLUMN; +import static com.sz.generator.pojo.po.table.GeneratorTableTableDef.GENERATOR_TABLE; + +/** + *

+ * 代码生成业务表 服务实现类 + *

+ * + * @author sz + * @since 2023-11-27 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class GeneratorTableServiceImpl extends ServiceImpl implements GeneratorTableService { + + private final GeneratorTableColumnService generatorTableColumnService; + + private final FreeMarkerConfigurer configurer; + + private final GeneratorProperties generatorProperties; + + /** + * 导入表 + * + * @param dto + * 导入表名 + */ + @Transactional + @Override + public void importTable(ImportTableDTO dto) { + List tableNames = dto.getTableName(); + // 禁止相同table_name的记录出现多条,先执行清除操作,再生成覆盖 + this.mapper.cleanTableColumnByTableName(tableNames); + this.mapper.cleanTableRecordByTableName(tableNames); + List tableResults = this.mapper.selectDbTableListByNames(tableNames); + GeneratorTable generatorTable; + GeneratorTableColumn generatorTableColumn; + List tableColumns = new ArrayList<>(); + + String pathApi = ""; + String pathWeb = ""; + if (SpringApplicationContextUtils.getInstance().isLocalEnv()) { + String moduleName = generatorProperties.getModuleName(); + String serviceName = generatorProperties.getServiceName(); + String projectRootPath = System.getProperty("user.dir"); + pathApi = projectRootPath + File.separator + moduleName + File.separator + serviceName; + pathWeb = generatorProperties.getPath().getWeb(); + } + + boolean enableIgnoreTablePrefix = generatorProperties.getGlobal().getIgnoreTablePrefix().getEnabled(); + String[] prefixes = generatorProperties.getGlobal().getIgnoreTablePrefix().getPrefixes(); + + for (TableResult table : tableResults) { + generatorTable = GeneratorUtils.initGeneratorTable(table, enableIgnoreTablePrefix, prefixes); + generatorTable.setPathApi(pathApi); + generatorTable.setPathWeb(pathWeb); + save(generatorTable); + Long tableId = generatorTable.getTableId(); + String tableName = table.getTableName(); + List tableColumResults = this.mapper.selectDbTableColumnsByName(tableName); + int i = 1; + for (TableColumResult columResult : tableColumResults) { + generatorTableColumn = GeneratorUtils.initColumnField(columResult, tableId, i); + tableColumns.add(generatorTableColumn); + i++; + } + } + generatorTableColumnService.batchInsert(tableColumns); + } + + /** + * 查询未导入的表 + * + * @param dto + * 查询条件 + * @return 未导入的表 + */ + @Override + public PageResult selectDbTableNotInImport(DbTableQueryDTO dto) { + PageUtils.toPage(dto); + List generatorTables = this.mapper.selectDbTableNotInImport(dto); + return PageUtils.getPageResult(generatorTables); + } + + /** + * 查询已经导入的表 + * + * @param dto + * 查询条件 + * @return 已经导入的表 + */ + @Override + public PageResult selectDbTableByImport(DbTableQueryDTO dto) { + PageUtils.toPage(dto); + List generatorTables = this.mapper.selectDbTableByImport(dto); + return PageUtils.getPageResult(generatorTables); + } + + /** + * 代码生成配置详情 + * + * @param tableName + * 表名 + * @return 代码生成配置详情 + */ + @Override + public GeneratorDetailVO detail(String tableName) { + GeneratorDetailVO detailVO = new GeneratorDetailVO(); + GeneratorTable one = QueryChain.of(GeneratorTable.class).eq(GeneratorTable::getTableName, tableName).one(); + CommonResponseEnum.NOT_EXISTS.message(1002, "table不存在").assertNull(one); + Long tableId = one.getTableId(); + List tableColumns = generatorTableColumnService.getTableColumnsByTableId(tableId); + List columns = BeanCopyUtils.copyList(tableColumns, GeneratorDetailVO.Column.class); + GeneratorDetailVO.BaseInfo baseInfo = BeanCopyUtils.copy(one, GeneratorDetailVO.BaseInfo.class); + GeneratorDetailVO.GeneratorInfo generatorInfo = BeanCopyUtils.copy(one, GeneratorDetailVO.GeneratorInfo.class); + detailVO.setBaseInfo(baseInfo); + detailVO.setGeneratorInfo(generatorInfo); + detailVO.setColumns(columns); + Set dictTypes = new HashSet<>(); + for (GeneratorDetailVO.Column column : columns) { + if (column.getDictType() != null && !column.getDictType().isEmpty()) { + dictTypes.add(column.getDictType()); + } + } + detailVO.setDictTypes(dictTypes); + return detailVO; + } + + /** + * 更新代码生成配置 + * + * @param generatorDetailVO + * 代码生成配置 + */ + @Transactional + @Override + public void updateGeneratorSetting(GeneratorDetailVO generatorDetailVO) { + Long tableId = generatorDetailVO.getBaseInfo().getTableId(); + GeneratorTable one = QueryChain.of(mapper).eq(GeneratorTable::getTableId, tableId).one(); + CommonResponseEnum.INVALID_ID.assertNull(one); + + GeneratorDetailVO.BaseInfo baseInfo = generatorDetailVO.getBaseInfo(); + GeneratorDetailVO.GeneratorInfo generatorInfo = generatorDetailVO.getGeneratorInfo(); + GeneratorTable table = new GeneratorTable(); + BeanCopyUtils.copy(baseInfo, table); + BeanCopyUtils.copy(generatorInfo, table); + // 更新配置信息 + updateById(table); + + List detailColumns = generatorDetailVO.getColumns(); + List columns = BeanCopyUtils.copyList(detailColumns, GeneratorTableColumn.class); + for (int i = 0; i < columns.size(); i++) { + columns.get(i).setSort(i + 1); + if (("select".equals(columns.get(i).getHtmlType()))) { + columns.get(i).setSearchType(columns.get(i).getHtmlType()); + } + } + // 更新column设置 + generatorTableColumnService.updateBatchTableColumns(columns); + } + + @Override + public List generator(String tableName) throws IOException { + List messages = new ArrayList<>(); + GeneratorDetailVO detailVO = detail(tableName); + CodeModelBuilder modelBuilder = new CodeModelBuilder(); + String rootPathApi = detailVO.getGeneratorInfo().getPathApi(); + String rootPathWeb = detailVO.getGeneratorInfo().getPathWeb(); + Map model = modelBuilder.builderBaseInfo(detailVO).builderImportPackage(detailVO).builderDynamicsParam(detailVO).builderPojo(detailVO) + .builderVue(detailVO).getModel(); + List apiTemplates = BuildTemplateUtils.getApiTemplates(configurer, rootPathApi, detailVO, model); + for (AbstractCodeGenerationTemplate apiTemplate : apiTemplates) { + CodeGenTempResult result = apiTemplate.buildTemplate(true); + messages.add(result.getOutputMessage()); + } + List webTemplates = BuildTemplateUtils.getWebTemplates(configurer, rootPathWeb, detailVO, model); + for (AbstractCodeGenerationTemplate webTemplate : webTemplates) { + CodeGenTempResult result = webTemplate.buildTemplate(true); + messages.add(result.getOutputMessage()); + } + + if (shouldInitializeMenu(detailVO)) { + initMenu(detailVO, model, true); // 生成菜单 + } + return messages; + } + + /** + * 磁盘校验 + * + * @param tableName + * 表名 + * @return 校验信息 + */ + @Override + public GenCheckedInfoVO checkDist(String tableName) { + GeneratorDetailVO detailVO = detail(tableName); + String pathApi = detailVO.getGeneratorInfo().getPathApi(); + String pathWeb = detailVO.getGeneratorInfo().getPathWeb(); + boolean apiPathExists = FileUtils.isPathExists(pathApi); + boolean webPathExists = FileUtils.isPathExists(pathWeb); + GenCheckedInfoVO checkedInfo = new GenCheckedInfoVO(); + // 如果选择模版包含前端,进行前端校验 + if (("all").equals(detailVO.getGeneratorInfo().getGenerateType())) { + checkedInfo.setCheckedWebPath(webPathExists); + } + checkedInfo.setCheckedApiPath(apiPathExists); + checkedInfo.setPathApi(pathApi); + checkedInfo.setPathWeb(pathWeb); + return checkedInfo; + } + + @Override + @Transactional + public byte[] downloadZip(SelectTablesDTO dto) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + try { + List tableNames = dto.getTableNames(); + // 根据id 获取要导入的表detail + List detailVOS = getDetailsForTables(tableNames); + + for (GeneratorDetailVO detailVO : detailVOS) { + CodeModelBuilder modelBuilder = new CodeModelBuilder(); + String rootPathApi = detailVO.getGeneratorInfo().getPathApi(); + String rootPathWeb = detailVO.getGeneratorInfo().getPathWeb(); + Map model = modelBuilder.builderBaseInfo(detailVO).builderImportPackage(detailVO).builderDynamicsParam(detailVO) + .builderPojo(detailVO).builderVue(detailVO).getModel(); + + List apiTemplates = BuildTemplateUtils.getApiTemplates(configurer, rootPathApi, detailVO, model); + for (AbstractCodeGenerationTemplate apiTemplate : apiTemplates) { + CodeGenTempResult apiTmpRes = apiTemplate.buildTemplate(false); + addFileToZip(zip, apiTmpRes, model); + } + + List webTemplates = BuildTemplateUtils.getWebTemplates(configurer, rootPathWeb, detailVO, model); + for (AbstractCodeGenerationTemplate webTemplate : webTemplates) { + CodeGenTempResult webTmpRes = webTemplate.buildTemplate(false); + addFileToZip(zip, webTmpRes, model); + } + if (shouldInitializeMenu(detailVO)) { + List menuCreateDTOS = initMenu(detailVO, model, false); + if (!menuCreateDTOS.isEmpty()) { + model.put("sysMenuList", menuCreateDTOS); + MenuSqlCodeBuilder menuSqlCodeBuilder = new MenuSqlCodeBuilder(configurer, "", detailVO, model); + CodeGenTempResult sqlTmpRes = menuSqlCodeBuilder.buildTemplate(false); + addFileToZip(zip, sqlTmpRes, model); + } + } + } + } finally { + zip.close(); + } + return outputStream.toByteArray(); + } + + @Override + @Transactional + public List preview(String tableName) throws IOException { + List previews = new ArrayList<>(); + GeneratorDetailVO detailVO = detail(tableName); + String rootPathApi = detailVO.getGeneratorInfo().getPathApi(); + String rootPathWeb = detailVO.getGeneratorInfo().getPathWeb(); + Map model = new CodeModelBuilder().builderBaseInfo(detailVO).builderImportPackage(detailVO).builderDynamicsParam(detailVO) + .builderPojo(detailVO).builderVue(detailVO).getModel(); + + // 处理 API 模板 + handleTemplates(BuildTemplateUtils.getApiTemplates(configurer, rootPathApi, detailVO, model), previews, model); + // 处理 Web 模板 + handleTemplates(BuildTemplateUtils.getWebTemplates(configurer, rootPathWeb, detailVO, model), previews, model); + // 处理 Sql模板 + if (shouldInitializeMenu(detailVO)) { + List menuCreateDTOS = initMenu(detailVO, model, false); // 预览仅生成sql,不插入sql + if (!menuCreateDTOS.isEmpty()) { + model.put("sysMenuList", menuCreateDTOS); + MenuSqlCodeBuilder menuSqlCodeBuilder = new MenuSqlCodeBuilder(configurer, "", detailVO, model); + CodeGenTempResult sqlTmpRes = menuSqlCodeBuilder.buildTemplate(false); + String relativePath = sqlTmpRes.getRelativePath(); + String templateProcess = renderTemplateString(sqlTmpRes, model); + String fileName = Paths.get(relativePath).getFileName().toString(); + GeneratorPreviewVO previewVO = new GeneratorPreviewVO(); + previewVO.setCode(templateProcess); + previewVO.setName(fileName); + previewVO.setLanguage(sqlTmpRes.getLanguage()); + previewVO.setAlias(sqlTmpRes.getAlias()); + previews.add(previewVO); + } + } + + return previews; + } + + @Override + public Template getMenuSqlTemplate() throws IOException { + return configurer.getConfiguration().getTemplate(File.separator + "sql" + File.separator + "menuImport.sql.ftl"); + } + + private void handleTemplates(List templates, List previews, Map model) + throws IOException { + for (AbstractCodeGenerationTemplate template : templates) { + CodeGenTempResult tmpRes = template.buildTemplate(false); + String relativePath = tmpRes.getRelativePath(); + String fileName = Paths.get(relativePath).getFileName().toString(); + String templateProcess = renderTemplateString(tmpRes, model); + + GeneratorPreviewVO previewVO = new GeneratorPreviewVO(); + previewVO.setCode(templateProcess); + previewVO.setName(fileName); + previewVO.setLanguage(tmpRes.getLanguage()); + previewVO.setAlias(tmpRes.getAlias()); + previews.add(previewVO); + } + } + + private void addFileToZip(ZipOutputStream zip, CodeGenTempResult tempResult, Map model) throws IOException { + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(renderTemplate(tempResult, model))) { + String relativePath = tempResult.getRelativePath(); + ZipEntry zipEntry = new ZipEntry(relativePath); + zip.putNextEntry(zipEntry); + IOUtils.copy(inputStream, zip); + zip.closeEntry(); + } + } + + private byte[] renderTemplate(CodeGenTempResult tempResult, Map model) throws IOException { + return renderTemplateString(tempResult, model).getBytes(StandardCharsets.UTF_8); + } + + private String renderTemplateString(CodeGenTempResult tempResult, Map model) throws IOException { + try (StringWriter writer = new StringWriter()) { + tempResult.getTemplate().process(model, writer); + return writer.toString(); + } catch (TemplateException e) { + throw new IOException("Error rendering template", e); + } + } + + /** + * 菜单的生成 + * + * @param detailVO + * 详情 + * @param model + * 模型 + */ + public List initMenu(GeneratorDetailVO detailVO, Map model, boolean isInsertDB) { + List menus = new ArrayList<>(); + if ("0".equals(detailVO.getGeneratorInfo().getMenuInitType())) { // 获取代码配置,是否启用菜单(菜单不启用,按钮也不会启用)初始化 + return menus; + } + String menuId = Utils.generateUUIDs(); // 按钮父级id,菜单id + String parentMenuId = detailVO.getGeneratorInfo().getParentMenuId(); + int menuDeep = getMenuDepth(parentMenuId); + String routerName = model.get("indexDefineOptionsName").toString(); + String path = buildPath(detailVO); + String component = buildComponent(detailVO); + int count = this.mapper.selectMenuCount(parentMenuId); + + MenuCreateDTO menuDto = buildMenu(detailVO, menuId, parentMenuId, path, routerName, component, count, menuDeep); + menus.add(menuDto); + if (isInsertDB) { + if (!assertMenuDoesNotExist(routerName, path, component, parentMenuId)) { + this.mapper.insertMenu(menuDto); + } + } + menus.addAll(createButtonPermissions(menuId, model, menuDeep, isInsertDB, detailVO)); + this.mapper.syncTreeHasChildren(); + return menus; + } + + private int getMenuDepth(String parentMenuId) { + SysMenuResult sysMenuResult = this.mapper.selectSysMenuByPid(parentMenuId); + return (sysMenuResult != null) ? sysMenuResult.getDeep() + 1 : 1; + } + + private String buildPath(GeneratorDetailVO detailVO) { + return SEPARATOR + detailVO.getGeneratorInfo().getModuleName() + SEPARATOR + detailVO.getGeneratorInfo().getBusinessName(); // 获取前端设置的业务名称 + } + + private String buildComponent(GeneratorDetailVO detailVO) { + return buildPath(detailVO) + SEPARATOR + "index"; + } + + private boolean assertMenuDoesNotExist(String routerName, String path, String component, String parentMenuId) { + int menuCount = this.mapper.countMenu(routerName, path, component, parentMenuId); + String message = String.format("菜单已存在: name=%s, path=%s, component=%s, pid=%s", routerName, path, component, parentMenuId); + // CommonResponseEnum.EXISTS.message(1001, message).assertTrue(menuCount > 0); + log.warn(message); + return menuCount > 0; + } + + private List createButtonPermissions(String menuId, Map model, int menuDeep, boolean isInsertDB, + GeneratorDetailVO detailVO) { + List buttonMenus = new ArrayList<>(); + + int order = 1; + + if ("1".equals(detailVO.getGeneratorInfo().getBtnPermissionType())) { + buttonMenus.add(buildAndInsertButton(menuId, "查询", model.get("listPermission").toString(), order * 100, menuDeep, isInsertDB)); + order++; + buttonMenus.add(buildAndInsertButton(menuId, "新增", model.get("createPermission").toString(), order * 100, menuDeep, isInsertDB)); + order++; + buttonMenus.add(buildAndInsertButton(menuId, "修改", model.get("updatePermission").toString(), order * 100, menuDeep, isInsertDB)); + order++; + buttonMenus.add(buildAndInsertButton(menuId, "删除", model.get("removePermission").toString(), order * 100, menuDeep, isInsertDB)); + order++; + } + + if ("1".equals(detailVO.getGeneratorInfo().getHasImport())) { + buttonMenus.add(buildAndInsertButton(menuId, "导入", model.get("importPermission").toString(), order * 100, menuDeep, isInsertDB)); + order++; + } + + if ("1".equals(detailVO.getGeneratorInfo().getHasExport())) { + buttonMenus.add(buildAndInsertButton(menuId, "导出", model.get("exportPermission").toString(), order * 100, menuDeep, isInsertDB)); + } + + return buttonMenus; + } + + private MenuCreateDTO buildAndInsertButton(String menuId, String action, String permission, int order, int deep, boolean isInsertDB) { + MenuCreateDTO btnDto = buildBtn(menuId, action, permission, order, deep); + if (isInsertDB) { + this.mapper.insertMenu(btnDto); + } + return btnDto; + } + + private static MenuCreateDTO buildMenu(GeneratorDetailVO detailVO, String btnParentId, String parentMenuId, String path, String routerName, + String component, int count, int parentDeep) { + MenuCreateDTO createDTO = new MenuCreateDTO(); + createDTO.setId(btnParentId); + if (Utils.isNotNull(parentMenuId)) { + createDTO.setPid(parentMenuId); + } + createDTO.setPath(path); + createDTO.setName(routerName); + createDTO.setTitle(detailVO.getGeneratorInfo().getFunctionName()); // eg: 教师统计 + createDTO.setIcon(""); + createDTO.setComponent(component); + createDTO.setSort(count * 100 + 100); + createDTO.setDeep(parentDeep); + createDTO.setMenuTypeCd("1002002"); // 菜单 + createDTO.setPermissions(""); + createDTO.setHasChildren("F"); + if (detailVO.getGeneratorInfo().getBtnDataScopeType().equals("1")) { + createDTO.setUseDataScope("T"); + } else { + createDTO.setUseDataScope("F"); + } + return createDTO; + } + + private MenuCreateDTO buildBtn(String btnParentId, String btnName, String createPermission, int sort, int menuDeep) { + MenuCreateDTO dto = new MenuCreateDTO(); + dto.setId(Utils.generateUUIDs()); + dto.setPid(btnParentId); + dto.setPath(""); + dto.setName(""); + dto.setTitle(btnName); // eg: 教师统计 + dto.setIcon(""); + dto.setComponent(""); + dto.setMenuTypeCd("1002003"); // 菜单类型:按钮 + dto.setPermissions(createPermission); + dto.setDeep(menuDeep + 1); + dto.setHasChildren("F"); + dto.setSort(sort); + return dto; + } + + @Override + @Transactional + public void remove(SelectTablesDTO dto) { + UpdateChain.of(GeneratorTableColumn.class).from(GENERATOR_TABLE_COLUMN) + .where(GENERATOR_TABLE_COLUMN.TABLE_ID.in( + QueryWrapper.create().select(GENERATOR_TABLE.TABLE_ID).from(GENERATOR_TABLE).where(GENERATOR_TABLE.TABLE_NAME.in(dto.getTableNames())))) + .remove(); + QueryWrapper wrapper = QueryWrapper.create().in(GeneratorTable::getTableName, dto.getTableNames()); + remove(wrapper); + } + + private List getDetailsForTables(List tableNames) { + List detailVOS = new ArrayList<>(); + for (String tableName : tableNames) { + GeneratorDetailVO detail = detail(tableName); + detailVOS.add(detail); + } + return detailVOS; + } + + /** + * 是否应该初始化菜单 + * + * @param detailVO + * 配置详情 + * @return boolean + */ + private boolean shouldInitializeMenu(GeneratorDetailVO detailVO) { + return ("1").equals(detailVO.getGeneratorInfo().getMenuInitType()) && (("all").equals(detailVO.getGeneratorInfo().getGenerateType())); // 开启菜单初始化配置 && + // // 代码生成类型是all + } + + @Override + public Template getDictSqlTemplate() throws IOException { + return configurer.getConfiguration().getTemplate(File.separator + "sql" + File.separator + "dictImport.sql.ftl"); + } + +} diff --git a/sz-common/sz-common-generator/src/main/resources/mapper/GeneratorTableColumnMapper.xml b/sz-common/sz-common-generator/src/main/resources/mapper/GeneratorTableColumnMapper.xml new file mode 100644 index 0000000..e24a604 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/mapper/GeneratorTableColumnMapper.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + column_id + , table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, is_autofill, is_unique_valid, query_type, html_type, dict_type, sort, create_id, create_time, update_id, update_time, options, is_logic_del + + + + + diff --git a/sz-common/sz-common-generator/src/main/resources/mapper/GeneratorTableMapper.xml b/sz-common/sz-common-generator/src/main/resources/mapper/GeneratorTableMapper.xml new file mode 100644 index 0000000..1ef49d8 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/mapper/GeneratorTableMapper.xml @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table_id + , table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, type, path, path_api, path_web, create_id, create_time, update_id, update_time, options, has_import, has_export, is_autofill, btn_data_scope_type + + + + id + , pid, path, name, title, icon, component, redirect, sort, deep, menu_type_cd, permissions, is_hidden, has_children, is_link, is_full, is_affix, is_keep_alive, del_flag + + + + + DELETE + FROM generator_table + where table_name in + + #{name} + + + + DELETE FROM generator_table_column + WHERE EXISTS ( + SELECT 1 + FROM generator_table + WHERE generator_table_column.table_id = generator_table.table_id + AND generator_table.table_name IN + + #{name} + + ); + + + + + + + + + + + INSERT INTO `sys_menu` (`id`, + `pid`, + `path`, + `name`, + `title`, + `icon`, + `component`, + `sort`, + `deep`, + `menu_type_cd`, + `permissions`, + `has_children`, + `use_data_scope`) + VALUES (#{createDTO.id}, + #{createDTO.pid}, + #{createDTO.path}, + #{createDTO.name}, + #{createDTO.title}, + #{createDTO.icon}, + #{createDTO.component}, + #{createDTO.sort}, + #{createDTO.deep}, + #{createDTO.menuTypeCd}, + #{createDTO.permissions}, + #{createDTO.hasChildren}, + #{createDTO.useDataScope}) + + + + UPDATE sys_menu AS m + JOIN ( + SELECT id, + IF(EXISTS (SELECT 1 FROM sys_menu WHERE pid = sub_m.id), 'T', 'F') AS has_children + FROM sys_menu AS sub_m + WHERE 1=1 and sub_m.del_flag = 'F' + ) AS subquery + ON m.id = subquery.id + SET m.has_children = 'T' + WHERE subquery.has_children = 'T'; + + + UPDATE sys_menu AS m + JOIN sys_menu AS parent + ON m.pid = parent.id + SET m.deep = parent.deep + 1 + WHERE 1=1 and m.del_flag = 'F'; + + + + diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/controller.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/controller.java.ftl new file mode 100644 index 0000000..96b87d1 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/controller.java.ftl @@ -0,0 +1,125 @@ +package ${controllerPkg}; + +<#compress> +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +<#if GeneratorInfo.hasImport == "1"> +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; + +import lombok.RequiredArgsConstructor; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.constant.GlobalConstant; + +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import ${servicePkg}.${serviceClassName}; +import ${dtoPkg}.${dtoCreateClassName}; +import ${dtoPkg}.${dtoUpdateClassName}; +import ${dtoPkg}.${dtoListClassName}; +import ${voPkg}.${voClassName}; +<#if GeneratorInfo.hasImport == "1"> +import com.sz.core.common.entity.ImportExcelDTO; + +<#if GeneratorInfo.hasExport == "1"> +import jakarta.servlet.http.HttpServletResponse; + + + + +/** + *

+ * ${tableComment} Controller + *

+ * + * @author ${author} + * @since ${datetime} + */ +@Tag(name = "${tableComment}") +@RestController +@RequestMapping("${router}") +@RequiredArgsConstructor +public class ${controllerClassName} { + +<#assign serviceName = lower_case_first_letter(serviceClassName)> + private final ${serviceClassName} ${serviceName}; + + @Operation(summary = "新增") +<#if GeneratorInfo.btnPermissionType == "1"> + @SaCheckPermission(value = "${createPermission}") + + @PostMapping + public ApiResult create(@RequestBody ${dtoCreateClassName} dto) { + ${serviceName}.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") +<#if GeneratorInfo.btnPermissionType == "1"> + @SaCheckPermission(value = "${updatePermission}") + + @PutMapping + public ApiResult update(@RequestBody ${dtoUpdateClassName} dto) { + ${serviceName}.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") +<#if GeneratorInfo.btnPermissionType == "1"> + @SaCheckPermission(value = "${removePermission}") + + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + ${serviceName}.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "${listPermission}") + @GetMapping + public ApiResult> list(${dtoListClassName} dto) { + return ApiPageResult.success(${serviceName}.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "${listPermission}") + @GetMapping("/{id}") + public ApiResult<${voClassName}> detail(@PathVariable Object id) { + return ApiResult.success(${serviceName}.detail(id)); + } +<#if GeneratorInfo.hasImport == "1"> + + @Operation(summary = "导入") + @Parameters({ + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true), + }) + <#if GeneratorInfo.btnPermissionType == "1"> + @SaCheckPermission(value = "${importPermission}") + + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + ${serviceName}.importExcel(dto); + } + +<#if GeneratorInfo.hasExport == "1"> + + @Operation(summary = "导出") + <#if GeneratorInfo.btnPermissionType == "1"> + @SaCheckPermission(value = "${exportPermission}") + + @PostMapping("/export") + public void exportExcel(@RequestBody ${dtoListClassName} dto, HttpServletResponse response) { + ${serviceName}.exportExcel(dto, response); + } + +<#compress> +} +<#-- 内建函数,实现首字母小写 --> +<#function lower_case_first_letter str> + <#return str?substring(0, 1)?lower_case + str?substring(1)> + + \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/dtoCreate.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoCreate.java.ftl new file mode 100644 index 0000000..a13d1f7 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoCreate.java.ftl @@ -0,0 +1,41 @@ +package ${dtoPkg}; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +<#list importPackages as pkg> +import ${pkg}; + +<#if hasDateFormat == true> +import org.springframework.format.annotation.DateTimeFormat; + + +/** + *

+ * ${poClassName}添加DTO + *

+ * + * @author ${author} + * @since ${datetime} + */ +@Data +@Schema(description = "${poClassName}添加DTO") +public class ${dtoCreateClassName} { + +<#list columns as field> + <#if field.isInsert == "1" > + <#if field.javaType == "LocalDateTime" > + @Schema(description = "${field.columnComment}") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private ${field.javaType} ${field.javaField}; + <#else> +<#if field.javaType?starts_with("List")> + @Column(typeHandler = JacksonTypeHandler.class) + + @Schema(description = "${field.columnComment}") + private ${field.javaType} ${field.javaField}; + + + + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/dtoImport.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoImport.java.ftl new file mode 100644 index 0000000..0a3470e --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoImport.java.ftl @@ -0,0 +1,55 @@ +package ${dtoPkg}; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +<#list importPackages as pkg> +import ${pkg}; + + +import cn.idev.excel.annotation.ExcelProperty; +<#if hasDict == true> +import com.sz.excel.annotation.DictFormat; + +<#if hasDateFormat == true> +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * ${poClassName}导入DTO + *

+ * + * @author ${author} + * @since ${datetime} + */ +@Data +@Schema(description = "${poClassName}导入DTO") +public class ${dtoImportClassName} { + +<#list columns as field> +<#if field.isImport == "1" > + <#-- 时间类型处理--> + <#if field.javaType == "LocalDateTime"> + @Schema(description = "${field.columnComment}") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private ${field.javaType} ${field.javaField}; + <#else> + <#-- 有字典值 --> + <#if field.dictType != ""> + @ExcelProperty(value = "${field.columnComment}") + <#if field.dictShowWay == "0"> + @DictFormat(dictType = "${field.dictType}") + <#else> + @DictFormat(dictType = "${field.dictType}", useAlias = true) + + <#else> + <#-- 无字典值--> + @ExcelProperty(value = "${field.columnComment}") + + @Schema(description = "${field.columnComment}") + private ${field.javaType} ${field.javaField}; + + + + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/dtoList.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoList.java.ftl new file mode 100644 index 0000000..5ed3ae4 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoList.java.ftl @@ -0,0 +1,52 @@ +package ${dtoPkg}; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import com.sz.core.common.entity.PageQuery; +<#list importPackages as pkg> +import ${pkg}; + +<#if hasDateFormat == true> +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * ${poClassName}查询DTO + *

+ * + * @author ${author} + * @since ${datetime} + */ +@Data +@Schema(description = "${poClassName}查询DTO") +public class ${dtoListClassName} extends PageQuery { + +<#list columns as field> +<#if field.isQuery == "1" > + <#-- 范围查询 --> + <#if field.queryType == "BETWEEN"> + <#-- 范围查询-日期 --> + <#if field.javaType == "LocalDateTime"> + @Schema(description = "${field.columnComment}开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private ${field.javaType} ${field.javaField}Start; + + @Schema(description = "${field.columnComment}结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private ${field.javaType} ${field.javaField}End; + <#else> + @Schema(description = "${field.columnComment}开始") + private ${field.javaType} ${field.javaField}Start; + + @Schema(description = "${field.columnComment}结束") + private ${field.javaType} ${field.javaField}End; + + <#else> + @Schema(description = "${field.columnComment}") + private ${field.javaType} ${field.javaField}; + + + + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/dtoUpdate.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoUpdate.java.ftl new file mode 100644 index 0000000..61a13d4 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/dtoUpdate.java.ftl @@ -0,0 +1,46 @@ +package ${dtoPkg}; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +<#list importPackages as pkg> +import ${pkg}; + +<#if hasDateFormat == true> +import org.springframework.format.annotation.DateTimeFormat; + + +/** + *

+ * ${poClassName}修改DTO + *

+ * + * @author ${author} + * @since ${datetime} + */ +@Data +@Schema(description = "${poClassName}修改DTO") +public class ${dtoUpdateClassName} { + +<#list columns as field> + <#if field.isPk =="1"> + @Schema(description = "${field.columnComment}") + private ${field.javaType} ${field.javaField}; + + + <#if field.isEdit == "1" && field.isPk == "0" > + <#if field.javaType == "LocalDateTime"> + @Schema(description = "${field.columnComment}") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private ${field.javaType} ${field.javaField}; + <#else> + <#if field.javaType?starts_with("List")> + @Column(typeHandler = JacksonTypeHandler.class) + + @Schema(description = "${field.columnComment}") + private ${field.javaType} ${field.javaField}; + + + + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/mapper.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/mapper.java.ftl new file mode 100644 index 0000000..5231293 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/mapper.java.ftl @@ -0,0 +1,16 @@ +package ${mapperPkg}; + +import com.mybatisflex.core.BaseMapper; +import ${poPkg}.${poClassName}; + +/** +*

+* ${tableComment} Mapper 接口 +*

+* +* @author ${author} +* @since ${datetime} +*/ +public interface ${mapperClassName} extends BaseMapper<${className}> { + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/mapper.xml.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/mapper.xml.ftl new file mode 100644 index 0000000..541a604 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/mapper.xml.ftl @@ -0,0 +1,22 @@ + + + + + + <#list columns as field> + <#-- 主键 --> + <#if field.isPk == "1" > + + <#-- 普通字段 --> + <#else> + typeHandler="com.mybatisflex.core.handler.JacksonTypeHandler"/> + + + + + + + <#list columns as field>${field.columnName}<#if !field?is_last>, + + + diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/po.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/po.java.ftl new file mode 100644 index 0000000..801fa20 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/po.java.ftl @@ -0,0 +1,61 @@ +package ${poPkg}; + +<#compress> +import com.mybatisflex.annotation.*; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.io.Serial; +import com.sz.mysql.EntityChangeListener; +<#list importPackages as pkg> +import ${pkg}; + + + + +/** +*

+* ${tableComment} +*

+* +* @author ${author} +* @since ${datetime} +*/ +@Data +<#if GeneratorInfo.isAutofill == "1"> +@Table(value = "${tableName}", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +<#else> +@Table(value = "${tableName}") + +@Schema(description = "${tableComment}") +public class ${poClassName} implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + +<#-- ---------- BEGIN 字段循环遍历 ----------> +<#list columns as field> + <#-- 主键 --> + <#if field.isPk == "1"> + <#if field.isIncrement == "1"> + @Id(keyType = KeyType.Auto) + <#else> + @Id + + + <#-- 逻辑删除 --> + <#if field.isLogicDel == "1"> + @Column(isLogicDelete = true) + + <#if field.javaType?starts_with("List")> + @Column(typeHandler = JacksonTypeHandler.class) + + @Schema(description ="${field.columnComment}") + private ${field.javaType} ${field.javaField}; + + +<#-- ---------- BEGIN 字段循环遍历 ----------> +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/service.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/service.java.ftl new file mode 100644 index 0000000..3b428da --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/service.java.ftl @@ -0,0 +1,56 @@ +package ${servicePkg}; + +<#compress> +import com.mybatisflex.core.service.IService; +import ${poPkg}.${poClassName}; +<#if GeneratorInfo.generateType != "service"> +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.entity.PageResult; +import java.util.List; + +import ${dtoPkg}.${dtoCreateClassName}; +import ${dtoPkg}.${dtoUpdateClassName}; +import ${dtoPkg}.${dtoListClassName}; +import ${voPkg}.${voClassName}; +<#if GeneratorInfo.hasImport == "1"> +import com.sz.core.common.entity.ImportExcelDTO; + +<#if GeneratorInfo.hasExport == "1"> +import jakarta.servlet.http.HttpServletResponse; + + + + + +/** + *

+ * ${tableComment} Service + *

+ * + * @author ${author} + * @since ${datetime} + */ +public interface ${serviceClassName} extends IService<${poClassName}> { + +<#if GeneratorInfo.generateType != "service"> + void create(${dtoCreateClassName} dto); + + void update(${dtoUpdateClassName} dto); + + PageResult<${voClassName}> page(${dtoListClassName} dto); + + List<${voClassName}> list(${dtoListClassName} dto); + + void remove(SelectIdsDTO dto); + + ${voClassName} detail(Object id); + <#if GeneratorInfo.hasImport == "1"> + + void importExcel(ImportExcelDTO dto); + + <#if GeneratorInfo.hasExport == "1"> + + void exportExcel(${dtoListClassName} dto, HttpServletResponse response); + + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/serviceImpl.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/serviceImpl.java.ftl new file mode 100644 index 0000000..eef5900 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/serviceImpl.java.ftl @@ -0,0 +1,223 @@ +package ${serviceImplPkg}; + +<#compress> +import com.mybatisflex.spring.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ${servicePkg}.${serviceClassName}; +import ${poPkg}.${poClassName}; +import ${mapperPkg}.${mapperClassName}; +<#if GeneratorInfo.generateType != "service"> +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.query.QueryChain; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.PageUtils; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.Utils; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import java.io.Serializable; +import java.util.List; +import ${dtoPkg}.${dtoCreateClassName}; +import ${dtoPkg}.${dtoUpdateClassName}; +import ${dtoPkg}.${dtoListClassName}; +<#if GeneratorInfo.hasImport == "1"> +import ${dtoPkg}.${dtoImportClassName}; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.excel.core.ExcelResult; + +<#if GeneratorInfo.hasExport == "1"> +import java.io.OutputStream; +import jakarta.servlet.http.HttpServletResponse; +import com.sz.core.util.FileUtils; + +<#if GeneratorInfo.hasImport == "1" || GeneratorInfo.hasExport == "1"> +import com.sz.excel.utils.ExcelUtils; +import lombok.SneakyThrows; + +<#if GeneratorInfo.btnDataScopeType == "1"> +import com.sz.core.datascope.SimpleDataScopeHelper; + + +import ${voPkg}.${voClassName}; + + + + +/** + *

+ * ${tableComment} 服务实现类 + *

+ * + * @author ${author} + * @since ${datetime} + */ +@Service +@RequiredArgsConstructor +public class ${serviceImplClassName} extends ServiceImpl<${mapperClassName}, ${poClassName}> implements ${serviceClassName} { +<#if GeneratorInfo.generateType != "service"> + @Override + public void create(${dtoCreateClassName} dto){ + ${poClassName} ${camelClassName} = BeanCopyUtils.copy(dto, ${poClassName}.class); +<#if hasUniqueValidField == true> + long count; +<#list columns as field> + <#if field.isUniqueValid == "1" && field.isInsert == "1" > + // 唯一性校验 + count = QueryChain.of(${poClassName}.class).eq(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()).count(); + CommonResponseEnum.EXISTS.message("${field.javaField}已存在").assertTrue(count > 0); + + + + save(${camelClassName}); + } + + @Override + public void update(${dtoUpdateClassName} dto){ + ${poClassName} ${camelClassName} = BeanCopyUtils.copy(dto, ${poClassName}.class); + QueryWrapper wrapper; +<#list columns as field> + <#if field.isPk == "1"> + // id有效性校验 + wrapper = QueryWrapper.create() + <#list pkColumns as pkField> + .eq(${poClassName}::get${pkField.upCamelField}, dto.get${pkField.upCamelField}()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + + + +<#if hasUniqueValidField == true> + // 唯一性校验 + long count; +<#list columns as field> + <#if field.isUniqueValid == "1" && field.isEdit == "1"> + count = QueryChain.of(${poClassName}.class).eq(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}())<#list pkColumns as pkField>.ne(${poClassName}::get${pkField.upCamelField}, dto.get${pkField.upCamelField}()).count(); + CommonResponseEnum.EXISTS.message("${field.javaField}已存在").assertTrue(count > 0); + + + + saveOrUpdate(${camelClassName}); + } + + @Override + public PageResult<${voClassName}> page(${dtoListClassName} dto){ +<#if GeneratorInfo.btnDataScopeType == "1"> + try { + SimpleDataScopeHelper.start(${poClassName}.class); + Page<${voClassName}> page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), ${voClassName}.class); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } +<#else> + Page<${voClassName}> page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), ${voClassName}.class); + return PageUtils.getPageResult(page); + + } + + @Override + public List<${voClassName}> list(${dtoListClassName} dto){ +<#if GeneratorInfo.btnDataScopeType == "1"> + try { + SimpleDataScopeHelper.start(${poClassName}.class); + return listAs(buildQueryWrapper(dto), ${voClassName}.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } +<#else> + return listAs(buildQueryWrapper(dto), ${voClassName}.class); + + } + + @Override + public void remove(SelectIdsDTO dto){ + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public ${voClassName} detail(Object id){ + ${poClassName} ${camelClassName} = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(${camelClassName}); + return BeanCopyUtils.copy(${camelClassName}, ${voClassName}.class); + } +<#if GeneratorInfo.hasImport == "1"> + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult<${dtoImportClassName}> excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), ${dtoImportClassName}.class, true); + List<${dtoImportClassName}> list = excelResult.getList(); + // 入库 + List<${poClassName}> importList = BeanCopyUtils.copyList(list, ${poClassName}.class); + saveBatch(importList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + } + +<#if GeneratorInfo.hasExport == "1"> + + @SneakyThrows + @Override + public void exportExcel(${dtoListClassName} dto, HttpServletResponse response) { + List<${voClassName}> list = list(dto); + String fileName = "${functionName}模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "${functionName}", ${voClassName}.class, os); + } + + + private static QueryWrapper buildQueryWrapper(${dtoListClassName} dto) { + QueryWrapper wrapper = QueryWrapper.create().from(${poClassName}.class); +<#list columns as field> + <#if field.isQuery == "1"> + <#-- 等于--> + <#if field.queryType == "EQ"> + if (Utils.isNotNull(dto.get${field.upCamelField}())) { + wrapper.eq(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()); + } + <#--不等于--> + <#elseif field.queryType == "NEQ" > + if (Utils.isNotNull(dto.get${field.upCamelField}())) { + wrapper.ne(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()); + } + <#--大于--> + <#elseif field.queryType == "GT" > + if (Utils.isNotNull(dto.get${field.upCamelField}())) { + wrapper.gt(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()); + } + <#--小于--> + <#elseif field.queryType == "LT" > + if (Utils.isNotNull(dto.get${field.upCamelField}())) { + wrapper.lt(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()); + } + <#--BETWEEN--> + <#elseif field.queryType == "BETWEEN" > + if (Utils.isNotNull(dto.get${field.upCamelField}Start()) && Utils.isNotNull(dto.get${field.upCamelField}End())) { + wrapper.between(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}Start(), dto.get${field.upCamelField}End()); + } + <#--大于等于--> + <#elseif field.queryType == "GTE" > + if (Utils.isNotNull(dto.get${field.upCamelField}())) { + wrapper.gte(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()); + } + <#--小于等于--> + <#elseif field.queryType == "LTE" > + if (Utils.isNotNull(dto.get${field.upCamelField}())) { + wrapper.lte(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()); + } + <#--模糊--> + <#elseif field.queryType == "LIKE" > + if (Utils.isNotNull(dto.get${field.upCamelField}())) { + wrapper.like(${poClassName}::get${field.upCamelField}, dto.get${field.upCamelField}()); + } + + + + return wrapper; + } + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/api/vo.java.ftl b/sz-common/sz-common-generator/src/main/resources/templates/api/vo.java.ftl new file mode 100644 index 0000000..bd2b4dd --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/api/vo.java.ftl @@ -0,0 +1,59 @@ +package ${voPkg}; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +<#list importPackages as pkg> +import ${pkg}; + +<#if hasExcel == true> +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; + <#if hasDict == true> +import com.sz.excel.annotation.DictFormat; + + +<#if hasDateFormat == true> +import org.springframework.format.annotation.DateTimeFormat; + + +/** + *

+ * ${poClassName}返回vo + *

+ * + * @author ${author} + * @since ${datetime} + */ +@Data +@Schema(description = "${poClassName}返回vo") +public class ${voClassName} { + +<#list columns as field> +<#if field.isList == "1" > + <#if field.isExport == "1" && hasExcel == true> + <#if field.dictType != ""> + @ExcelProperty(value = "${field.columnComment}") + <#if field.dictShowWay == "0"> + @DictFormat(dictType = "${field.dictType}") + <#else> + @DictFormat(dictType = "${field.dictType}", useAlias = true) + + <#else> + @ExcelProperty(value = "${field.columnComment}") + + <#if field.javaType == "LocalDateTime"> + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + + <#elseif hasExcel == true> + @ExcelIgnore + + <#if field.javaType?starts_with("List")> + @Column(typeHandler = JacksonTypeHandler.class) + + @Schema(description = "${field.columnComment}") + private ${field.javaType} ${field.javaField}; + + + +} \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/sql/dictImport.sql.ftl b/sz-common/sz-common-generator/src/main/resources/templates/sql/dictImport.sql.ftl new file mode 100644 index 0000000..84a77cd --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/sql/dictImport.sql.ftl @@ -0,0 +1,18 @@ +<#-- 字典SQL --> +<#setting number_format="0"> +<#compress> +<#if dictTypeList?has_content> +<#list dictTypeList as dictType> + INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (${dictType.id}, '${dictType.typeName}', '${dictType.typeCode}', '${dictType.isLock}', '${dictType.isShow}', '${dictType.delFlag}', '${dictType.remark}', '${dictType.createTime}', NULL, NULL, NULL, NULL, NULL, '${dictType.type}'); + + + + + +<#compress> +<#if dictList?has_content> +<#list dictList as dict> + INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (${dict.id}, '${dict.sysDictTypeId}', '${dict.codeName}', '${dict.alias}', ${dict.sort}, '${dict.callbackShowStyle}', '${dict.remark}', '${dict.isLock}', '${dict.isShow}', '${dict.delFlag}', '${dict.createTime}', NULL, NULL, NULL, NULL, NULL); + + + \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/sql/menuImport.sql.ftl b/sz-common/sz-common-generator/src/main/resources/templates/sql/menuImport.sql.ftl new file mode 100644 index 0000000..aed638d --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/sql/menuImport.sql.ftl @@ -0,0 +1,7 @@ +<#-- 菜单SQL --> +<#setting number_format="0"> +<#compress> +<#list sysMenuList as menu> +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`, `use_data_scope`) VALUES ('${menu.id}', '${menu.pid}', '${menu.path}', '${menu.name}', '${menu.title}', '${menu.icon}', '${menu.component}', '${menu.redirect}', ${menu.sort}, ${menu.deep}, '${menu.menuTypeCd}', '${menu.permissions}', '${menu.isHidden}', '${menu.hasChildren}', '${menu.isLink}', '${menu.isFull}', '${menu.isAffix}', '${menu.isKeepAlive}', '${menu.delFlag}', '${menu.useDataScope}'); + + \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/sql/menuInit.sql.ftl b/sz-common/sz-common-generator/src/main/resources/templates/sql/menuInit.sql.ftl new file mode 100644 index 0000000..59c085f --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/sql/menuInit.sql.ftl @@ -0,0 +1,7 @@ +<#-- 菜单SQL --> +<#setting number_format="0"> +<#compress> +<#list sysMenuList as menu> +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `sort`, `deep`, `menu_type_cd`, `permissions`, `has_children`, `use_data_scope`) VALUES ('${menu.id}', '${menu.pid}', '${menu.path}', '${menu.name}', '${menu.title}', '${menu.icon}', '${menu.component}', ${menu.sort}, ${menu.deep}, '${menu.menuTypeCd}', '${menu.permissions}', '${menu.hasChildren}', '${menu.useDataScope}'); + + \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/vue/componentForm.vue.ftl b/sz-common/sz-common-generator/src/main/resources/templates/vue/componentForm.vue.ftl new file mode 100644 index 0000000..2f9b821 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/vue/componentForm.vue.ftl @@ -0,0 +1,175 @@ + + + + + \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/vue/index.vue.ftl b/sz-common/sz-common-generator/src/main/resources/templates/vue/index.vue.ftl new file mode 100644 index 0000000..f60f1c0 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/vue/index.vue.ftl @@ -0,0 +1,290 @@ + + + \ No newline at end of file diff --git a/sz-common/sz-common-generator/src/main/resources/templates/vue/modules.ts.ftl b/sz-common/sz-common-generator/src/main/resources/templates/vue/modules.ts.ftl new file mode 100644 index 0000000..e796779 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/vue/modules.ts.ftl @@ -0,0 +1,81 @@ +import http from '@/api'; +import { ADMIN_MODULE } from '@/api/helper/prefix'; +import type { IPage } from '@/api/types'; +import type { + ${interfaceNamespace}Query, + ${interfaceNamespace}Row, + ${interfaceNamespace}Form +} from '@${typePkg}/${interfaceClassName}'; +<#if GeneratorInfo.hasImport == "1"> +import type { UploadRawFile } from "element-plus/es/components/upload/src/upload"; +import type { AxiosRequestConfig } from 'axios'; + + +/** +* 查询列表 +* @param params +* @returns {*} +*/ +export const ${funGetList} = (params: ${interfaceNamespace}Query) => { + return http.get>(ADMIN_MODULE + `/${router}`, params); +}; + +/** +* 添加 +* @param params +* @returns {*} +*/ +export const ${funCreate} = (params: ${interfaceNamespace}Form) => { + return http.post(ADMIN_MODULE + `/${router}`, params); +}; + +/** +* 修改 +* @param params +* @returns {*} +*/ +export const ${funUpdate} = (params: ${interfaceNamespace}Form) => { + return http.put(ADMIN_MODULE + `/${router}`, params); +}; + +/** +* 删除 +* @param params +* @returns {*} +*/ +export const ${funRemove} = (params: { ids: (string | number)[] }) => { + return http.delete(ADMIN_MODULE + `/${router}`, params); +}; + +/** +* 获取详情 +* @param params +* @returns {*} +*/ +export const ${funDetail} = (params: { id: ${idType} }) => { + const { id } = params; + return http.get<${interfaceNamespace}Row>(ADMIN_MODULE + `/${router}/<#noparse>${id}`); +}; +<#if GeneratorInfo.hasImport == "1"> + +/** +* 导入excel +* @param params +*/ +export const ${funImport} = (params : UploadRawFile, config?: AxiosRequestConfig | undefined) => { + return http.upload(ADMIN_MODULE + `/${router}/import`, params, config); +}; + + +<#if GeneratorInfo.hasExport == "1"> +/** +* 导出excel +* @param params +* @returns {*} +*/ +export const ${funExport} = (params: ${interfaceNamespace}Query) => { + return http.download(ADMIN_MODULE + `/${router}/export`, params); +<#compress> +}; + + diff --git a/sz-common/sz-common-generator/src/main/resources/templates/vue/type.ts.ftl b/sz-common/sz-common-generator/src/main/resources/templates/vue/type.ts.ftl new file mode 100644 index 0000000..73cd0c2 --- /dev/null +++ b/sz-common/sz-common-generator/src/main/resources/templates/vue/type.ts.ftl @@ -0,0 +1,34 @@ +import type { IPageQuery } from '@/api/types'; + +// 查询条件 +export type ${interfaceNamespace}Query = IPageQuery & { +<#list columns as field> + <#if field.isQuery == "1" > + <#if field.queryType == "BETWEEN" > + ${field.javaField}Start?: ${field.tsType}; + ${field.javaField}End?: ${field.tsType}; + <#else> + ${field.javaField}?: ${field.tsType}; + + + +}; + +// 编辑form表单 +export type ${interfaceNamespace}Form = { +<#list columns as field> + <#if field.isInsert == "1" || field.isEdit == "1" > + ${field.javaField}?: ${field.tsType}; + + +}; + +// list或detail返回结构 +export type ${interfaceNamespace}Row = { +<#list columns as field> + <#if field.isList == "1"> + ${field.javaField}?: ${field.tsType}; + + +}; + diff --git a/sz-common/sz-common-log/pom.xml b/sz-common/sz-common-log/pom.xml new file mode 100644 index 0000000..62d21dd --- /dev/null +++ b/sz-common/sz-common-log/pom.xml @@ -0,0 +1,48 @@ + + + + sz-common + com.sz + ${revision} + + 4.0.0 + + sz-common-log + + + + com.sz + sz-common-core + ${revision} + provided + true + + + com.sz + sz-common-security + ${revision} + provided + true + + + org.aspectj + aspectjweaver + provided + true + + + org.springframework.boot + spring-boot-starter-logging + + + com.mybatis-flex + mybatis-flex-spring-boot3-starter + provided + true + + + + + \ No newline at end of file diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/PrintSQL.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/PrintSQL.java new file mode 100644 index 0000000..c46ba08 --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/PrintSQL.java @@ -0,0 +1,33 @@ +package com.sz.logger; + +import com.mybatisflex.core.audit.AuditManager; +import lombok.extern.slf4j.Slf4j; + +/** + * PrintSQL + * + * @author sz + * @since 2024/5/11 15:03 + */ +@Slf4j +public class PrintSQL { + + private PrintSQL() { + throw new IllegalStateException("Utility class"); + } + + public static void print() { + // 开启审计功能 + AuditManager.setAuditEnable(true); + // 自定义sql打印 或 自定义审计功能,也可结合logback将sql日志输出到独立文件中。 + // 详见https://mybatis-flex.com/zh/core/audit.html + // 设置 SQL 审计收集器 + AuditManager.setMessageCollector(auditMessage -> log.info("{} ---- {}ms, row:{}", formatSQL(auditMessage.getFullSql()), auditMessage.getElapsedTime(), + auditMessage.getQueryCount())); + } + + public static String formatSQL(String sql) { + return sql.replaceAll("\\s+", " ").replace("\\r", " ").replace("\\n", " "); + } + +} diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/aspect/AccessLogAspect.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/aspect/AccessLogAspect.java new file mode 100644 index 0000000..45a2b85 --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/aspect/AccessLogAspect.java @@ -0,0 +1,128 @@ +package com.sz.logger.aspect; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.stp.StpUtil; +import com.sz.core.common.entity.AccessRequestLog; +import com.sz.core.common.entity.AccessResponseLog; +import com.sz.core.util.HttpReqResUtil; +import com.sz.core.util.JsonUtils; +import com.sz.security.pojo.WhitelistProperties; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; + +import org.springframework.web.multipart.MultipartFile; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArraySet; + +@Component +@Aspect +@Slf4j(topic = "http-log") +@RequiredArgsConstructor +public class AccessLogAspect { + + private final WhitelistProperties whitelistProperties; + + private static final String SEND_TIME = "SEND_TIME"; + + private static final long SLOW_QUERY_THRESHOLD = 2000; + + @Pointcut("execution(public * com.sz..*.controller..*.*(..))") + public void methodArgs() { + } + + @Before("methodArgs()") + public void doBefore(JoinPoint joinPoint) { + try { + HttpServletRequest request = HttpReqResUtil.getRequest(); + AccessRequestLog requestLog = buildRequestLog(joinPoint, request); + CopyOnWriteArraySet whitelist = whitelistProperties.getWhitelist(); + if (isNotSaIgnoreInterface(joinPoint) && isNotWhitelist(request.getRequestURI(), request.getContextPath(), whitelist)) { + requestLog.setUserId(StpUtil.getLoginIdAsString()); + } + log.info(" [aop] request log : {}", JsonUtils.toJsonString(requestLog)); + request.setAttribute(SEND_TIME, System.currentTimeMillis()); + } catch (Exception e) { + log.error("Error in doBefore method", e); + } + } + + @AfterReturning(returning = "returnValue", pointcut = "methodArgs()") + public void doAfterReturning(JoinPoint joinPoint, Object returnValue) { + try { + HttpServletRequest request = HttpReqResUtil.getRequest(); + AccessResponseLog responseLog = buildResponseLog(joinPoint, returnValue, request); + CopyOnWriteArraySet whitelist = whitelistProperties.getWhitelist(); + whitelist.add("/auth/logout"); // 登出接口会清除 session,无法获取到用户id。加入白名单中 + if (isNotSaIgnoreInterface(joinPoint) && isNotWhitelist(request.getRequestURI(), request.getContextPath(), whitelist)) { + responseLog.setUserId(StpUtil.getLoginIdAsString()); + } + + if (responseLog.getMs() >= SLOW_QUERY_THRESHOLD) { // 慢查询日志打印 + log.info(" [aop] response log : {}", JsonUtils.toJsonString(responseLog)); + } + } catch (Exception e) { + log.error("Error in doAfterReturning method", e); + } + } + + private AccessRequestLog buildRequestLog(JoinPoint joinPoint, HttpServletRequest request) { + String contentType = request.getContentType(); + String queryString = request.getQueryString(); + Map urlParams = HttpReqResUtil.getUrlParams(queryString); + String body = HttpReqResUtil.getBody(request); + Map parameter = HttpReqResUtil.getParameter(request); + Object[] args = filterAndConvertArguments(joinPoint.getArgs()); + + return AccessRequestLog.builder().traceId("").url(request.getRequestURI()).timestamp(System.currentTimeMillis()).method(request.getMethod()) + .ip(HttpReqResUtil.getIpAddress(request)).param(urlParams).body(body).form(parameter).requestBody(args).type("request").contentType(contentType) + .build(); + } + + private AccessResponseLog buildResponseLog(JoinPoint joinPoint, Object returnValue, HttpServletRequest request) { + String queryString = request.getQueryString(); + Map urlParams = HttpReqResUtil.getUrlParams(queryString); + Map parameter = HttpReqResUtil.getParameter(request); + long sendTime = (long) request.getAttribute(SEND_TIME); + long ms = System.currentTimeMillis() - sendTime; + + return AccessResponseLog.builder().timestamp(System.currentTimeMillis()).traceId("").param(JsonUtils.toJsonString(urlParams)) + .form(JsonUtils.toJsonString(parameter)).reqBody(filterAndConvertArguments(joinPoint.getArgs())).resBody(returnValue) + .method(request.getMethod()).url(request.getRequestURI()).ms(ms).build(); + } + + private Object[] filterAndConvertArguments(Object[] args) { + if (Objects.nonNull(args)) { + List filteredArgs = Arrays.stream(args) + .filter(arg -> !(arg instanceof HttpServletResponse || arg instanceof HttpServletRequest || arg instanceof MultipartFile)).toList(); + return filteredArgs.toArray(); + } + return new Object[0]; + } + + private boolean isNotWhitelist(String requestURI, String contextPath, CopyOnWriteArraySet whitelist) { + AntPathMatcher antPathMatcher = new AntPathMatcher(); + String pathAfterContext = contextPath.equals("/") ? requestURI.substring(1) : requestURI.replace(contextPath, ""); + return whitelist.stream().noneMatch(pattern -> antPathMatcher.match(pattern, pathAfterContext)); + } + + private boolean isNotSaIgnoreInterface(JoinPoint joinPoint) { + MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); + Method method = methodSignature.getMethod(); + return !method.isAnnotationPresent(SaIgnore.class); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/entity/AccessRequestLog.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/entity/AccessRequestLog.java new file mode 100644 index 0000000..ac6ae58 --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/entity/AccessRequestLog.java @@ -0,0 +1,59 @@ +package com.sz.logger.entity; + +import lombok.Data; +import lombok.experimental.SuperBuilder; + +/** + * @author sz + * @since 2022/02/16 09:39 + */ +@Data +@SuperBuilder +public class AccessRequestLog { + + private String type = "request"; + + /** + * 请求标识 + */ + private String traceId; + + private String userId; + + /** + * 请求路径 + */ + private String url; + + /** + * 开始时间戳 + */ + private long timestamp; + + /** + * http 方法:GET、POST等 + */ + private String method; + + /** + * url 参数体 + */ + private Object param; + + /** + * form表单参数体 + */ + private Object form; + + /** + * post body参数体 + */ + private Object body; + + private String ip; + + private String contentType; + + private Object requestBody; + +} diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/entity/AccessResponseLog.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/entity/AccessResponseLog.java new file mode 100644 index 0000000..d287224 --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/entity/AccessResponseLog.java @@ -0,0 +1,58 @@ +package com.sz.logger.entity; + +import lombok.Data; +import lombok.experimental.SuperBuilder; + +/** + * @author sz + * @since 2023/2/20 16:33 + */ + +@Data +@SuperBuilder +public class AccessResponseLog { + + private String traceId; + + /** + * 开始时间戳 + */ + private long timestamp; + + private String userId; + + /** + * 请求地址 + */ + private String url; + + /** + * 请求耗时 (ms) + */ + private long ms; + + /** + * 响应结果 + */ + private Object resBody; + + /** + * url 参数体 + */ + private Object param; + + /** + * form表单参数体 + */ + private Object form; + + /** + * post body参数体 + */ + private Object reqBody; + + private String type = "response"; + + private String method; + +} diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/DesensitizationAppender.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/DesensitizationAppender.java new file mode 100644 index 0000000..0abb0ac --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/DesensitizationAppender.java @@ -0,0 +1,58 @@ +package com.sz.logger.logbackadvice; + +import ch.qos.logback.classic.spi.LoggingEvent; +import com.sz.logger.utils.DesensitizationUtil; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; + +/** + * 脱敏类 - 将日志进行脱敏 + * + * @author 柳成荫 + * @since 2021/1/9 + */ +@Slf4j +public class DesensitizationAppender { + + /** + * LoggingEvent的属性 - message 格式化前的日志信息,如log.info("your name : {}", "柳成荫") + * message就是"your name : {}" + */ + private static final String MESSAGE = "message"; + + /** + * LoggingEvent的属性 - formattedMessage 格式化后的日志信息,如log.info("your name : {}", + * "柳成荫") formattedMessage就是"your name : 柳成荫" + */ + private static final String FORMATTED_MESSAGE = "formattedMessage"; + + public void operation(LoggingEvent event) { + // event.getArgumentArray() - 获取日志中的参数数组 + // 如:log.info("your name : {}, your id : {}", "柳成荫", 11) + // event.getArgumentArray() => ["柳成荫",11] + if (event.getArgumentArray() != null) { + // 获取格式化后的Message + String eventFormattedMessage = event.getFormattedMessage(); + DesensitizationUtil util = new DesensitizationUtil(); + // 获取替换后的日志信息 + String changeMessage = util.customChange(eventFormattedMessage); + if (!(null == changeMessage || changeMessage.isEmpty())) { + try { + // 利用反射的方式,将替换后的日志设置到原event对象中去 + Class eventClass = event.getClass(); + // 保险起见,将message和formattedMessage都替换了 + Field message = eventClass.getDeclaredField(MESSAGE); + message.setAccessible(true); + message.set(event, changeMessage); + Field formattedMessage = eventClass.getDeclaredField(FORMATTED_MESSAGE); + formattedMessage.setAccessible(true); + formattedMessage.set(event, changeMessage); + } catch (IllegalAccessException | NoSuchFieldException e) { + log.error("DesensitizationAppender err", e); + } + } + + } + } +} diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzConsoleAppender.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzConsoleAppender.java new file mode 100644 index 0000000..bec3b1a --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzConsoleAppender.java @@ -0,0 +1,19 @@ +package com.sz.logger.logbackadvice; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.ConsoleAppender; + +/** + * @author 柳成荫 + * @since 2021/1/9 + */ +public class SzConsoleAppender extends ConsoleAppender { + + @Override + protected void subAppend(LoggingEvent event) { + // 自定义操作 + DesensitizationAppender appender = new DesensitizationAppender(); + appender.operation(event); // 处理日志事件 + super.subAppend(event); // 调用父类方法,传递 LoggingEvent 类型 + } +} diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzFileAppender.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzFileAppender.java new file mode 100644 index 0000000..1cca535 --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzFileAppender.java @@ -0,0 +1,18 @@ +package com.sz.logger.logbackadvice; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.FileAppender; + +/** + * @author 柳成荫 + * @since 2021/1/9 + */ +public class SzFileAppender extends FileAppender { + + @Override + protected void subAppend(LoggingEvent event) { + DesensitizationAppender appender = new DesensitizationAppender(); + appender.operation(event); + super.subAppend(event); + } +} \ No newline at end of file diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzRollingFileAppender.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzRollingFileAppender.java new file mode 100644 index 0000000..65bc3cf --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/logbackadvice/SzRollingFileAppender.java @@ -0,0 +1,18 @@ +package com.sz.logger.logbackadvice; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.rolling.RollingFileAppender; + +/** + * @author 柳成荫 + * @since 2021/1/9 + */ +public class SzRollingFileAppender extends RollingFileAppender { + + @Override + protected void subAppend(LoggingEvent event) { + DesensitizationAppender appender = new DesensitizationAppender(); + appender.operation(event); + super.subAppend(event); + } +} diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/utils/DesensitizationUtil.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/utils/DesensitizationUtil.java new file mode 100644 index 0000000..e7c81ce --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/utils/DesensitizationUtil.java @@ -0,0 +1,461 @@ +package com.sz.logger.utils; + +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * !!! 后续此类警徽被移除,将不会做太多优化。 This class will be deprecated in future versions. + * + * 脱敏工具类 + * + * @author 柳成荫 + * @since 2021/1/9 + */ +public class DesensitizationUtil { + + /** + * 正则匹配模式 - + * 该正则表达式第三个()可能无法匹配以某些特殊符号开头和结尾的(如果像密码这种字段,前后如果有很多特殊字段,则无法匹配,建议密码直接加密,无需脱敏) + */ + public static final Pattern REGEX_PATTERN = Pattern + .compile("\\s*(\"?\\w+\"?)\\s*[:=]\\s*([^\\u4e00-\\u9fa5@,.*{\\[\\w]*\\s*)([\\u4e00-\\u9fa5_\\-@.\\w]+)\\s*"); + + /** + * 匹配非数字 + */ + public static final Pattern REGEX_NUM = Pattern.compile("[^0-9]"); + + /** + * 是否开启脱敏 + */ + public static Boolean openFlag = false; + + /** + * 是否忽略key的大小写 + */ + public static Boolean ignoreFlag = true; + + /** + * 作为ignoreFlag初始的标记 + */ + private static Boolean initIgnoreFlag = false; + + /** + * 作为openFlag初始化的标记 + */ + private static Boolean initOpenFlag = false; + + /** + * 所有key:value配置匹配对 + */ + public static Map allPattern; + + /** + * key为全小写的allPattern - pattern和patterns + */ + public static Map lowerCaseAllPattern; + + /** + * 手机 + */ + public static final String PHONE = "phone"; + + /** + * 邮箱 + */ + public static final String EMAIL = "email"; + + /** + * 身份证 + */ + public static final String IDENTITY = "identity"; + + /** + * 自定义 + */ + public static final String OTHER = "other"; + + /** + * 密码 + */ + public static final String PASSWORD = "password"; + + public static final String PWD = "pwd"; + + /** + * 将event对象的formattedMessage脱敏 + * + * @param eventFormattedMessage + * LoggingEvent的formattedMessage属性 + * @return 脱敏后的日志信息 + */ + public String customChange(String eventFormattedMessage) { + try { + // 原始信息 - 格式化后的 + String originalMessage = eventFormattedMessage; + boolean flag = false; + // 获取Yml配置文件内容 - Map格式 + Map patternMap = YmlUtils.patternMap; + if (!CollectionUtils.isEmpty(patternMap)) { + // 如果没有开启脱敏,返回"",则不会做脱敏操作 + if (!this.checkOpen(patternMap)) { + return ""; + } + // 获取一个原始Message的正则匹配器 + Matcher regexMatcher = REGEX_PATTERN.matcher(eventFormattedMessage); + // 如果部分匹配(一个对象/JSON字符串/Map/List<对象/Map>等会有多个匹配),就根据分组来获取key和value + while (regexMatcher.find()) { + // group(1)就是key,group(2)就是分隔符(如:和=),group(3)就是value + try { + // 获取key - 将引号替换掉,去掉两边空格(JSON字符串去引号) + String key = regexMatcher.group(1).replaceAll("\"", "").trim(); + // 获取原始Value + String originalValue = regexMatcher.group(3); + // 获取Key对应规则 + Object keyPatternValue = this.getKeyIgnoreCase(key); + if (null != keyPatternValue && null != originalValue && !"null".equals(originalValue)) { + // 将原始Value - 引号替换掉,去掉两边空格(JSON字符串去引号) + String value = originalValue.replaceAll("\"", "").trim(); + if (!"null".equals(value) || value.equalsIgnoreCase(key)) { + String patternVales = getMultiplePattern(keyPatternValue, value); + if ("".equals(patternVales)) { + // 不符规则/没有规则的不能影响其他符合规则的 + continue; + } + patternVales = patternVales.replaceAll(" ", ""); + if (PASSWORD.equalsIgnoreCase(patternVales)) { + String origin = regexMatcher.group(1) + regexMatcher.group(2) + regexMatcher.group(3); + originalMessage = originalMessage.replace(origin, regexMatcher.group(1) + regexMatcher.group(2) + "******"); + flag = true; + // 密码级别的,直接替换为全*,继续下一轮匹配 + continue; + } + // 原始的规则(完整) + String originalPatternValues = patternVales; + // 判断这个规则是否带括号,带括号的需要把括号拿出来 - 核心规则 + String filterData = this.getBracketPattern(patternVales); + if (!filterData.isEmpty()) { + patternVales = filterData; + } + // 以逗号分割 + String[] split = patternVales.split(","); + value = getReplaceValue(value, patternVales, split, originalPatternValues); + if (value != null && !value.isEmpty()) { + flag = true; + String origin = regexMatcher.group(1) + regexMatcher.group(2) + regexMatcher.group(3); + originalMessage = originalMessage.replace(origin, regexMatcher.group(1) + regexMatcher.group(2) + value); + } + } + } + } catch (Exception e) { + // 捕获到异常,直接返回结果(空字符串) - 这个异常可能发生的场景:同时开启控制台和输出文件的时候 + // 当控制台进行一次脱敏之后,文件的再去脱敏,是对脱敏后的message脱敏,则正则匹配会出现错误 + // 比如123456789@.com 脱敏后:123***456789@qq.com,正则匹配到123,这个123去substring的时候会出错 + return ""; + } + } + } + return flag ? originalMessage : ""; + } catch (Exception e) { + return ""; + } + } + + /** + * 获取替换后的value + * + * @param value + * value + * @param patternVales + * 核心规则 + * @param split + * 分割 + * @param originalPatternValues + * 原始规则 + * @return 替换后的value + */ + private String getReplaceValue(String value, String patternVales, String[] split, String originalPatternValues) { + if (split.length >= 2 && !"".equals(patternVales)) { + String append = ""; + String start = REGEX_NUM.matcher(split[0]).replaceAll(""); + String end = REGEX_NUM.matcher(split[1]).replaceAll(""); + int startSub = Integer.parseInt(start) - 1; + int endSub = Integer.parseInt(end) - 1; + // 脱敏起点/结尾符下标 + int index; + String flagSub; + int indexOf; + int newValueL; + String newValue; + // 脱敏结尾 + if (originalPatternValues.contains(">")) { + // 获取>的下标 + index = originalPatternValues.indexOf(">"); + // 获取标志符号 + flagSub = originalPatternValues.substring(0, index); + // 获取标志符号的下标 + indexOf = value.indexOf(flagSub); + // 获取标志符号前面数据 + newValue = value.substring(0, indexOf); + // 获取数据的长度 + newValueL = newValue.length(); + // 获取标识符及后面的数据 + append = value.substring(indexOf); + value = this.dataDesensitization(Math.max(startSub, 0), endSub >= 0 ? (endSub <= newValueL ? endSub : newValueL - 1) : 0, newValue) + append; + } else if (originalPatternValues.contains("<")) { + // 脱敏起点 + index = originalPatternValues.indexOf("<"); + flagSub = originalPatternValues.substring(0, index); + indexOf = value.indexOf(flagSub); + newValue = value.substring(indexOf + 1); + newValueL = newValue.length(); + append = value.substring(0, indexOf + 1); + value = append + this.dataDesensitization(Math.max(startSub, 0), endSub >= 0 ? (endSub <= newValueL ? endSub : newValueL - 1) : 0, newValue); + } else if (originalPatternValues.contains(",")) { + newValueL = value.length(); + value = this.dataDesensitization(Math.max(startSub, 0), endSub >= 0 ? (endSub <= newValueL ? endSub : newValueL - 1) : 0, value); + } + } else if (!"".equals(patternVales)) { + int beforeIndexOf = patternVales.indexOf("*"); + int last = patternVales.length() - patternVales.lastIndexOf("*"); + int lastIndexOf = value.length() - last; + value = this.dataDesensitization(beforeIndexOf, lastIndexOf, value); + } + return value; + } + + /** + * 根据key获取对应的规则(也许是Map,也许是String) + * + * @param key + * key + * @return key对应的规则(也许是Map , 也许是String) + */ + private Object getKeyIgnoreCase(String key) { + // 获取所有pattern + if (CollectionUtils.isEmpty(allPattern)) { + allPattern = YmlUtils.getAllPattern(); + } + // 作为ignoreFlag初始化的标记,第一次ignoreFlag需要从Yml中获取是否开启 + // 后面就不用去Yml里获取了 + if (!initIgnoreFlag) { + initIgnoreFlag = true; + // 仅在第一次会去获取,无论true还是false(默认是开启忽略大小写) + ignoreFlag = YmlUtils.getIgnore(); + if (ignoreFlag) { + // 如果忽略大小写,就去获取一份key小写化的allPattern + lowerCaseAllPattern = this.transformUpperCase(allPattern); + } + } + // 只有忽略大小写的时候,才去从lowerCaseAllPattern里获取 + if (ignoreFlag) { + return lowerCaseAllPattern.get(key.toLowerCase()); + } else { + // 否则从原始的pattern中取 + return allPattern.get(key); + } + } + + /** + * 将pattern的key值全部转换为小写 + * + * @param pattern + * pattern + * @return 转换后的pattern + */ + public Map transformUpperCase(Map pattern) { + Map resultMap = new HashMap<>(); + if (pattern != null && !pattern.isEmpty()) { + // 获取Key的Set集合 + Set keySet = pattern.keySet(); + // 黄线强迫症,用for代替while + for (String key : keySet) { + // 把key转换为小写字符串 + String newKey = key.toLowerCase(); + // 重新放入 + resultMap.put(newKey, pattern.get(key)); + } + } + return resultMap; + } + + /** + * 获取规则字符串 + * + * @param patternVale + * 规则 + * @param newValue + * key对应的值 - 如 name:liuchengyin 这个参数就是liuchengyn + * @return 规则的字符串 + */ + private String getMultiplePattern(Object patternVale, String newValue) { + if (patternVale instanceof String) { + // 如果规则是String类型,直接转换为String类型返回 + return (String) patternVale; + } else if (patternVale instanceof Map) { + // 获取规则 - Map类型(不推荐,有风险) + return this.getPatternByMap((Map) patternVale, newValue); + } else { // 获取规则 - List类型,一个Key可能有多种匹配规则 + if (patternVale instanceof List) { + List> list = (List>) patternVale; + if (!CollectionUtils.isEmpty(list)) { + // 遍历每一种规则 + for (Map map : list) { + String patternValue = this.getPatternByMap(map, newValue); + // 如果是空的,表示没匹配上该规则,去匹配下一个规则 + if (!"".equals(patternValue)) { + return patternValue; + } + } + } + } + return ""; + } + } + + /** + * 获取规则 + * + * @param map + * 规则 + * @param value + * key对应的值 - 如 name:liuchengyin 这个参数就是liuchengyn + * @return 规则 + */ + private String getPatternByMap(Map map, String value) { + if (CollectionUtils.isEmpty(map)) { + // 为空就是无规则 + return ""; + } else { + // 获取匹配规则 - 自定义规则(正则) + Object customRegexObj = map.get("customRegex"); + // 获取脱敏方式 + Object positionObj = map.get("position"); + // 获取匹配规则 - 自定义规则(正则) + String customRegex = ""; + // position必须有 + String position = ""; + if (customRegexObj instanceof String) { + customRegex = (String) customRegexObj; + } + if (positionObj instanceof String) { + position = (String) positionObj; + } + // 如果日志中的值能够匹配,直接返回其对应的规则 + if (!customRegex.isEmpty() && value.matches(customRegex)) { + return position; + } else { + // 如果不能匹配到正则,就看他是不是内置规则 + Object defaultRegexObj = map.get("defaultRegex"); + String defaultRegex = ""; + if (defaultRegexObj instanceof String) { + defaultRegex = (String) defaultRegexObj; + } + // 这段代码写的多多少少感觉有点问题,可以写在一个if里,但是阿里检测代码的工具会警告 + if (!defaultRegex.isEmpty()) { + if (IDENTITY.equals(defaultRegex) && isIdentity(value)) { + return position; + } else if (EMAIL.equals(defaultRegex) && isEmail(value)) { + return position; + } else if (PHONE.equals(defaultRegex) && isMobile(value)) { + return position; + } else if (OTHER.equals(defaultRegex)) { + return position; + } + } + return ""; + } + } + } + + /** + * 获取规则 - 判断是否带括号,带括号则返回括号内数据 + * + * @param patternVales + * 规则 + * @return 规则 + */ + private String getBracketPattern(String patternVales) { + // 是否存在括号 + if (patternVales.contains("(")) { + int startCons = patternVales.indexOf("("); + int endCons = patternVales.indexOf(")"); + patternVales = patternVales.substring(startCons + 1, endCons); + return patternVales; + } else { + return ""; + } + } + + public static boolean isEmail(String str) { + // 优化后的正则表达式 + String emailRegex = "^[\\w-\\.]+@[\\w-]+\\.[\\w-]{2,4}$"; + return str.matches(emailRegex); + } + + public static boolean isIdentity(String str) { + return str.matches("(^\\d{18}$)|(^\\d{15}$)"); + } + + public static boolean isMobile(String str) { + return str.matches("^1[0-9]{10}$"); + } + + /** + * 检查是否开启脱敏 + * + * @param pattern + * Yml配置文件内容 - Map格式 + * @return 是否开启脱敏 + */ + private Boolean checkOpen(Map pattern) { + // 作为openFlag初始化的标记,第一次openFlag需要从Yml中获取是否开启 + // 后面就不用去Yml里获取了 + if (!initOpenFlag) { + initOpenFlag = true; + // 仅在第一次会去获取 + openFlag = YmlUtils.getOpen(); + } + // 第二次以后openFlag已经有值,无论true还是false(默认是未开启) + return openFlag; + } + + /** + * 脱敏处理 + * + * @param start + * 脱敏开始下标 + * @param end + * 脱敏结束下标 + * @param value + * value + * @return 脱敏后的value + */ + public String dataDesensitization(int start, int end, String value) { + char[] chars; + int i; + // 正常情况 - end在数组长度内 + if (start >= 0 && end + 1 <= value.length()) { + chars = value.toCharArray(); + // 脱敏替换 + for (i = start; i < chars.length && i < end + 1; ++i) { + chars[i] = '*'; + } + return new String(chars); + } else if (start >= 0 && end >= value.length()) { + // 非正常情况 - end在数组长度外 + chars = value.toCharArray(); + for (i = start; i < chars.length; ++i) { + chars[i] = '*'; + } + return new String(chars); + } else { + // 不符要求,不脱敏 + return value; + } + } +} \ No newline at end of file diff --git a/sz-common/sz-common-log/src/main/java/com/sz/logger/utils/YmlUtils.java b/sz-common/sz-common-log/src/main/java/com/sz/logger/utils/YmlUtils.java new file mode 100644 index 0000000..9098161 --- /dev/null +++ b/sz-common/sz-common-log/src/main/java/com/sz/logger/utils/YmlUtils.java @@ -0,0 +1,195 @@ +package com.sz.logger.utils; + +import org.springframework.util.CollectionUtils; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + +import java.io.InputStream; +import java.util.*; + +/** + * !!! 后续此类警徽被移除,将不会做太多优化。 This class will be deprecated in future versions. + */ +public class YmlUtils { + + private YmlUtils() { + throw new IllegalStateException("Utility class"); + } + + /** 默认脱敏配置文件名 - 默认在resources目录下 */ + public static final String PROPERTY_NAME = "logback-desensitize.yml"; + + /** Key:pattern - 单规则 */ + public static final String PATTERN = "pattern"; + + /** Key:patterns - 多规则 */ + public static final String PATTERNS = "patterns"; + + /** Key:open - 是否开启脱敏 */ + public static final String OPEN_FLAG = "open"; + + /** Key:ignore - 是否开启忽略大小写匹配 */ + public static final String IGNORE = "ignore"; + + /** Key:脱敏配置文件头Key */ + public static final String YML_HEAD_KEY = "log-desensitize"; + + /** key:patterns对应key下的规则Key */ + public static final String CUSTOM = "custom"; + + /** Yml脱敏配置文件内容 - Map格式 */ + protected static final Map patternMap; + + public static final DumperOptions OPTIONS = new DumperOptions(); + + static { + OPTIONS.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + patternMap = getYmlByName(PROPERTY_NAME); + } + + /** + * 获取Yml配置文件的内容 - 以Map的格式 + * + * @param fileName + * Yml配置文件名 + * @return 配置信息(Map格式) + */ + private static Map getYmlByName(String fileName) { + if (CollectionUtils.isEmpty(patternMap)) { + Object fromYml = null; + try { + // 获取Yml配置文件的Map对象 + fromYml = getFromYml(fileName, YML_HEAD_KEY); + // LinkedHashMap,如果不是Map类型(比如配置文件里只有log-desensitize=123456),直接返回patternMap本身 + if (fromYml instanceof Map) { + return (Map) fromYml; + } + } catch (Exception e) { + return null; + } + } + return patternMap; + } + + /** + * 通过key获取value从yml配置文件 + * + * @param fileName + * Yml文件名 + * @param key + * key + * @return value或者map本身 + */ + public static Object getFromYml(String fileName, String key) { + // 创建一个Yaml对象 + Yaml yaml = new Yaml(OPTIONS); + // 获得流 + InputStream inputStream = YmlUtils.class.getClassLoader().getResourceAsStream(fileName); + HashMap map = (HashMap) yaml.loadAs(inputStream, HashMap.class); + // 如果map内有值,直接返回key对应的Value,否则返回map本身 + return Objects.nonNull(map) && !map.isEmpty() ? map.get(key) : map; + } + + /** + * 获取key为pattern的值 + * + * @return pattern对应的map,或者null(如pattern=123这种情况) + */ + public static Map getPattern() { + Object pattern = patternMap.get(PATTERN); + if (pattern instanceof Map) { + return (Map) pattern; + } else { + return null; + } + } + + /** + * 获取所有pattern,含key为pattern,key为patterns + * + * @return pattern + */ + public static Map getAllPattern() { + Map allPattern = new HashMap(); + Map pattern = getPattern(); + Map patterns = getPatterns(); + if (!CollectionUtils.isEmpty(patterns)) { + allPattern.putAll(patterns); + } + // 注意:patterns中的key与pattern的key重复,patterns中的不生效(Map无重复Key) + if (!CollectionUtils.isEmpty(pattern)) { + allPattern.putAll(pattern); + } + return allPattern; + } + + /** + * 获取key为patterns的值 + * + * @return patterns对应的map,或者null(如patterns=123这种情况) + */ + public static Map getPatterns() { + Map map = new HashMap(); + Object patterns = patternMap.get(PATTERNS); + // patterns下有多个key的时候(List) + if (patterns instanceof List) { + // 获取key为"patterns"的值(List>) + List> list = (List>) patterns; + if (!CollectionUtils.isEmpty(list)) { + for (Map maps : list) { + assembleMap(map, maps); + } + return map; + } + } + // patterns只有一个key的时候,且非List + if (patterns instanceof Map) { + assembleMap(map, (Map) patterns); + return map; + } else { + return null; + } + } + + /** + * 将patterns中每个key对应的规则按的方式放入map + * + * @param map + * map + * @param patterns + * patterns + */ + private static void assembleMap(Map map, Map patterns) { + // 获取patterns里key值为"key"的值(脱敏关键字) + Object key = patterns.get("key"); + if (key instanceof String) { + // 清除空格 + String keyWords = ((String) key).replace(" ", ""); + // 以逗号分隔出一个key数组 + String[] keyArr = keyWords.split(","); + for (String keyStr : keyArr) { + map.put(keyStr, patterns.get(CUSTOM)); + } + } + } + + /** + * 是否开启脱敏,默认不开启 + * + * @return 是否开启脱敏 + */ + public static Boolean getOpen() { + Object flag = patternMap.get(OPEN_FLAG); + return flag instanceof Boolean ? (Boolean) flag : false; + } + + /** + * 是否忽略大小写匹配,默认开启 + * + * @return 是否忽略大小写匹配 + */ + public static Boolean getIgnore() { + Object flag = patternMap.get(IGNORE); + return flag instanceof Boolean ? (Boolean) flag : true; + } +} diff --git a/sz-common/sz-common-log/src/main/resources/logback-desensitize.yml b/sz-common/sz-common-log/src/main/resources/logback-desensitize.yml new file mode 100644 index 0000000..b770c8d --- /dev/null +++ b/sz-common/sz-common-log/src/main/resources/logback-desensitize.yml @@ -0,0 +1,53 @@ +# 日志脱敏 +log-desensitize: + # 是否忽略大小写匹配,默认为true + ignore: true + # 是否开启脱敏,默认为false + open: true + # pattern下的key/value为固定脱敏规则 + pattern: + # 邮箱 - @前第4-7位脱敏 + email: "@>(4,7)" + # qq邮箱 - @后1-3位脱敏 + qqemail: "@<(1,3)" + # 姓名 - 姓脱敏,如*杰伦 + name: 1,1 + # 密码 - 所有需要完全脱敏的都可以使用内置的password + password: password + pwd: password + patterns: + # 身份证号,key后面的字段都可以匹配以下规则(用逗号分隔) + - key: identity,idcard + # 定义规则的标识 + custom: + # defaultRegex表示使用组件内置的规则:identity表示身份证号 - 内置的18/15位 + - defaultRegex: identity + position: 9,13 + # 内置的other表示如果其他规则都无法匹配到,则按该规则处理 + - defaultRegex: other + position: 9,10 + # 电话号码,key后面的字段都可以匹配以下规则(用逗号分隔) + - key: phone,cellphone,mobile + custom: + # 手机号 - 内置的11位手机匹配规则 + - defaultRegex: phone + position: 4,7 + # 自定义正则匹配表达式:座机号(带区号,号码七位|八位) + - customRegex: "^0[0-9]{2,3}-[0-9]{7,8}" + # -后面的1-4位脱敏 + position: "-<(1,4)" + # 自定义正则匹配表达式:座机号(不带区号) + - customRegex: "^[0-9]{7,8}" + position: 3,5 + # 内置的other表示如果其他规则都无法匹配到,则按该规则处理 + - defaultRegex: other + position: 1,3 + - key: pwd + custom: + - defaultRegex: password + position: 1,10 + # 这种方式不太推荐 - 一旦匹配不上,就不会脱敏 +# - key: localMobile +# custom: +# customRegex: "^0[0-9]{2,3}-[0-9]{7,8}" +# position: 1,3 \ No newline at end of file diff --git a/sz-common/sz-common-log/src/main/resources/logback-spring.xml b/sz-common/sz-common-log/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..14b7f49 --- /dev/null +++ b/sz-common/sz-common-log/src/main/resources/logback-spring.xml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${LOG_PATH}/app.log + + + ${CONSOLE_LOG_PATTERN_SIMPLE} + utf8 + + + + INFO + + ACCEPT + + DENY + + + + + ${LOG_PATH}/app.log.%d{yyyy-MM-dd}.%i.log + + ${MAX_HISTORY} + + ${MAX_FILE_SIZE} + + ${TOTAL_SIZE_CAP} + + + + + ${LOG_PATH}/warn.log + + + ${CONSOLE_LOG_PATTERN_SIMPLE} + utf8 + + + + + ${LOG_PATH}/warn.%d{yyyy-MM-dd}.%i.log + + 60 + + 50MB + + 500MB + + + + + WARN + + ACCEPT + + DENY + + + + + ${LOG_PATH}/error.log + + + ${CONSOLE_LOG_PATTERN_SIMPLE} + utf8 + + + + + ${LOG_PATH}/error.%d{yyyy-MM-dd}.%i.log + + ${MAX_HISTORY} + + ${MAX_FILE_SIZE} + + ${TOTAL_SIZE_CAP} + + + + ERROR + + + + + + + ${CONSOLE_LOG_PATTERN} + utf8 + + + + + ${LOG_PATH}/http-topic.log + + + ${CONSOLE_LOG_PATTERN_SIMPLE} + utf8 + + + + + ${LOG_PATH}/http-topic.%d{yyyy-MM-dd}.%i.log + + ${MAX_HISTORY} + + ${MAX_FILE_SIZE} + + ${TOTAL_SIZE_CAP} + + + + + + + + + + + + + + + + + + + + + diff --git a/sz-common/sz-common-mq/pom.xml b/sz-common/sz-common-mq/pom.xml new file mode 100644 index 0000000..aeeab40 --- /dev/null +++ b/sz-common/sz-common-mq/pom.xml @@ -0,0 +1,15 @@ + + + + sz-common + com.sz + ${revision} + + 4.0.0 + + sz-common-mq + + + \ No newline at end of file diff --git a/sz-common/sz-common-oss/pom.xml b/sz-common/sz-common-oss/pom.xml new file mode 100644 index 0000000..1fe2a95 --- /dev/null +++ b/sz-common/sz-common-oss/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + com.sz + sz-common + ${revision} + + + com.sz.oss + sz-common-oss + + + + org.springframework.boot + spring-boot-starter-web + provided + true + + + com.sz + sz-common-core + ${revision} + provided + true + + + software.amazon.awssdk + s3 + + + software.amazon.awssdk.crt + aws-crt + + + software.amazon.awssdk + s3-transfer-manager + + + + \ No newline at end of file diff --git a/sz-common/sz-common-oss/src/main/java/com/sz/oss/FileNamingEnum.java b/sz-common/sz-common-oss/src/main/java/com/sz/oss/FileNamingEnum.java new file mode 100644 index 0000000..d4b3ab5 --- /dev/null +++ b/sz-common/sz-common-oss/src/main/java/com/sz/oss/FileNamingEnum.java @@ -0,0 +1,17 @@ +package com.sz.oss; + +/** + * 文件命名方式 + * + * @author sz + * @since 2024/11/14 10:52 + */ +public enum FileNamingEnum { + /* 每个文件都将被分配一个唯一的 UUID,这有助于在系统中精确标识文件,避免任何命名冲突。 */ + UUID, + /* + * 优先使用文件的原始名称,以保持其直观性和易于识别。如果出现文件名冲突,将通过添加时间戳(时分秒.毫秒,eg:162615.587)来解决, + * 确保每个文件名的唯一性。 + */ + ORIGINAL +} diff --git a/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssClient.java b/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssClient.java new file mode 100644 index 0000000..f988965 --- /dev/null +++ b/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssClient.java @@ -0,0 +1,357 @@ +package com.sz.oss; + +import com.sz.core.common.entity.UploadResult; +import com.sz.core.util.FileUtils; +import com.sz.core.util.StringUtils; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.core.async.AsyncResponseTransformer; +import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.GetObjectRequest; +import software.amazon.awssdk.services.s3.presigner.S3Presigner; +import software.amazon.awssdk.transfer.s3.S3TransferManager; +import software.amazon.awssdk.transfer.s3.model.*; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author sz + * @since 2024/11/12 14:56 + */ + +@Service +@RequiredArgsConstructor +public class OssClient { + + private final OssProperties properties; + + private final S3Client s3Client; + + private final S3TransferManager transferManager; + + private final S3Presigner s3Presigner; + + private static final Long DEFAULT_EXPIRE_TIME = 3600L; + + private final S3AsyncClient s3AsyncClient; + + private static final String FILE_SEPARATOR = "/"; + + /** + * 上传文件 + * + * @param file + * 文件 + * @param dirTag + * 目录 + * @return 上传结果 + * @throws IOException + * IO异常 + */ + public UploadResult upload(MultipartFile file, String dirTag, String bucket) throws IOException { + FileNamingEnum naming = properties.getNaming(); + String objectName; + String originalFilename = file.getOriginalFilename(); + if (naming.equals(FileNamingEnum.ORIGINAL)) { + objectName = dirTag + generateOriginalFileName(originalFilename); + // 过滤掉#号 + objectName = objectName.replaceAll("#", ""); + if (isFileExists(objectName)) { + String ext = org.springframework.util.StringUtils.getFilenameExtension(objectName); + assert ext != null; + DateTimeFormatter df = DateTimeFormatter.ofPattern("HHmmss.SSS"); // 获取时分秒.毫秒 + String localTime = df.format(LocalDateTime.now()); + objectName = objectName.split("." + ext)[0] + " (" + localTime + ")." + ext; + } + } else { + objectName = dirTag + generateFileName(originalFilename); + // 也建议过滤一次#号,保证一致性 + objectName = objectName.replaceAll("#", ""); + } + return upload(file.getInputStream(), objectName, file.getSize(), file.getContentType(), originalFilename, bucket); + } + + /** + * 上传文件 + * + * @param file + * 文件 + * @param dirTag + * 目录标签 + * @param filename + * 文件名 + * @return 上传结果 + * @throws IOException + * IO异常 + */ + public UploadResult upload(MultipartFile file, String dirTag, String filename, String bucket) throws IOException { + String objectName = dirTag + "/" + filename; + return upload(file.getInputStream(), objectName, file.getSize(), file.getContentType(), file.getOriginalFilename(), bucket); + } + + /** + * 上传文件 + * + * @param inputStream + * 输入流 + * @param objectName + * 对象名(唯一,可包含路径) + * @param size + * 文件大小 + * @param contextType + * 文件类型 + * @param originalFilename + * 原始文件名 + * @return 上传结果 + */ + public UploadResult upload(InputStream inputStream, String objectName, Long size, String contextType, String originalFilename, String bucket) { + try { + BlockingInputStreamAsyncRequestBody body = AsyncRequestBody.forBlockingInputStream(size); + // 构建meta元数据 + Map metaMap = new HashMap<>(); + metaMap.put("original-filename", originalFilename); + metaMap.put("bucket-name", bucket); + Upload upload = transferManager.upload(x -> x.requestBody(body) + .putObjectRequest(y -> y.bucket(bucket).key(objectName).contentType(contextType).metadata(metaMap).build()).build()); + body.writeInputStream(inputStream); + CompletedUpload uploadResult = upload.completionFuture().join(); + String eTag = normalizeETag(uploadResult.response().eTag()); + String url = getUrl(bucket) + "/" + objectName; + return UploadResult.builder().url(url).objectName(objectName).dirTag(getDirTag(objectName)).filename(getFileName(objectName)) + .contextType(contextType).size(size).eTag(eTag).metaData(metaMap).build(); + } catch (Exception e) { + throw new IllegalArgumentException("上传文件失败,Message:[" + e.getMessage() + "]"); + } + } + + /** + * 验证文件是否存在 + * + * @param key + * 文件名 + * @return 是否存在 + */ + public boolean isFileExists(String key) { + try { + s3Client.headObject(b -> b.bucket(properties.getBucketName()).key(key)); + return true; + } catch (Exception e) { + return false; + } + } + + /** + * 获取私有文件链接 + * + * @param objectName + * 对象名(唯一,可包含路径) + * @return 链接 + */ + public String getPrivateUrl(String objectName) { + URL url = s3Presigner.presignGetObject(x -> x.signatureDuration(Duration.ofSeconds(DEFAULT_EXPIRE_TIME)) + .getObjectRequest(y -> y.bucket(properties.getBucketName()).key(objectName).build()).build()).url(); + return url.toString(); + } + + /** + * 获取私有文件链接 + * + * @param objectName + * 对象名(唯一,可包含路径) + * @return 链接 + */ + public String getPrivateUrl(String bucket, String objectName) { + if (bucket.isEmpty()) { + bucket = properties.getBucketName(); + } + String finalBucket = bucket; + URL url = s3Presigner.presignGetObject( + x -> x.signatureDuration(Duration.ofSeconds(DEFAULT_EXPIRE_TIME)).getObjectRequest(y -> y.bucket(finalBucket).key(objectName).build()).build()) + .url(); + return url.toString(); + } + + /** + * 获取私有文件的访问链接。 + *

+ * 该方法生成一个带有签名的私有文件访问链接,允许在指定的有效期内访问存储在 S3 兼容服务中的私有文件。 例如: + * + *

+     * https://your_domain.com/test/user/20241125/6%E5%AD%97%E5%85%B8%E7%AE%A1%E7%90%86.png
+     * ?X-Amz-Algorithm=AWS4-HMAC-SHA256
+     * &X-Amz-Date=20241125T011936Z
+     * &X-Amz-SignedHeaders=host
+     * &X-Amz-Credential=EBPVrHftB014oEKdR9y8%2F20241125%2Fus-east-1%2Fs3%2Faws4_request
+     * &X-Amz-Expires=120
+     * &X-Amz-Signature=41e40237dc426d7a3e000014183219607cd709a799c9133e3ee61a882b2d3642
+     * 
+ * + * @param objectName + * 对象名(唯一,可包含路径),用于指定要访问的文件 + * @param second + * 链接的有效期(秒),决定该链接在多长时间内有效 + * @return 生成的私有文件访问链接 + */ + + public String getPrivateUrl(String objectName, Long second) { + URL url = s3Presigner.presignGetObject(x -> x.signatureDuration(Duration.ofSeconds(second)) + .getObjectRequest(y -> y.bucket(properties.getBucketName()).key(objectName).build()).build()).url(); + return url.toString(); + } + + /** + * 文件下载 + * + * @param objectName + * 对象名(唯一,可包含路径) + * @param outputStream + * 输出流 + */ + public void download(String objectName, OutputStream outputStream) { + try { + // 构建请求 + GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(properties.getBucketName()).key(objectName).build(); + + // 下载对象到内存字节缓冲区 + s3AsyncClient.getObject(getObjectRequest, AsyncResponseTransformer.toBytes()).thenAccept(response -> { + try { + // 写入输出流 + outputStream.write(response.asByteArray()); + outputStream.flush(); + } catch (Exception e) { + throw new IllegalArgumentException("写入输出流失败", e); + } + }).join(); // 同步等待完成 + } catch (Exception e) { + throw new IllegalArgumentException("下载文件失败,Message:[" + e.getMessage() + "]", e); + } + } + + /** + * 文件下载 + * + * @param objectName + * 对象名(唯一,可包含路径) + * @param response + * 响应 + */ + public void download(String objectName, HttpServletResponse response, String showFileName) { + try { + // 构建请求 + GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(properties.getBucketName()).key(objectName).build(); + String filename = showFileName; + if (showFileName.isEmpty()) { + filename = getFileName(objectName); + } + OutputStream os = FileUtils.getOutputStream(response, filename); + // 下载对象到内存字节缓冲区 + s3AsyncClient.getObject(getObjectRequest, AsyncResponseTransformer.toBytes()).thenAccept(responseBytes -> { + try { + + // 写入响应流 + os.write(responseBytes.asByteArray()); + os.flush(); + } catch (IOException e) { + throw new IllegalArgumentException("写入响应失败", e); + } + }).join(); // 同步等待完成 + } catch (Exception e) { + throw new IllegalArgumentException("下载文件失败,Message:[" + e.getMessage() + "]", e); + } + } + + private String getUrl(String bucketName) { + String domain = properties.getDomain(); + String endpoint = properties.getEndpoint(); + // String scheme = properties.isHttps() ? "https" : "http"; + String scheme = properties.getScheme().toString(); + // 非 MinIO 处理 + if (!properties.getProvider().equals(OssProviderEnum.MINIO)) { + if (StringUtils.isNotEmpty(domain)) { + return (domain.startsWith("https://") || domain.startsWith("http://")) ? domain : scheme + domain; + } else { + return scheme + bucketName + "." + endpoint; // eg: https://your_bucket_name.oss-cn-beijing.aliyuncs.com + } + } + if (StringUtils.isNotEmpty(domain)) { + return (domain.startsWith("https://") || domain.startsWith("http://")) ? domain + "/" + bucketName : scheme + domain + "/" + bucketName; + } else { + return scheme + endpoint + "/" + bucketName; + } + } + + /** + * 生成文件名 eg: /20231212/4150e7c6-b92f-419d-b804-0e8be80f5e71.png + * + * @param originalFilename + * 原始文件名 + * @return 文件名 + */ + private String generateFileName(String originalFilename) { + DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd"); + String localTime = df.format(LocalDate.now()); + String pathStr = FILE_SEPARATOR + localTime + FILE_SEPARATOR; + String extension = org.springframework.util.StringUtils.getFilenameExtension(originalFilename); + String fileName = UUID.randomUUID().toString(); + return pathStr + fileName + "." + extension; + } + + /** + * 生成文件名 eg: /20231212/logo.jpg + * + * @param originalFilename + * 原始文件名 + * @return 文件名 + */ + private String generateOriginalFileName(String originalFilename) { + DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd"); + String localTime = df.format(LocalDate.now()); + String pathStr = FILE_SEPARATOR + localTime + FILE_SEPARATOR; + return pathStr + originalFilename; + } + + private String getFileName(String path) { + int lastSlashIndex = path.lastIndexOf('/'); + return (lastSlashIndex != -1) ? path.substring(lastSlashIndex + 1) : path; + } + + private String getDirTag(String str) { + if (str == null || str.isEmpty()) { + return str; + } + // 找到第一个'/'的位置 + int index = str.indexOf('/'); + // 如果第一个字符是'/',找到第二个'/'的位置 + if (index == 0) { + index = str.indexOf('/', index + 1); + } + if (index == -1) { + return str; // 如果没有找到'/',返回整个字符串 + } + return str.substring(0, index); + } + + private String normalizeETag(String eTag) { + if (eTag == null || eTag.isEmpty()) { + return eTag; + } + // 替换掉前后的双引号 + return eTag.replaceAll("(^\")|(\"$)", ""); + } + +} \ No newline at end of file diff --git a/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssProperties.java b/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssProperties.java new file mode 100644 index 0000000..7d2c942 --- /dev/null +++ b/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssProperties.java @@ -0,0 +1,42 @@ +package com.sz.oss; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author sz + * @since 2024/11/12 14:39 + */ +@Data +@Component +@ConfigurationProperties(prefix = "oss") +public class OssProperties { + + // 服务提供商 + private OssProviderEnum provider = OssProviderEnum.MINIO; + + // 访问站点 + private String endpoint; + + // access_key + private String accessKey; + + // secret_key + private String secretKey; + + // 存储空间 + private String bucketName; + + // 富文本存储空间 + private String richtextBucketName; + + // 域名 + private String domain; + + // 文件名称方式 + private FileNamingEnum naming = FileNamingEnum.ORIGINAL; + + private SchemeEnum scheme = SchemeEnum.https; + +} diff --git a/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssProviderEnum.java b/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssProviderEnum.java new file mode 100644 index 0000000..57acf86 --- /dev/null +++ b/sz-common/sz-common-oss/src/main/java/com/sz/oss/OssProviderEnum.java @@ -0,0 +1,9 @@ +package com.sz.oss; + +/** + * @author sz + * @since 2024/11/12 14:49 + */ +public enum OssProviderEnum { + ALIYUN, QINIU, TENCENT, MINIO +} diff --git a/sz-common/sz-common-oss/src/main/java/com/sz/oss/S3Configuration.java b/sz-common/sz-common-oss/src/main/java/com/sz/oss/S3Configuration.java new file mode 100644 index 0000000..7a62666 --- /dev/null +++ b/sz-common/sz-common-oss/src/main/java/com/sz/oss/S3Configuration.java @@ -0,0 +1,100 @@ +package com.sz.oss; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.presigner.S3Presigner; +import software.amazon.awssdk.transfer.s3.S3TransferManager; + +import java.net.URI; + +/** + * S3AsyncConfiguration + * + * @author sz + * @since 2024/11/12 15:16 + */ +@Configuration +@RequiredArgsConstructor +public class S3Configuration { + + private final OssProperties ossProperties; + + @Bean + public S3AsyncClient s3AsyncClient() { + StaticCredentialsProvider credentialsProvider = credentialsProvider(); + return S3AsyncClient.crtBuilder().region(getRegion()).forcePathStyle(isPathStyle()).credentialsProvider(credentialsProvider).endpointOverride(getUri()) + .targetThroughputInGbps(20.0).checksumValidationEnabled(false).build(); + } + + @Bean + public S3Client s3Client() { + StaticCredentialsProvider credentialsProvider = credentialsProvider(); + return S3Client.builder().region(getRegion()).forcePathStyle(isPathStyle()).credentialsProvider(credentialsProvider).endpointOverride(getUri()).build(); + } + + @Bean + public S3TransferManager s3TransferManager(S3AsyncClient s3AsyncClient) { + return S3TransferManager.builder().s3Client(s3AsyncClient).build(); + } + + @Bean + public S3Presigner s3Presigner() { + software.amazon.awssdk.services.s3.S3Configuration config = software.amazon.awssdk.services.s3.S3Configuration.builder() + .pathStyleAccessEnabled(isPathStyle()).chunkedEncodingEnabled(false).build(); + return S3Presigner.builder().region(getRegion()).credentialsProvider(credentialsProvider()).endpointOverride(getUri()).serviceConfiguration(config) + .build(); + } + + private Region getRegion() { + return Region.US_EAST_1; + } + + private StaticCredentialsProvider credentialsProvider() { + return StaticCredentialsProvider.create(AwsBasicCredentials.create(ossProperties.getAccessKey(), ossProperties.getSecretKey())); + } + /** + * 强制使用路径风格访问存储桶和对象的参数 `forcePathStyle` 在 MinIO 中的作用。 + * + * 在 S3 兼容 API 中,访问存储桶和对象有两种方式: + * + *
    + *
  • 虚拟主机风格:存储桶名称作为 URL 的一部分,例如: + * http://bucket-name.s3.amazonaws.com/object-name。 此方式要求存储桶名称符合 + * DNS 规则。
  • + *
  • 路径风格:存储桶名称作为 URL 路径的一部分,例如: + * http://s3.amazonaws.com/bucket-name/object-name。 此方式不要求存储桶名称符合 + * DNS 规则。
  • + *
+ * + * 使用 MinIO 作为 S3 兼容服务时,如果存储桶名称不符合 DNS 规则, 或希望强制使用路径风格的 URL,可以将 `forcePathStyle` + * 参数设置为 `true`。 这样,即使存储桶名称不符合 DNS 规则,也可以通过路径风格访问存储桶和对象。 + * + *

+ * 例如,当 `forcePathStyle` 设置为 `true` 时,访问对象的 URL 格式应为: + *

+ *
    + *
  • http://minio-server:9000/bucket-name/object-name
  • + *
  • 而非:http://bucket-name.minio-server:9000/object-name
  • + *
+ * + * 在某些客户端库或工具中,明确设置 `forcePathStyle` 参数对于确保与 MinIO 的兼容性非常重要, 特别是在存储桶名称不符合 DNS + * 命名规则时。 + */ + private boolean isPathStyle() { + return ossProperties.getProvider().equals(OssProviderEnum.MINIO); + } + + private URI getUri() { + if (ossProperties.getEndpoint().startsWith("https://") || ossProperties.getEndpoint().startsWith("http://")) { + return URI.create(ossProperties.getEndpoint()); + } + String scheme = ossProperties.getScheme().toString(); + return URI.create(scheme + "://" + ossProperties.getEndpoint()); + } +} diff --git a/sz-common/sz-common-oss/src/main/java/com/sz/oss/SchemeEnum.java b/sz-common/sz-common-oss/src/main/java/com/sz/oss/SchemeEnum.java new file mode 100644 index 0000000..d34ff73 --- /dev/null +++ b/sz-common/sz-common-oss/src/main/java/com/sz/oss/SchemeEnum.java @@ -0,0 +1,5 @@ +package com.sz.oss; + +public enum SchemeEnum { + http, https +} diff --git a/sz-common/sz-common-oss/src/main/resources/application.yml b/sz-common/sz-common-oss/src/main/resources/application.yml new file mode 100644 index 0000000..6364c98 --- /dev/null +++ b/sz-common/sz-common-oss/src/main/resources/application.yml @@ -0,0 +1,11 @@ +oss: + # 兼容S3协议的厂商 (理论上说所有兼容S3协议的OSS厂商都可以使用) + provider: minio + endpoint: http://192.168.56.101:9001/ + accessKey: NhQlOFYcyXiQm40DpW56 + secretKey: O1q6YRp79cTeNrtHT8yHXgcFWcOTDJNpKpRsYMzp + # bucket + bucketName: sz-boot-parent-local + # 自定义域名 + domain: http://192.168.56.101:9001/ + is-https: false \ No newline at end of file diff --git a/sz-common/sz-common-security/pom.xml b/sz-common/sz-common-security/pom.xml new file mode 100644 index 0000000..e92413b --- /dev/null +++ b/sz-common/sz-common-security/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + com.sz + sz-common + ${revision} + + + sz-common-security + + + + com.sz + sz-common-core + ${revision} + provided + true + + + com.sz + sz-common-db-redis + ${revision} + provided + true + + + org.springframework.boot + spring-boot-starter-web + provided + true + + + cn.dev33 + sa-token-spring-boot3-starter + + + cn.dev33 + sa-token-jwt + + + cn.hutool + hutool-jwt + + + + + + cn.hutool + hutool-jwt + + + cn.dev33 + sa-token-redis-jackson + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + provided + true + + + + + + \ No newline at end of file diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/config/CorsConfig.java b/sz-common/sz-common-security/src/main/java/com/sz/security/config/CorsConfig.java new file mode 100644 index 0000000..dfd5eea --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/config/CorsConfig.java @@ -0,0 +1,57 @@ +package com.sz.security.config; + +import com.sz.security.core.CorsProperties; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * CorsConfig + * + * @author sz + * @since 2024/2/2 8:31 + */ +@Configuration +@RequiredArgsConstructor +public class CorsConfig { + + private final CorsProperties corsProperties; + + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", buildConfig()); + return new CorsFilter(source); + } + + @Bean + public FilterRegistrationBean corsFilterFilterRegistrationBean() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(corsFilter()); + registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); + return registrationBean; + } + + private CorsConfiguration buildConfig() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + // 在生产环境中,推荐将 origin 设置为准确的域名,而不是使用 * + CopyOnWriteArrayList allowedOrigins = corsProperties.getAllowedOrigins(); + if (allowedOrigins.contains("*")) { + corsConfiguration.addAllowedOrigin(CorsConfiguration.ALL); + } else { + for (String origin : allowedOrigins) { + corsConfiguration.addAllowedOrigin(origin); + } + } + corsConfiguration.addAllowedHeader(CorsConfiguration.ALL); + corsConfiguration.addAllowedMethod(CorsConfiguration.ALL); + corsConfiguration.addExposedHeader(CorsConfiguration.ALL); + corsConfiguration.setMaxAge(3600L); + return corsConfiguration; + } +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/config/SaTokenConfig.java b/sz-common/sz-common-security/src/main/java/com/sz/security/config/SaTokenConfig.java new file mode 100644 index 0000000..0ea63c0 --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/config/SaTokenConfig.java @@ -0,0 +1,61 @@ +package com.sz.security.config; + +import cn.dev33.satoken.jwt.StpLogicJwtForSimple; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.stp.StpLogic; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; +import com.sz.security.core.MySaCheckPermissionHandler; +import com.sz.security.core.interceptor.MySaInterceptor; +import com.sz.security.pojo.WhitelistProperties; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.ArrayList; + +/** + * @author sz + * @since 2024/1/22 16:36 + */ + +@Slf4j +@Configuration +@RequiredArgsConstructor +public class SaTokenConfig implements WebMvcConfigurer { + + private final WhitelistProperties whitelistProperties; + + @Bean + public StpLogic getStpLogicJwt() { + // Sa-Token 整合 jwt (简单模式) + return new StpLogicJwtForSimple(); + } + + /** + * 注册 Sa-Token 路由拦截器 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册自定义 @SaCheckPermission 注解Handler; + SaAnnotationStrategy.instance.registerAnnotationHandler(new MySaCheckPermissionHandler()); + // 注册 自定义 MySaInterceptor 拦截器 + registry.addInterceptor(new MySaInterceptor(handler -> SaRouter.match("/**", r -> StpUtil.checkLogin()) // 这里可以结合自己业务改造 + )).addPathPatterns("/**").excludePathPatterns(new ArrayList<>(whitelistProperties.getWhitelist())) + .excludePathPatterns("/save/**") + .excludePathPatterns("/algorithm-task/**"); + } + + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // D:/work/images/save/1.jpg + registry.addResourceHandler("/save/**") + .addResourceLocations("file:D:/work/images/"); + } + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/controller/AuthController.java b/sz-common/sz-common-security/src/main/java/com/sz/security/controller/AuthController.java new file mode 100644 index 0000000..3d5ee4a --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/controller/AuthController.java @@ -0,0 +1,49 @@ +package com.sz.security.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.stp.StpUtil; +import com.sz.core.common.annotation.DebounceIgnore; +import com.sz.core.common.entity.ApiResult; +import com.sz.security.pojo.LoginInfo; +import com.sz.security.pojo.LoginVO; +import com.sz.security.service.AuthService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +/** + * 认证Controller。 + * + * @author sz + * @since 2023/12/25 + */ + +@Tag(name = "认证") +@RestController +@RequestMapping("/auth") +@RequiredArgsConstructor +@Slf4j +public class AuthController { + + private final AuthService authService; + + @SaIgnore + @DebounceIgnore + @Operation(summary = "登录") + @PostMapping("login") + public ApiResult login(@RequestBody LoginInfo loginInfo) { + return ApiResult.success(authService.loginClient(loginInfo)); + } + + @Operation(summary = "登出") + @PostMapping("logout") + public ApiResult logout() { + // 注意执行顺序,最后再执行logout + StpUtil.getTokenSession().logout(); // 清除缓存session + StpUtil.logout(); // 退出登录 + return ApiResult.success(); + } + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/core/CorsProperties.java b/sz-common/sz-common-security/src/main/java/com/sz/security/core/CorsProperties.java new file mode 100644 index 0000000..cf230e1 --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/core/CorsProperties.java @@ -0,0 +1,21 @@ +package com.sz.security.core; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author sz + * @since 2025/1/6 10:02 + * @version 1.0 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "sz.cors") +public class CorsProperties { + + private CopyOnWriteArrayList allowedOrigins; + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/core/MySaCheckPermissionHandler.java b/sz-common/sz-common-security/src/main/java/com/sz/security/core/MySaCheckPermissionHandler.java new file mode 100644 index 0000000..a68545e --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/core/MySaCheckPermissionHandler.java @@ -0,0 +1,61 @@ +package com.sz.security.core; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface; +import cn.dev33.satoken.exception.NotPermissionException; +import cn.dev33.satoken.stp.StpLogic; +import cn.dev33.satoken.util.SaFoxUtil; +import com.sz.security.core.util.LoginUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +/** + * @author sz + * @since 2024/10/9 14:16 + * @version 1.0 + */ +public class MySaCheckPermissionHandler implements SaAnnotationHandlerInterface { + + @Override + public Class getHandlerAnnotationClass() { + return SaCheckPermission.class; + } + + @Override + public void check(Annotation at, AnnotatedElement element) { + SaAnnotationHandlerInterface.super.check(at, element); + } + + @Override + public void checkMethod(SaCheckPermission at, AnnotatedElement element) { + doCheck(at.type(), at.value(), at.mode(), at.orRole()); + } + + public static void doCheck(String type, String[] value, SaMode mode, String[] orRole) { + StpLogic stpLogic = SaManager.getStpLogic(type, false); + try { + if (mode == SaMode.AND) { + stpLogic.checkPermissionAnd(value); + } else { + stpLogic.checkPermissionOr(value); + } + } catch (NotPermissionException e) { + // Start------------以下是自定义代码------- + if (LoginUtils.isSuperAdmin()) + return; + // End------------以上是自定义代码------- + // 权限认证校验未通过,再开始角色认证校验 + for (String role : orRole) { + String[] rArr = SaFoxUtil.convertStringToArray(role); + // 某一项 role 认证通过,则可以提前退出了,代表通过 + if (stpLogic.hasRoleAnd(rArr)) { + return; + } + } + throw e; + } + } +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/core/exception/SaExceptionHandler.java b/sz-common/sz-common-security/src/main/java/com/sz/security/core/exception/SaExceptionHandler.java new file mode 100644 index 0000000..b22bd6e --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/core/exception/SaExceptionHandler.java @@ -0,0 +1,47 @@ +package com.sz.security.core.exception; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.exception.NotPermissionException; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.enums.CommonResponseEnum; +import org.springframework.core.annotation.Order; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * @author sz + * @since 2024/2/4 15:42 + */ +@Order(Integer.MIN_VALUE) +@RestControllerAdvice +public class SaExceptionHandler { + + @ExceptionHandler(NotLoginException.class) + public ApiResult handlerNotLoginException(NotLoginException e) { + String message; + if (e.getType().equals(NotLoginException.NOT_TOKEN)) { + message = "未能读取到有效 token"; + } else if (e.getType().equals(NotLoginException.INVALID_TOKEN) || e.getType().equals(NotLoginException.TOKEN_FREEZE)) { + message = "您的登录信息已过期,请重新登录以继续访问。"; + // [ do something ...] websocket close + // sendWsClose(); + } else if (e.getType().equals(NotLoginException.TOKEN_TIMEOUT)) { + message = "token 已过期"; + } else if (e.getType().equals(NotLoginException.BE_REPLACED)) { + message = "token 已被顶下线"; + } else if (e.getType().equals(NotLoginException.KICK_OUT)) { + message = "token 已被踢下线"; + } else if (e.getType().equals(NotLoginException.NO_PREFIX)) { + message = "未按照指定前缀提交 token"; + } else { + message = "当前会话未登录"; + } + return new ApiResult<>(CommonResponseEnum.INVALID_TOKEN.getCodePrefixEnum().getPrefix() + CommonResponseEnum.INVALID_TOKEN.getCode(), message); + } + + @ExceptionHandler(NotPermissionException.class) + public ApiResult handlerNotPermissionException(NotPermissionException e) { + return ApiResult.error(CommonResponseEnum.INVALID_PERMISSION); + } + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/core/interceptor/MySaInterceptor.java b/sz-common/sz-common-security/src/main/java/com/sz/security/core/interceptor/MySaInterceptor.java new file mode 100644 index 0000000..b9019b7 --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/core/interceptor/MySaInterceptor.java @@ -0,0 +1,77 @@ +package com.sz.security.core.interceptor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.exception.BackResultException; +import cn.dev33.satoken.exception.StopMatchException; +import cn.dev33.satoken.fun.SaParamFunction; +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; +import com.sz.core.common.entity.ControlPermissions; +import com.sz.core.datascope.ControlThreadLocal; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.lang.NonNull; +import org.springframework.web.method.HandlerMethod; + +import java.lang.reflect.Method; + +/** + * @author sz + * @since 2024/7/9 14:29 + */ +public class MySaInterceptor extends SaInterceptor { + + public MySaInterceptor() { + } + + public MySaInterceptor(SaParamFunction auth) { + super(auth); + } + + @Override + @SuppressWarnings("all") + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + try { + // 这里必须确保 handler 是 HandlerMethod 类型时,才能进行注解鉴权 + if (isAnnotation && handler instanceof HandlerMethod) { + Method method = ((HandlerMethod) handler).getMethod(); + SaAnnotationStrategy.instance.checkMethodAnnotation.accept(method); + + // 如果此 Method 标注了 @SaCheckPermission,则进行(数据权限)校验 + SaCheckPermission checkPermission = (SaCheckPermission) SaAnnotationStrategy.instance.getAnnotation.apply(method, SaCheckPermission.class); + if (checkPermission != null) { + ControlThreadLocal.set(new ControlPermissions(checkPermission.value(), checkPermission.mode().name())); + } + } + + // Auth 校验 + auth.run(handler); + + } catch (StopMatchException e) { + // StopMatchException 异常代表:停止匹配,进入Controller + ControlThreadLocal.clearDataScope(); + } catch (BackResultException e) { + ControlThreadLocal.clearDataScope(); + // BackResultException 异常代表:停止匹配,向前端输出结果 + // 请注意此处默认 Content-Type 为 text/plain,如果需要返回 JSON 信息,需要在 back 前自行设置 Content-Type + // 为 application/json + // 例如:SaHolder.getResponse().setHeader("Content-Type", + // "application/json;charset=UTF-8"); + if (response.getContentType() == null) { + response.setContentType("text/plain; charset=utf-8"); + } + response.getWriter().print(e.getMessage()); + return false; + } + + // 通过验证 + return true; + } + + @Override + public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) + throws Exception { + ControlThreadLocal.clearDataScope(); + super.afterCompletion(request, response, handler, ex); + } +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/core/listener/CustomUserListener.java b/sz-common/sz-common-security/src/main/java/com/sz/security/core/listener/CustomUserListener.java new file mode 100644 index 0000000..452b0c2 --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/core/listener/CustomUserListener.java @@ -0,0 +1,93 @@ +package com.sz.security.core.listener; + +import cn.dev33.satoken.listener.SaTokenListener; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * @author sz + * @version 1.0 + * @since 2024/1/22 16:47 + */ +@Component +@Slf4j +public class CustomUserListener implements SaTokenListener { + + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) { + log.info("user doLogin, userId:{}, token:{}, loginParameter: {}", loginId, tokenValue, loginParameter.toString()); + } + + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); + } + + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); + } + + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被封禁时触发 + */ + @Override + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { + log.info("user doDisable, userId:{}, service:{}", loginId, service); + } + + /** + * 每次被解封时触发 + */ + @Override + public void doUntieDisable(String loginType, Object loginId, String service) { + log.info("user doUntieDisable, userId:{}, service:{}", loginId, service); + } + + /** + * 每次打开二级认证时触发 + */ + @Override + public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { + log.info("user doOpenSafe, token:{}, service:{}", tokenValue, service); + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCloseSafe(String loginType, String tokenValue, String service) { + log.info("user doCloseSafe, token:{}, service:{}", tokenValue, service); + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCreateSession(String id) { + log.info("user doCreateSession, id:{}", id); + } + + /** + * 每次注销Session时触发 + */ + @Override + public void doLogoutSession(String id) { + log.info("user doLogoutSession, id:{}", id); + } + + /** + * 每次 Token 续期时触发 + */ + @Override + public void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout) { + log.info("user doRenewTimeout, loginId:{}, token:{}, timeout:{}", loginId, tokenValue, timeout); + } + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/core/util/LoginUtils.java b/sz-common/sz-common-security/src/main/java/com/sz/security/core/util/LoginUtils.java new file mode 100644 index 0000000..22579ba --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/core/util/LoginUtils.java @@ -0,0 +1,89 @@ +package com.sz.security.core.util; + +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.util.ObjectUtil; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.LoginUser; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +/** + * @author sz + * @since 2024/1/24 9:38 + * @version 1.0 + */ +@Slf4j +public class LoginUtils { + + private LoginUtils() { + throw new IllegalStateException("Utility class"); + } + + public static final String USER_KEY = "loginUser"; + + public static void performLogin(LoginUser loginUser, SaLoginParameter model, Map extraData) { + model = ObjectUtil.defaultIfNull(model, new SaLoginParameter()); + model.setExtraData(extraData); + // 登录,生成token + StpUtil.login(loginUser.getUserInfo().getId(), model); + StpUtil.getTokenSession().set(USER_KEY, loginUser); + // 使用全局配置而不使用model独立配置时间的问题 + StpUtil.getTokenSession().updateTimeout(model.getTimeout()); + StpUtil.getSession().updateTimeout(model.getTimeout()); + } + + public static void performMiniLogin(Object userId, Object loginUser, SaLoginParameter model, Map extraData) { + model = ObjectUtil.defaultIfNull(model, new SaLoginParameter()); + model.setExtraData(extraData); + // 登录,生成token + StpUtil.login(userId, model); + StpUtil.getTokenSession().set(USER_KEY, loginUser); + // 使用全局配置而不使用model独立配置时间的问题 + StpUtil.getTokenSession().updateTimeout(model.getTimeout()); + StpUtil.getSession().updateTimeout(model.getTimeout()); + } + + /** + * 获取用户 + */ + public static LoginUser getLoginUser() { + SaSession session = StpUtil.getTokenSession(); + if (ObjectUtil.isNull(session)) { + return null; + } + return (LoginUser) session.get(USER_KEY); + } + + /** + * 根据token获取用户信息 + * + * @param token + * token + * @return 用户信息 + */ + public static LoginUser getLoginUser(String token) { + SaSession session = StpUtil.getTokenSessionByToken(token); + if (ObjectUtil.isNull(session)) { + return null; + } + return (LoginUser) session.get(USER_KEY); + } + + /** + * 是否是超级管理员 + * + * @return 是否是超级管理员 + */ + public static boolean isSuperAdmin() { + if (!StpUtil.isLogin()) + return false; + LoginUser loginUser = getLoginUser(); + if (loginUser == null) + return false; + return loginUser.getRoles().contains(GlobalConstant.SUPER_ROLE); + } + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/ClientVO.java b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/ClientVO.java new file mode 100644 index 0000000..c0f48cd --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/ClientVO.java @@ -0,0 +1,50 @@ +package com.sz.security.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + *

+ * SysClient查询返回 + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Data +@Schema(description = "SysClient返回vo") +public class ClientVO { + + @Schema(description = "客户端id") + private String clientId; + + @Schema(description = "客户端key") + private String clientKey; + + @Schema(description = "客户端秘钥") + private String clientSecret; + + @Schema(description = "授权类型数组") + private List grantTypeCdList; + + @Schema(description = "授权类型") + private String grantTypeCd; + + @Schema(description = "设备类型") + private String deviceTypeCd; + + @Schema(description = "token活跃超时时间") + private Integer activeTimeout; + + @Schema(description = "token固定超时") + private Integer timeout; + + @Schema(description = "状态") + private String clientStatusCd; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/LoginInfo.java b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/LoginInfo.java new file mode 100644 index 0000000..54afcd8 --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/LoginInfo.java @@ -0,0 +1,37 @@ +package com.sz.security.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 登录信息 + * + * @author sz + * @since 2024/1/22 9:38 + * @version 1.0 + */ +@Data +public class LoginInfo { + + @Schema(description = "用户名") + private String username; + + @Schema(description = "密码, 防止明文传输使用AES-GCM加密") + private String password; + + @Schema(description = "客户端id", requiredMode = Schema.RequiredMode.REQUIRED) + private String clientId; + + @Schema(description = "授权类型", requiredMode = Schema.RequiredMode.REQUIRED) + private String grantType; + + @Schema(description = "微信小程序登录code") + private String code; + + @Schema(description = "请求id") + private String requestId; + + @Schema(description = "iv向量") + private String iv; + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/LoginVO.java b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/LoginVO.java new file mode 100644 index 0000000..d49be8c --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/LoginVO.java @@ -0,0 +1,24 @@ +package com.sz.security.pojo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2024/1/22 15:35 + * @version 1.0 + */ +@Data +@Schema(description = "通用用户返回") +public class LoginVO { + + @Schema(description = "access_token") + private String accessToken; + + @Schema(description = "授权令牌 access_token 的有效期") + private Long expireIn; + + @Schema(description = "用户信息") + private Object userInfo; + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/WhitelistProperties.java b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/WhitelistProperties.java new file mode 100644 index 0000000..eceee11 --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/pojo/WhitelistProperties.java @@ -0,0 +1,16 @@ +package com.sz.security.pojo; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CopyOnWriteArraySet; + +@Data +@Component +@ConfigurationProperties(prefix = "router") +public class WhitelistProperties { + + private CopyOnWriteArraySet whitelist; + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/service/AuthService.java b/sz-common/sz-common-security/src/main/java/com/sz/security/service/AuthService.java new file mode 100644 index 0000000..4c4551f --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/service/AuthService.java @@ -0,0 +1,16 @@ +package com.sz.security.service; + +import com.sz.security.pojo.LoginInfo; +import com.sz.security.pojo.LoginVO; + +/** + * @author sz + * @since 2024/1/22 17:24 + * @version 1.0 + */ +public interface AuthService { + + LoginVO loginClient(LoginInfo info); + + void kickOut(Long userId); +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/service/ClientService.java b/sz-common/sz-common-security/src/main/java/com/sz/security/service/ClientService.java new file mode 100644 index 0000000..4350bda --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/service/ClientService.java @@ -0,0 +1,14 @@ +package com.sz.security.service; + +import com.sz.security.pojo.ClientVO; + +/** + * @author sz + * @since 2024/2/18 8:42 + * @version 1.0 + */ +public interface ClientService { + + ClientVO getClientByClientId(Object id); + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/service/IAuthStrategy.java b/sz-common/sz-common-security/src/main/java/com/sz/security/service/IAuthStrategy.java new file mode 100644 index 0000000..7b3e20e --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/service/IAuthStrategy.java @@ -0,0 +1,30 @@ +package com.sz.security.service; + +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.security.pojo.ClientVO; +import com.sz.security.pojo.LoginInfo; +import com.sz.security.pojo.LoginVO; + +/** + * 策略接口 + * + * @author sz + * @since 2024/1/23 9:38 + * @version 1.0 + */ +public interface IAuthStrategy { + + String BASE_NAME = "AuthStrategy"; + + static LoginVO login(LoginInfo info, ClientVO client, String grantType) { + // 授权类型和客户端id + String beanName = grantType + BASE_NAME; + CommonResponseEnum.INVALID.message("无效的授权类型").assertFalse(SpringApplicationContextUtils.getInstance().containsBean(beanName)); + IAuthStrategy instance = SpringApplicationContextUtils.getInstance().getBean(beanName); + return instance.login(info, client); + } + + LoginVO login(LoginInfo info, ClientVO client); + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/service/impl/AuthServiceImpl.java b/sz-common/sz-common-security/src/main/java/com/sz/security/service/impl/AuthServiceImpl.java new file mode 100644 index 0000000..7d3ed72 --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/service/impl/AuthServiceImpl.java @@ -0,0 +1,61 @@ +package com.sz.security.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.redis.WebsocketRedisService; +import com.sz.security.pojo.ClientVO; +import com.sz.security.pojo.LoginInfo; +import com.sz.security.pojo.LoginVO; +import com.sz.security.service.AuthService; +import com.sz.security.service.ClientService; +import com.sz.security.service.IAuthStrategy; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Collections; + +/** + * + * @author sz + * @since 2022-10-01 + */ +@Service +@RequiredArgsConstructor +public class AuthServiceImpl implements AuthService { + + private final WebsocketRedisService websocketRedisService; + + @Override + public LoginVO loginClient(LoginInfo info) { + String clientId = info.getClientId(); + ClientService clientService = SpringApplicationContextUtils.getInstance().getBean(ClientService.class); + ClientVO client = clientService.getClientByClientId(clientId); + // 验证clientId有效性 + CommonResponseEnum.CLIENT_INVALID.assertNull(client); + // 验证client status 有效性 + CommonResponseEnum.CLIENT_BLOCKED.assertTrue(!("1003001").equals(client.getClientStatusCd())); + return IAuthStrategy.login(info, client, info.getGrantType()); + } + + /** + * 强制注销指定用户 + * + * @param id + * 用户id + */ + @Override + public void kickOut(Long id) { + TransferMessage tm = new TransferMessage(); + tm.setToUsers(Collections.singletonList(id + "")); + SocketMessage sb = new SocketMessage(); + sb.setChannel(SocketChannelEnum.KICK_OFF); + tm.setMessage(sb); + websocketRedisService.sendServiceToWs(tm); + StpUtil.logout(id); + } + +} diff --git a/sz-common/sz-common-security/src/main/java/com/sz/security/service/impl/StpInterfaceImpl.java b/sz-common/sz-common-security/src/main/java/com/sz/security/service/impl/StpInterfaceImpl.java new file mode 100644 index 0000000..be81d2f --- /dev/null +++ b/sz-common/sz-common-security/src/main/java/com/sz/security/service/impl/StpInterfaceImpl.java @@ -0,0 +1,36 @@ +package com.sz.security.service.impl; + +import cn.dev33.satoken.stp.StpInterface; +import com.sz.core.common.entity.LoginUser; +import com.sz.security.core.util.LoginUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author sz + * @since 2024/1/26 16:40 + * @version 1.0 + */ +@Order(Integer.MIN_VALUE) +@Component +@RequiredArgsConstructor +public class StpInterfaceImpl implements StpInterface { + + @Override + public List getPermissionList(Object loginId, String loginType) { + LoginUser loginUser = LoginUtils.getLoginUser(); + assert loginUser != null; + return new ArrayList<>(loginUser.getPermissions()); + } + + @Override + public List getRoleList(Object loginId, String loginType) { + LoginUser loginUser = LoginUtils.getLoginUser(); + assert loginUser != null; + return new ArrayList<>(loginUser.getRoles()); + } +} diff --git a/sz-common/sz-common-security/src/main/resources/application.yml b/sz-common/sz-common-security/src/main/resources/application.yml new file mode 100644 index 0000000..3459a90 --- /dev/null +++ b/sz-common/sz-common-security/src/main/resources/application.yml @@ -0,0 +1,15 @@ +router: + whitelist: + - "/v3/api-docs/**" + - "/auth/login" + - "/register" + - "/sys-dict/dict" + - "/doc.html" + - "/webjars/**" + - "/swagger-resources" + - "/favicon.ico" + - "/common/**" + - "/swagger-ui.html" + - "/www/**" + - "/save/**" + - "/algorithm-task/**" \ No newline at end of file diff --git a/sz-common/sz-common-wechat/pom.xml b/sz-common/sz-common-wechat/pom.xml new file mode 100644 index 0000000..d0f9f5f --- /dev/null +++ b/sz-common/sz-common-wechat/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + com.sz + sz-common + ${revision} + + + com.sz.wechat + sz-common-wechat + + + + org.springframework.boot + spring-boot-starter-web + provided + true + + + com.sz + sz-common-core + ${revision} + provided + true + + + com.sz + sz-common-db-redis + ${revision} + provided + true + + + + + \ No newline at end of file diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/WechatApiConstant.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/WechatApiConstant.java new file mode 100644 index 0000000..46fa96e --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/WechatApiConstant.java @@ -0,0 +1,34 @@ +package com.sz.wechat; + +/** + * 微信API常量类 + * + * @author sz + * @since 2024/4/26 9:41 + * @version 1.0 + */ +public class WechatApiConstant { + + private WechatApiConstant() { + throw new IllegalStateException("Utility class"); + } + + public static final String WECHAT_API_BASE_URL = "https://api.weixin.qq.com"; + + // 小程序接口调用凭证 + public static final String WECHAT_TOKEN_URL = WECHAT_API_BASE_URL + "/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={APP_SECRET}"; + + // 小程序登录 + public static final String WECHAT_MINI_LOGIN_URL = WECHAT_API_BASE_URL + + "/sns/jscode2session?appid={APPID}&secret={APP_SECRET}&js_code={JS_CODE}&grant_type=authorization_code&access_token={ACCESS_TOKEN}"; + + // ----------------------- 企业微信 --------------------------- + private static final String WORK_WECHAT_API_BASE_URL = "https://qyapi.weixin.qq.com"; + + // 企业微信接口access_token + public static final String WORK_WECHAT_TOKEN_URL = WORK_WECHAT_API_BASE_URL + "/cgi-bin/gettoken?corpid={CORPID}&corpsecret={CORPSECRET}"; + + // 企业微信发送消息 + public static final String WORK_WECHAT_MESSAGE_SEND_URL = WORK_WECHAT_API_BASE_URL + "/cgi-bin/message/send?access_token={ACCESS_TOKEN}"; + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/WechatProperties.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/WechatProperties.java new file mode 100644 index 0000000..753cdf1 --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/WechatProperties.java @@ -0,0 +1,47 @@ +package com.sz.wechat; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author sz + * @since 2024/4/26 9:23 + * @version 1.0 + */ +@Data +@Component +@ConfigurationProperties(prefix = "sz.wechat") +public class WechatProperties { + + @Schema(description = "小程序开发者配置") + private MiniProgramProperties mini; + + @Schema(description = "企业微信开发者配置") + private WorkProgramProperties work; + + @Data + public static class MiniProgramProperties { + + @Schema(description = "小程序应用ID") + private String appId; + + @Schema(description = "小程序应用密钥") + private String appSecret; + } + + @Data + public static class WorkProgramProperties { + + @Schema(description = "企业ID; 登录企业微信管理后台,位于【我的企业-应用信息】-> 企业ID处获取; 文档:https://developer.work.weixin.qq.com/document/path/90665#corpid") + private String corpId; + + @Schema(description = "企业微信应用密钥; 登录企业微信管理后台,位于【应用管理-应用-自建】-> 创建应用; 文档:https://developer.work.weixin.qq.com/document/path/90665#secret") + private String corpSecret; + + @Schema(description = "企业微信应用凭证; 同上述corpSecret,位于“应用”secret属性的下方; 文档:https://developer.work.weixin.qq.com/document/path/90665#agentid") + private Integer agentId; + + } +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/mini/LoginInfoResult.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/mini/LoginInfoResult.java new file mode 100644 index 0000000..436165e --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/mini/LoginInfoResult.java @@ -0,0 +1,23 @@ +package com.sz.wechat.mini; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.sz.wechat.pojo.ErrorMessage; +import lombok.Data; + +/** + * @author sz + * @since 2024/4/26 11:27 + * @version 1.0 + */ +@Data +public class LoginInfoResult extends ErrorMessage { + + private String openid; + + @JsonProperty("session_key") + private String sessionKey; + + @JsonProperty("unionid") + private String unionId; + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/mini/MiniWechatService.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/mini/MiniWechatService.java new file mode 100644 index 0000000..cd01b9f --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/mini/MiniWechatService.java @@ -0,0 +1,86 @@ +package com.sz.wechat.mini; + +import com.sz.core.util.JsonUtils; +import com.sz.redis.RedisUtils; +import com.sz.wechat.WechatProperties; +import com.sz.wechat.pojo.AccessTokenResult; +import com.sz.wechat.pojo.ErrorMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClient; + +import java.util.concurrent.TimeUnit; + +import static com.sz.wechat.WechatApiConstant.WECHAT_MINI_LOGIN_URL; +import static com.sz.wechat.WechatApiConstant.WECHAT_TOKEN_URL; + +/** + * @author sz + * @since 2024/4/26 10:04 + * @version 1.0 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class MiniWechatService { + + private final WechatProperties wechatProperties; + + private static final String WECHAT_MINI_TOKEN = "wechat:mini:token"; + + /** + * 获取accessToken【小程序】 + * + * @return accessToken + */ + public String getAccessToken() { + if (RedisUtils.hasKey(WECHAT_MINI_TOKEN)) { + return (String) RedisUtils.getValue(WECHAT_MINI_TOKEN); + } else { + ResponseEntity entity = RestClient.create().get() + .uri(WECHAT_TOKEN_URL, wechatProperties.getMini().getAppId(), wechatProperties.getMini().getAppSecret()).retrieve() + .toEntity(AccessTokenResult.class); + AccessTokenResult result = entity.getBody(); + assert result != null; + if (validSuccess(result)) { + int expireTime = result.getExpiresIn() - 1200; + RedisUtils.getRestTemplate().opsForValue().set(WECHAT_MINI_TOKEN, result.getAccessToken(), expireTime, TimeUnit.SECONDS); + return result.getAccessToken(); + } else { + log.error("【微信小程序】 获取accessToken失败,错误码:{},错误信息:{}", result.getErrcode(), result.getErrmsg()); + return ""; + } + } + } + + /** + * 微信小程序登录 + * + * @param code + * code + * @param accessToken + * accessToken + * @return 登录信息 + */ + public LoginInfoResult miniLogin(String code, String accessToken) { + // 微信小程序登录接口返回content-type是text/plain,因此无法直接映射对象。使用String接收,后续再做转换 + ResponseEntity entity = RestClient.create().get() + .uri(WECHAT_MINI_LOGIN_URL, wechatProperties.getMini().getAppId(), wechatProperties.getMini().getAppSecret(), code, accessToken).retrieve() + .toEntity(String.class); + return JsonUtils.parseObject(entity.getBody(), LoginInfoResult.class); + } + + /** + * 校验微信返回结果是否成功 + * + * @param errorMessage + * 微信返回结果 + * @return 是否成功 + */ + public boolean validSuccess(ErrorMessage errorMessage) { + return errorMessage.getErrcode() == null || errorMessage.getErrcode() == 0; + } + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/pojo/AccessTokenResult.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/pojo/AccessTokenResult.java new file mode 100644 index 0000000..1e53bbd --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/pojo/AccessTokenResult.java @@ -0,0 +1,22 @@ +package com.sz.wechat.pojo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 微信access_token返回结果 + * + * @author sz + * @since 2024/4/26 11:12 + * @version 1.0 + */ +@Data +public class AccessTokenResult extends ErrorMessage { + + @JsonProperty("access_token") + private String accessToken; + + @JsonProperty("expires_in") + private Integer expiresIn; + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/pojo/ErrorMessage.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/pojo/ErrorMessage.java new file mode 100644 index 0000000..f7ad820 --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/pojo/ErrorMessage.java @@ -0,0 +1,19 @@ +package com.sz.wechat.pojo; + +import lombok.Data; + +/** + * 微信错误信息实体类 + * + * @author sz + * @since 2024/4/26 11:11 + * @version 1.0 + */ +@Data +public class ErrorMessage { + + private Integer errcode; + + private String errmsg; + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/MessageResult.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/MessageResult.java new file mode 100644 index 0000000..4c34d8c --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/MessageResult.java @@ -0,0 +1,41 @@ +package com.sz.wechat.work; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.sz.wechat.pojo.ErrorMessage; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * MessageResult - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/4/23 + */ +@Data +@Schema(description = "消息发送结果") +public class MessageResult extends ErrorMessage { + + @Schema(description = "不合法的userid,不区分大小写,统一转为小写") + private String invaliduser; + + @Schema(description = "不合法的partyid") + private String invalidparty; + + @Schema(description = "不合法的标签id") + private String invalidtag; + + @Schema(description = "没有基础接口许可(包含已过期)的userid") + private String unlicenseduser; + + @Schema(description = "消息id,用于撤回应用消息") + private String msgid; + + @Schema(description = "仅消息类型为“按钮交互型”,“投票选择型”和“多项选择型”的模板卡片消息返回,应用可使用response_code调用更新模版卡片消息接口,72小时内有效,且只能使用一次") + @JsonProperty("response_code") + private String responseCode; + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/TextMessageBody.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/TextMessageBody.java new file mode 100644 index 0000000..07875d2 --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/TextMessageBody.java @@ -0,0 +1,68 @@ +package com.sz.wechat.work; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * TextMessageBody - 简要描述该类的功能. + *

+ * API详见 + * https://developer.work.weixin.qq.com/document/path/96458#%E6%96%87%E6%9C%AC%E6%B6%88%E6%81%AF + * https://developer.work.weixin.qq.com/document/path/90236#%E6%96%87%E6%9C%AC%E6%B6%88%E6%81%AF + *

+ * + * @author sz + * @version 1.0 + * @since 2025/4/23 + */ +@Data +@Schema(description = "发送文本消息实体类") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TextMessageBody { + + @Schema(description = "指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。\n" + "特殊情况:指定为\"@all\",则向该企业应用的全部成员发送") + private String touser; + + /* + * @Schema(description = "指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。\n" + + * "当touser为\"@all\"时忽略本参数") private String toparty; + * + * @Schema(description = "指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。\n" + + * "当touser为\"@all\"时忽略本参数") private String totag; + */ + + @Schema(description = "消息类型,此时固定为:text") + private String msgtype = "text"; + + @Schema(description = "企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值") + private Integer agentid; + + private Text text; + + @Schema(description = "表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0") + private Integer safe = 0; + + /* + * @Schema(description = "是否开启id转译,0表示否,1表示是,默认0。") + * + * @JsonProperty("enable_id_trans") private Integer enableIdTrans = 0; + */ + + @Data + @Schema(description = "文本消息体") + public static class Text { + + public Text(String content) { + this.content = content; + } + + @Schema(description = "消息内容,最长不超过2048个字节,超过将截断(支持id转译)") + private String content; + } + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/TextMessageDTO.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/TextMessageDTO.java new file mode 100644 index 0000000..e085f1b --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/TextMessageDTO.java @@ -0,0 +1,34 @@ +package com.sz.wechat.work; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * TextMessageDTO - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/4/23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TextMessageDTO { + + private String accessToken; + + private List toUserList; + + private String content; + + private Integer safe; + +} diff --git a/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/WorkWechatService.java b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/WorkWechatService.java new file mode 100644 index 0000000..fa8869a --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/java/com/sz/wechat/work/WorkWechatService.java @@ -0,0 +1,112 @@ +package com.sz.wechat.work; + +import com.sz.core.util.JsonUtils; +import com.sz.redis.RedisUtils; +import com.sz.wechat.WechatProperties; +import com.sz.wechat.pojo.AccessTokenResult; +import com.sz.wechat.pojo.ErrorMessage; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClient; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static com.sz.wechat.WechatApiConstant.WORK_WECHAT_MESSAGE_SEND_URL; +import static com.sz.wechat.WechatApiConstant.WORK_WECHAT_TOKEN_URL; + +/** + * @author sz + * @since 2024/4/26 10:04 + * @version 1.0 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class WorkWechatService { + + private final WechatProperties wechatProperties; + + private static final String WECHAT_WORK_TOKEN = "wechat:work:token"; + + /** + * 获取 accessToken(企业微信)。 + *

+ * 相关配置参见 {@link WechatProperties.WorkProgramProperties}。
+ * 企业微信官方文档: + * 企业微信-获取 + * access_token + *

+ * + * @return accessToken + * @see WechatProperties.WorkProgramProperties + */ + public String getAccessToken() { + if (RedisUtils.hasKey(WECHAT_WORK_TOKEN)) { + return (String) RedisUtils.getValue(WECHAT_WORK_TOKEN); + } else { + ResponseEntity entity = RestClient.create().get() + .uri(WORK_WECHAT_TOKEN_URL, wechatProperties.getWork().getCorpId(), wechatProperties.getWork().getCorpSecret()).retrieve() + .toEntity(AccessTokenResult.class); + AccessTokenResult result = entity.getBody(); + assert result != null; + if (validSuccess(result)) { + int expireTime = result.getExpiresIn() - 1200; + RedisUtils.getRestTemplate().opsForValue().set(WECHAT_WORK_TOKEN, result.getAccessToken(), expireTime, TimeUnit.SECONDS); + return result.getAccessToken(); + } else { + log.error("【企业微信】 获取accessToken失败,错误码:{},错误信息:{}", result.getErrcode(), result.getErrmsg()); + return ""; + } + } + } + + /** + * 发送企业微信消息。 + *

+ * 相关配置参见 {@link WechatProperties.WorkProgramProperties}。 + *

+ * 准备工作: + *

    + *
  1. 创建应用并获取 agentIdsecret
  2. + *
  3. 在“应用 - 开发者接口”中设置“网页授权及JS-SDK”可信任域名
  4. + *
  5. 在“应用 - 开发者接口”中设置“企业可信任IP”为企业服务器的IP地址
  6. + *
+ * 详细文档参见 企业微信-发送应用消息 + *

+ * + * @param dto + * 消息内容(TextMessageDTO) + * @return 发送结果(MessageResult) + */ + public MessageResult sendMessageText(TextMessageDTO dto) { + List toUserList = dto.getToUserList(); + if (toUserList == null || toUserList.isEmpty()) { + throw new IllegalArgumentException("接收人不能为空"); + } + String touser = String.join("|", toUserList); + TextMessageBody body = TextMessageBody.builder().touser(touser).agentid(wechatProperties.getWork().getAgentId()) + .text(new TextMessageBody.Text(dto.getContent())).msgtype("text").safe(1).build(); + + // 微信小程序登录接口返回content-type是text/plain,因此无法直接映射对象。使用String接收,后续再做转换 + ResponseEntity entity = RestClient.create().post().uri(WORK_WECHAT_MESSAGE_SEND_URL, dto.getAccessToken()) + .contentType(MediaType.APPLICATION_JSON).body(body).retrieve().toEntity(String.class); + return JsonUtils.parseObject(entity.getBody(), MessageResult.class); + } + + /** + * 校验微信返回结果是否成功 + * + * @param errorMessage + * 微信返回结果 + * @return 是否成功 + */ + public boolean validSuccess(ErrorMessage errorMessage) { + return errorMessage.getErrcode() == null || errorMessage.getErrcode() == 0; + } + +} diff --git a/sz-common/sz-common-wechat/src/main/resources/application.yml b/sz-common/sz-common-wechat/src/main/resources/application.yml new file mode 100644 index 0000000..9fef71d --- /dev/null +++ b/sz-common/sz-common-wechat/src/main/resources/application.yml @@ -0,0 +1,9 @@ +# sz-common-wechat模块需要的配置,这是一个示例配置文件,不会起作用,实际使用时请使用sz-service-admin 下的 application*.yml 来配置声明。 +wechat: + mini: + app-id: your-app-id + app-secret: your-app-secret + work: + corp-id: your-corp-id + corp-secret: your-corp-secret + agent-id: your-agent-id \ No newline at end of file diff --git a/sz-dependencies/pom.xml b/sz-dependencies/pom.xml new file mode 100644 index 0000000..7aa3ed0 --- /dev/null +++ b/sz-dependencies/pom.xml @@ -0,0 +1,206 @@ + + + 4.0.0 + + com.sz + sz-build + ${revision} + ../sz-build/pom.xml + + + sz-dependencies + + + 3.5.5 + 1.44.0 + 1.11.4 + 2.19.2 + 2.32.29 + 3.1.0 + + + + + + + com.github.pagehelper + pagehelper + 6.1.1 + + + org.apache.commons + commons-collections4 + 4.5.0 + + + commons-io + commons-io + 2.20.0 + + + org.apache.commons + commons-lang3 + 3.20.0 + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + + + org.modelmapper + modelmapper + 3.2.6 + + + com.mybatis-flex + mybatis-flex-spring-boot3-starter + ${mybatis-flex.version} + + + com.mybatis-flex + mybatis-flex-processor + ${mybatis-flex.version} + + + cn.dev33 + sa-token-spring-boot3-starter + ${sa-token.version} + + + cn.dev33 + sa-token-jwt + ${sa-token.version} + + + cn.dev33 + sa-token-redis-jackson + ${sa-token.version} + + + com.mysql + mysql-connector-j + 9.4.0 + + + com.zaxxer + HikariCP + 7.0.2 + + + org.springframework.boot + spring-boot-starter-data-redis + ${spring-boot.version} + + + org.aspectj + aspectjweaver + 1.9.24 + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + 4.5.0 + + + org.projectlombok + lombok + 1.18.42 + + + io.swagger.core.v3 + swagger-annotations + 2.2.41 + + + + cn.hutool + hutool-jwt + 5.8.39 + + + com.alibaba + transmittable-thread-local + 2.14.5 + + + + software.amazon.awssdk + s3 + ${aws.s3.version} + + + commons-logging + commons-logging + + + + + software.amazon.awssdk.crt + aws-crt + 0.38.11 + + + software.amazon.awssdk + s3-transfer-manager + ${aws.s3.version} + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.8.14 + + + cn.idev.excel + fastexcel + 1.2.0 + + + + + nl.basjes.parse.useragent + yauaa + 7.32.0 + + + + + org.lionsoul + ip2region + ${ip2region.version} + + + + org.apache.httpcomponents.client5 + httpclient5 + 5.4.2 + + + + + + + + com.diffplug.spotless + spotless-maven-plugin + 2.44.5 + + true + + + + + + \ No newline at end of file diff --git a/sz-service/pom.xml b/sz-service/pom.xml new file mode 100644 index 0000000..947c17a --- /dev/null +++ b/sz-service/pom.xml @@ -0,0 +1,39 @@ + + + + sz-boot-parent + com.sz + ${revision} + + 4.0.0 + + sz-service + pom + + sz-service-admin + sz-service-websocket + + + + + + + com.sz + sz-common-core + ${revision} + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/sz-service/sz-service-admin/pom.xml b/sz-service/sz-service-admin/pom.xml new file mode 100644 index 0000000..76db777 --- /dev/null +++ b/sz-service/sz-service-admin/pom.xml @@ -0,0 +1,154 @@ + + + + sz-service + com.sz + ${revision} + + 4.0.0 + sz-service-admin + + + + 4.31.1 + + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.sz + sz-common-db-mysql + ${revision} + + + + com.sz + sz-common-security + ${revision} + + + + com.sz.generator + sz-common-generator + ${revision} + + + + com.sz.wechat + sz-common-wechat + ${revision} + + + + com.sz + sz-common-log + ${revision} + + + + com.sz + sz-common-db-redis + ${revision} + + + com.sz.excel + sz-common-excel + ${revision} + + + + com.sz.oss + sz-common-oss + ${revision} + + + + org.aspectj + aspectjweaver + + + org.liquibase + liquibase-core + ${liquibase.version} + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + nl.basjes.parse.useragent + yauaa + + + org.springframework.boot + spring-boot-starter-actuator + + + + cc.eguid + FFmpegCommandManager + 1.0.0 + system + ${project.basedir}/src/main/resources/jar/FFmpegCommandHandler.jar + + + com.github.cbyzzy + Jna + 1.0.0 + system + ${project.basedir}/src/main/resources/jar/jna.jar + + + com.github.cbyzzy + Examples + 1.0.0 + system + ${project.basedir}/src/main/resources/jar/examples.jar + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + com.alibaba + fastjson + 2.0.41 + + + cn.hutool + hutool-all + 5.8.38 + + + org.apache.httpcomponents.client5 + httpclient5 + + + + org.bytedeco + javacv-platform + 1.5.11 + + + \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/AdminApplication.java b/sz-service/sz-service-admin/src/main/java/com/sz/AdminApplication.java new file mode 100644 index 0000000..8b44e30 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/AdminApplication.java @@ -0,0 +1,48 @@ +package com.sz; + +import jakarta.annotation.PostConstruct; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableAspectJAutoProxy +@RequiredArgsConstructor +@EnableScheduling +public class AdminApplication { + + @Value("${app.version}") + private String appVersion; + + @Getter + private static String version; + + @PostConstruct + public void init() { + setVersion(appVersion); // 通过辅助方法设置静态字段 + } + + private static void setVersion(String appVersion) { + AdminApplication.version = appVersion; + } + + public static void main(String[] args) { + SpringApplication.run(AdminApplication.class, args); + String template = """ + __ _ + | ] (_) + .--. ____ ______ ,--. .--.| | _ .--..--. __ _ .--. + ( (`\\] [_ ]|______|`'_\\ : / /'`\\' | [ `.-. .-. | [ | [ `.-. | + `'.'. .' /_ // | |,| \\__/ | | | | | | | | | | | | | + [\\__) )[_____] \\'-;__/ '.__.;__][___||__||__][___][___||__] + ------------------%s (v%s)------------------- + """; + String result = String.format(template, "https://szadmin.cn", getVersion()); + System.out.println(result); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/common/CommonKit.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/common/CommonKit.java new file mode 100644 index 0000000..eb9fc4c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/common/CommonKit.java @@ -0,0 +1,102 @@ +package com.sz.admin.monitor.common; + +import java.net.*; +import java.util.*; + +public class CommonKit { + + /** + * 根据前端传递的集合参数中取到指定属性的值 + */ + public static List getCols(List vo,String colName) { + List list = new ArrayList<>(); + for (Object obj : vo) { + list.add((String) ((LinkedHashMap) obj).get(colName)); + } + return list; + } + + public static String join(String[] strs , String separator){ + String result = ""; + for (int i = 0; i < strs.length; i++) { + if(i == 0){ + result += strs[i]; + }else{ + result += separator+strs[i]; + } + } + return result; + } + + /** + * 获取项目webapp目录 + * @return + */ + public static String getLibPath(){ + //String path = System.getProperty("user.dir") + "/config/lib/linux/libhcnetsdk.so"; + String path = CommonKit.class.getClassLoader().getResource("").getPath().substring(1) + "lib\\win\\HCNetSDK.dll"; + return path; + } + + /** + * 获取本机ip + * @return + */ + public static String getServerIp() { + // 获取操作系统类型 + String sysType = System.getProperties().getProperty("os.name"); + String ip; + if (sysType.toLowerCase().startsWith("win")) { // 如果是Windows系统,获取本地IP地址 + String localIP = null; + try { + localIP = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + if (localIP != null) { + return localIP; + } + } else { + ip = getIpByEthNum("eth0"); // 兼容Linux + if (ip != null) { + return ip; + } + } + return "获取服务器IP错误"; + } + + /** + * 根据网络接口获取IP地址 + * @param ethNum 网络接口名,Linux下是eth0 + * @return + */ + private static String getIpByEthNum(String ethNum) { + try { + Enumeration allNetInterfaces = NetworkInterface.getNetworkInterfaces(); + InetAddress ip; + while (allNetInterfaces.hasMoreElements()) { + NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement(); + if (ethNum.equals(netInterface.getName())) { + Enumeration addresses = netInterface.getInetAddresses(); + while (addresses.hasMoreElements()) { + ip = (InetAddress) addresses.nextElement(); + if (ip != null && ip instanceof Inet4Address) { + return ip.getHostAddress(); + } + } + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + return "获取服务器IP错误"; + } + + public static void main(String[] args) { + String ip = "10.192.44.101"; + String[] a = ip.split("\\."); + String b = CommonKit.join(a,""); + System.out.println(a+b); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/config/RestTemplateConfig.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/config/RestTemplateConfig.java new file mode 100644 index 0000000..0c7e777 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/config/RestTemplateConfig.java @@ -0,0 +1,18 @@ +package com.sz.admin.monitor.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(5000); + factory.setReadTimeout(5000); + return new RestTemplate(factory); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/constant/MediaConstant.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/constant/MediaConstant.java new file mode 100644 index 0000000..a48e81a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/constant/MediaConstant.java @@ -0,0 +1,8 @@ +package com.sz.admin.monitor.constant; + +public class MediaConstant { + + public final static String HTTP_MEDIA_URL = "http://%s:%s/index/api%s"; + public final static String HTTP_Edge_URL = "http://%s:%s/api%s"; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/AlgorithmTaskController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/AlgorithmTaskController.java new file mode 100644 index 0000000..6b52567 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/AlgorithmTaskController.java @@ -0,0 +1,37 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.pojo.dto.edgebox.AlarmReportDTO; +import com.sz.admin.monitor.pojo.po.AlgorithmTask; +import com.sz.admin.monitor.pojo.vo.cameraalarm.CameraAlarmVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlgorithmTaskVO; +import com.sz.admin.monitor.service.AlgorithmTaskService; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + * ClassName: AlgorithmTaskController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "算法任务") +@RestController +@RequestMapping("algorithm-task") +@RequiredArgsConstructor +public class AlgorithmTaskController { + private final AlgorithmTaskService algorithmTaskService; + // 根据摄像头id获取算法任务 + @Operation(summary = "根据摄像头id获取算法任务") + @GetMapping("/get") + public ApiResult getAlgorithmTaskByCameraId(@RequestParam("cameraId") Long cameraId) { + return ApiResult.success(algorithmTaskService.getAlgorithmTaskByCameraId(cameraId)); + } + // 报警上报接口 + @Operation(summary = "报警上报接口") + @PostMapping("/alarm") + public ApiResult alarmReport(@RequestBody AlarmReportDTO alarmReportDto) { + return ApiResult.success(algorithmTaskService.alarmReport(alarmReportDto)); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraAlarmController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraAlarmController.java new file mode 100644 index 0000000..5af3a33 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraAlarmController.java @@ -0,0 +1,97 @@ +package com.sz.admin.monitor.controller; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmCreateDTO; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmListDTO; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmUpdateDTO; +import com.sz.admin.monitor.pojo.vo.cameraalarm.CameraAlarmVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlarmReportVO; +import com.sz.admin.monitor.service.CameraAlarmService; +import com.sz.core.common.entity.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 告警工单表 Controller + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Tag(name = "告警工单表") +@RestController +@RequestMapping("ry-camera-alarm") +@RequiredArgsConstructor +public class CameraAlarmController { + + private final CameraAlarmService cameraAlarmService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "ry.camera.alarm.create") + @PostMapping + public ApiResult create(@RequestBody CameraAlarmCreateDTO dto) { + cameraAlarmService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "ry.camera.alarm.update") + @PutMapping + public ApiResult update(@RequestBody CameraAlarmUpdateDTO dto) { + cameraAlarmService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "ry.camera.alarm.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + cameraAlarmService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "ry.camera.alarm.query_table") + @GetMapping + public ApiResult> list(CameraAlarmListDTO dto) { + return ApiPageResult.success(cameraAlarmService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "ry.camera.alarm.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(cameraAlarmService.detail(id)); + } + @Operation(summary = "根据id查询算法报警信息详情") + @GetMapping("/get") + public ApiResult getAlarmReportDetail(@RequestParam("id") Long id) { + return ApiResult.success(cameraAlarmService.getAlarmReportDetail(id)); + } + @Operation(summary = "导入") + @Parameters({ + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true), + }) + @SaCheckPermission(value = "ry.camera.alarm.import") + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + cameraAlarmService.importExcel(dto); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "ry.camera.alarm.export") + @PostMapping("/export") + public void exportExcel(@RequestBody CameraAlarmListDTO dto, HttpServletResponse response) { + cameraAlarmService.exportExcel(dto, response); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraController.java new file mode 100644 index 0000000..627ef0d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraController.java @@ -0,0 +1,76 @@ +package com.sz.admin.monitor.controller; + + +import com.sz.admin.monitor.pojo.dto.camera.CameraListDTO; +import com.sz.admin.monitor.pojo.dto.camera.CameraUpdateDTO; +import com.sz.admin.monitor.pojo.vo.camera.CameraVO; +import com.sz.admin.monitor.service.CameraService; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * ClassName: CameraController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "摄像头表") +@RestController +@RequestMapping("camera") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class CameraController { + private final CameraService cameraService; + + @Operation(summary = "修改") + @PutMapping + public ApiResult update(@RequestBody CameraUpdateDTO dto) { + cameraService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + cameraService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @GetMapping + public ApiResult> list(CameraListDTO dto) { + return ApiPageResult.success(cameraService.page(dto)); + } + + @Operation(summary = "详情") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Long id) { + return ApiResult.success(cameraService.detail(id)); + } + + @Operation(summary = "远程搜索测试接口") + @GetMapping("/remote/{keyword}") + public ApiResult> remoteSearch(@PathVariable String keyword) { + return ApiResult.success(cameraService.remoteSearch(keyword)); + } + + @Operation(summary = "获取还没有绑定盒子的摄像头") + @GetMapping("/unboundList") + public ApiResult> getUnboundList() { + return ApiResult.success(cameraService.getUnboundList()); + } + + @Operation(summary = "获取已经绑定盒子的摄像头") + @GetMapping("/boundList") + public ApiResult> getBoundList(@RequestParam("boxId") Long boxId) { + return ApiResult.success(cameraService.getBoundList(boxId)); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraSnapshotController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraSnapshotController.java new file mode 100644 index 0000000..02188ab --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/CameraSnapshotController.java @@ -0,0 +1,38 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO; +import com.sz.admin.monitor.service.CameraSnapshotService; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * ClassName: CameraSnapshotController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "摄像头抓图表") +@RestController +@RequestMapping("cameraSnapshot") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class CameraSnapshotController { + private final CameraSnapshotService cameraSnapshotService; + + /** + * 手动抓拍图片接口 + */ + @Operation(summary = "手动抓拍图片接口") + @PostMapping("/capture/{id}") + public ApiResult manualCapture(@PathVariable Long id) { + CameraSnapshotVO cameraSnapshotVO = cameraSnapshotService.captureAndSave(id, 3); + return ApiResult.success(cameraSnapshotVO); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/DeviceController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/DeviceController.java new file mode 100644 index 0000000..4724a3d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/DeviceController.java @@ -0,0 +1,39 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.service.DeviceService; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * ClassName: DeviceController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "设备表") +@RestController +@RequestMapping("device") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class DeviceController { + private final DeviceService deviceService; + // 通道刷新 + @Operation(summary = "通道刷新") + @GetMapping("/refresh") + public ApiResult refresh(@RequestParam("id") Long id, @RequestParam("deviceType") Integer deviceType) { + return ApiResult.success(deviceService.refresh(id,deviceType)); + } + // 设备登录 + @Operation(summary = "/设备登录") + @GetMapping("/login") + public ApiResult deviceLogin(@RequestParam("id") Long id) + { + return ApiResult.success(deviceService.deviceLogin(id)); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/EdgeBoxController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/EdgeBoxController.java new file mode 100644 index 0000000..aa399b1 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/EdgeBoxController.java @@ -0,0 +1,98 @@ +package com.sz.admin.monitor.controller; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxBindCamerasDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxCreateDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxListDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxUpdateDTO; +import com.sz.admin.monitor.pojo.vo.edgebox.EdgeBoxVO; +import com.sz.admin.monitor.service.EdgeBoxService; +import com.sz.core.common.entity.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 边缘盒子 Controller + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Tag(name = "边缘盒子") +@RestController +@RequestMapping("ry-edge-box") +@RequiredArgsConstructor +public class EdgeBoxController { + + private final EdgeBoxService edgeBoxService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "ry.edge.box.create") + @PostMapping + public ApiResult create(@RequestBody EdgeBoxCreateDTO dto) { + edgeBoxService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "ry.edge.box.update") + @PutMapping + public ApiResult update(@RequestBody EdgeBoxUpdateDTO dto) { + edgeBoxService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "ry.edge.box.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + edgeBoxService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "ry.edge.box.query_table") + @GetMapping + public ApiResult> list(EdgeBoxListDTO dto) { + return ApiPageResult.success(edgeBoxService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "ry.edge.box.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(edgeBoxService.detail(id)); + } + + @Operation(summary = "导入") + @Parameters({ + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true), + }) + @SaCheckPermission(value = "ry.edge.box.import") + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + edgeBoxService.importExcel(dto); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "ry.edge.box.export") + @PostMapping("/export") + public void exportExcel(@RequestBody EdgeBoxListDTO dto, HttpServletResponse response) { + edgeBoxService.exportExcel(dto, response); + } + + @Operation(summary = "给盒子绑定摄像头通道") + @PostMapping("/bind-cameras") + public ApiResult bindCameras(@RequestBody EdgeBoxBindCamerasDTO dto) { + edgeBoxService.bindCameras(dto); + return ApiResult.success(); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceImageController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceImageController.java new file mode 100644 index 0000000..ecf8a87 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceImageController.java @@ -0,0 +1,36 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.service.FaceImageService; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +/** + * ClassName: FaceImageContoller + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "人脸图片表") +@RestController +@RequestMapping("ry-face-image") +@RequiredArgsConstructor +@Slf4j +public class FaceImageController { + private final FaceImageService faceImageService; + @Operation(summary = "人脸图片上传接口") + @PostMapping("/upload") + public ApiResult fileUpload(@RequestBody MultipartFile file) { + log.info("图片上传成功:{}", file.getOriginalFilename()); + return ApiResult.success(faceImageService.fileUpload(file)); + } + @Operation(summary = "人脸图片上传绑定") + @PostMapping("/upload/{id}") + public ApiResult fileUploadBind(@RequestBody MultipartFile file, @PathVariable("id") Long id) { + faceImageService.fileUploadBind(file, id); + return ApiResult.success(); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceInfoController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceInfoController.java new file mode 100644 index 0000000..439c101 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceInfoController.java @@ -0,0 +1,92 @@ +package com.sz.admin.monitor.controller; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoCreateDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoListDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoUpdateDTO; +import com.sz.admin.monitor.pojo.vo.faceinfo.FaceInfoVO; +import com.sz.admin.monitor.service.FaceImageService; +import com.sz.admin.monitor.service.FaceInfoService; +import com.sz.core.common.entity.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 人脸信息表 Controller + *

+ *FaceInfoController + * @author Lz + * @since 2026-02-26 + */ +@Tag(name = "人脸信息表") +@RestController +@RequestMapping("ry-face-info") +@RequiredArgsConstructor +public class FaceInfoController { + + private final FaceInfoService faceInfoService; + + + @Operation(summary = "新增") + @SaCheckPermission(value = "ry.face.info.create") + @PostMapping + public ApiResult create(@RequestBody FaceInfoCreateDTO dto) { + faceInfoService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "ry.face.info.update") + @PutMapping + public ApiResult update(@RequestBody FaceInfoUpdateDTO dto) { + faceInfoService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "ry.face.info.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + faceInfoService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "ry.face.info.query_table") + @GetMapping + public ApiResult> list(FaceInfoListDTO dto) { + return ApiPageResult.success(faceInfoService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "ry.face.info.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(faceInfoService.detail(id)); + } + + @Operation(summary = "导入") + @Parameters({ + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true), + }) + @SaCheckPermission(value = "ry.face.info.import") + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + faceInfoService.importExcel(dto); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "ry.face.info.export") + @PostMapping("/export") + public void exportExcel(@RequestBody FaceInfoListDTO dto, HttpServletResponse response) { + faceInfoService.exportExcel(dto, response); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceLibraryController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceLibraryController.java new file mode 100644 index 0000000..dbac48d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/FaceLibraryController.java @@ -0,0 +1,94 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryCreateDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryListDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryUpdateDTO; +import com.sz.admin.monitor.pojo.vo.facelibrary.FaceLibraryVO; +import com.sz.admin.monitor.service.FaceLibraryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import lombok.RequiredArgsConstructor; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.entity.ImportExcelDTO; +import jakarta.servlet.http.HttpServletResponse; + +/** + *

+ * 人脸库表 Controller + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Tag(name = "人脸库表") +@RestController +@RequestMapping("ry-face-library") +@RequiredArgsConstructor +public class FaceLibraryController { + + private final FaceLibraryService faceLibraryService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "ry.face.library.create") + @PostMapping + public ApiResult create(@RequestBody FaceLibraryCreateDTO dto) { + faceLibraryService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "ry.face.library.update") + @PutMapping + public ApiResult update(@RequestBody FaceLibraryUpdateDTO dto) { + faceLibraryService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "ry.face.library.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + faceLibraryService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "ry.face.library.query_table") + @GetMapping + public ApiResult> list(FaceLibraryListDTO dto) { + return ApiPageResult.success(faceLibraryService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "ry.face.library.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(faceLibraryService.detail(id)); + } + + @Operation(summary = "导入") + @Parameters({ + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true), + }) + @SaCheckPermission(value = "ry.face.library.import") + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + faceLibraryService.importExcel(dto); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "ry.face.library.export") + @PostMapping("/export") + public void exportExcel(@RequestBody FaceLibraryListDTO dto, HttpServletResponse response) { + faceLibraryService.exportExcel(dto, response); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/IpChannelController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/IpChannelController.java new file mode 100644 index 0000000..d2df090 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/IpChannelController.java @@ -0,0 +1,100 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.pojo.dto.edgebox.AlgorithmTaskDTO; +import com.sz.admin.monitor.pojo.vo.watchful.WatchfulVO; +import com.sz.admin.monitor.service.IpChannelService; +import com.sz.admin.monitor.utils.AlgMediaConfigResponse; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.*; + +/** + * ClassName: IpChannelController + * Package: com.sz.admin.monitor.controller + * Description: 通道相关操作的控制器 + */ +@Tag(name = "通道相关操作") +@RestController +@RequestMapping("channel") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class IpChannelController { + private final IpChannelService ipChannelService; + // 视频预览接口 + @Operation(summary = "视频预览接口") + @GetMapping("/preview") + public ApiResult preview(@RequestParam("id") Long id) { + String result = ipChannelService.preview(id); + return ApiResult.success(result); + } + + // 心跳保活接口 + @Operation(summary = "心跳保活接口") + @GetMapping("/heartbeat") + public ApiResult heartbeat(@RequestParam("id") Long id, + @RequestParam("uuid") String uuid) { + ipChannelService.userHeartbeat(id,uuid); + return ApiResult.success(); + } + + // 停止预览 + @Operation(summary = "停止预览") + @GetMapping("/stopPreview") + public ApiResult stopPreview(@RequestParam("id") Long id, + @RequestParam("uuid") String uuid) + { + Integer result = ipChannelService.stopPreview(id, uuid); + return ApiResult.success(result); + } + +// // 云台控制 +// @Operation(summary = "云台控制") +// @GetMapping("/ptzControl") +// public ApiResult ptzControl(@RequestParam("channelId") int channelId, +// @RequestParam("direction") Integer direction, +// @RequestParam("speed") int speed, +// @RequestParam("startFlag") int startFlag) +// { +// Object result = ipChannelService.ptzControl(channelId, direction, speed, startFlag); +// return ApiResult.success(result); +// } + // 控制预置位 + @Operation(summary = "控制预置位") + @GetMapping("/controlPreset") + public ApiResult controlPreset(@RequestParam("id") Long id, + @RequestParam("ptzPresetCmd") int ptzPresetCmd, + @RequestParam("dwPresetIndex") int dwPresetIndex, + @RequestParam("pointName") String pointName, + @RequestParam("isBasicPoint") int isBasicPoint) + { + Object result = ipChannelService.controlPreset(id, ptzPresetCmd, dwPresetIndex, pointName, isBasicPoint); + return ApiResult.success(result); + } + + // 控制云台守望 + @Operation(summary = "云台守望") + @GetMapping("/sentinel") + public ApiResult ControlSentinel(@RequestParam("id") Long id, + @RequestParam("openOrNo") Integer openOrNo, + @RequestParam("watchTime") Integer watchTime, + Integer presetIndex) { + return ApiResult.success(ipChannelService.ControlSentinel(id, openOrNo, watchTime, presetIndex)); + } + + // 获取云台守望的参数 + @Operation(summary = "获取云台守望的参数") + @GetMapping("/sentinel/get") + public ApiResult getWatchful(@RequestParam("id") Long id) { + return ApiResult.success(ipChannelService.getWatchful(id)); + } + // 配置算法任务 + @Operation(summary = "配置算法任务") + @PostMapping("/config/alg") + public ApiResult configAlg(@RequestBody AlgorithmTaskDTO algTaskConfigDto) { + return ApiResult.success(ipChannelService.configAlg(algTaskConfigDto)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/NvrController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/NvrController.java new file mode 100644 index 0000000..f5d10ec --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/NvrController.java @@ -0,0 +1,72 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.pojo.dto.nvr.NvrDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrCreateDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrListDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrUpdateDTO; + +import com.sz.admin.monitor.pojo.vo.nvr.NvrVO; +import com.sz.admin.monitor.service.NvrService; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * ClassName: NvrController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "nvr 设备表") +@RestController +@RequestMapping("nvr") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class NvrController { + private final NvrService nvrService; + + @Operation(summary = "新增") + @PostMapping + public ApiResult create(@RequestBody NvrCreateDTO dto) { + return ApiResult.success( nvrService.create(dto)); + } + + @Operation(summary = "修改") + @PutMapping + public ApiResult update(@RequestBody NvrUpdateDTO dto) { + nvrService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + nvrService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @GetMapping + public ApiResult> list(NvrListDTO dto) { + return ApiPageResult.success(nvrService.page(dto)); + } + + @Operation(summary = "详情") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Long id) { + return ApiResult.success(nvrService.detail(id)); + } + @Operation(summary = "获取指定节点下的所有NVR数据") + @GetMapping("/under-node") + public ApiResult> listByNode(@RequestParam("nodeId") Long nodeId,@RequestParam("type") Integer type,@RequestParam("pageNum") Integer pageNum,@RequestParam("pageSize") int pageSize) { + return ApiResult.success(nvrService.listByNode(nodeId,type,pageNum,pageSize)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/PresetController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/PresetController.java new file mode 100644 index 0000000..5c3fac6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/PresetController.java @@ -0,0 +1,66 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.pojo.dto.preset.PresetCreateDTO; +import com.sz.admin.monitor.pojo.dto.preset.PresetDeleteDTO; +import com.sz.admin.monitor.pojo.po.Preset; +import com.sz.admin.monitor.pojo.vo.Region.RegionVO; +import com.sz.admin.monitor.pojo.vo.preset.PresetVO; +import com.sz.admin.monitor.service.PresetService; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * ClassName: PresetController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "preset 预置表") +@RestController +@RequestMapping("preset") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class PresetController { + private final PresetService presetService; + + @Operation(summary = "查询已经设置的预置位") + @GetMapping + public ApiResult> getPresetList(@RequestParam("id") Long id) { + List presetList = presetService.getPresetList(id); + return ApiResult.success(presetList); + } + + + @Operation(summary = "查询数据库已经存在的预置位") + @GetMapping("/list") + public ApiResult> getExistPresetList(@RequestParam("id") Long id) { + List presetList = presetService.getExistPresetList(id); + return ApiResult.success(presetList); + } + + @Operation(summary = "删除预置位") + @DeleteMapping + public ApiResult remove(@RequestBody PresetDeleteDTO dto) { + presetService.removePreset(dto); + return ApiResult.success(); + } + + @Operation(summary = "保存预置位") + @PostMapping + public ApiResult create(@RequestBody PresetCreateDTO dto) { + presetService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "详情") + @GetMapping("/detail") + public ApiResult detail(@RequestParam("id") Long id, + @RequestParam("presetIndex") Integer presetIndex) { + return ApiResult.success(presetService.selectByCameraIdAndPresetIndex(id, presetIndex)); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/RegionController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/RegionController.java new file mode 100644 index 0000000..4515906 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/RegionController.java @@ -0,0 +1,72 @@ +package com.sz.admin.monitor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.monitor.pojo.dto.region.RegionCreateDTO; +import com.sz.admin.monitor.pojo.dto.region.RegionListDTO; +import com.sz.admin.monitor.pojo.dto.region.RegionUpdateDTO; +import com.sz.admin.monitor.pojo.vo.Region.RegionVO; +import com.sz.admin.monitor.service.RegionService; + +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * ClassName: RegionController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "区域表") +@RestController +@RequestMapping("region") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class RegionController { + private final RegionService regionService; + + @Operation(summary = "新增") + @PostMapping + public ApiResult create(@RequestBody RegionCreateDTO dto) { + regionService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @PutMapping + public ApiResult update(@RequestBody RegionUpdateDTO dto) { + regionService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + regionService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @GetMapping + public ApiResult> list(RegionListDTO dto) { + return ApiPageResult.success(regionService.page(dto)); + } + + @Operation(summary = "详情") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Long id) { + return ApiResult.success(regionService.detail(id)); + } + + + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/SubstationController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/SubstationController.java new file mode 100644 index 0000000..f9cb186 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/SubstationController.java @@ -0,0 +1,102 @@ +package com.sz.admin.monitor.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.monitor.pojo.dto.substation.SubstationCreateDTO; +import com.sz.admin.monitor.pojo.dto.substation.SubstationListDTO; +import com.sz.admin.monitor.pojo.dto.substation.SubstationUpdateDTO; + +import com.sz.admin.monitor.pojo.po.Substation; +import com.sz.admin.monitor.pojo.vo.substation.SubstationVO; +import com.sz.admin.monitor.service.SubstationService; +import com.sz.admin.monitor.service.SubstationService; +import com.sz.core.common.entity.*; +import com.sz.core.util.BeanCopyUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * ClassName: SubstationController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "变电站表") +@RestController +@RequestMapping("ry-substation") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class SubstationController { + private final SubstationService substationService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "ry.substation.create") + @PostMapping + public ApiResult create(@RequestBody SubstationCreateDTO dto) { + substationService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "ry.substation.update") + @PutMapping + public ApiResult update(@RequestBody SubstationUpdateDTO dto) { + substationService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "ry.substation.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + substationService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "ry.substation.query_table") + @GetMapping + public ApiResult> list(SubstationListDTO dto) { + return ApiPageResult.success(substationService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "ry.substation.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(substationService.detail(id)); + } + + @Operation(summary = "导入") + @Parameters({ + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true), + }) + @SaCheckPermission(value = "ry.substation.import") + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + substationService.importExcel(dto); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "ry.substation.export") + @PostMapping("/export") + public void exportExcel(@RequestBody SubstationListDTO dto, HttpServletResponse response) { + substationService.exportExcel(dto, response); + } + // 获取所有的列表 + @Operation(summary = "获取所有的变电站") + @GetMapping("/list") + public ApiResult> getAllList(){ + List substationList = substationService.list(); + return ApiResult.success(BeanCopyUtils.copyList(substationList, SubstationVO.class)); + } + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/TreeController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/TreeController.java new file mode 100644 index 0000000..4a72efd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/controller/TreeController.java @@ -0,0 +1,42 @@ +package com.sz.admin.monitor.controller; + +import com.sz.admin.monitor.pojo.vo.tree.TreeNodeVO; +import com.sz.admin.monitor.service.TreeService; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * ClassName: TreeController + * Package: com.sz.admin.monitor.controller + * Description: + */ +@Tag(name = "树结构") +@RestController +@RequestMapping("tree") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class TreeController { + @Resource + private TreeService treeService; + + @Operation(summary = "获取设备管理的树型结构数据") + @GetMapping("/structure") + public ApiResult> getTreeStructure() { + return ApiResult.success(treeService.buildTree()); + } + + @Operation(summary = "获取视频预览的树型结构数据") + @GetMapping("/preview") + public ApiResult> getTreePreview() { + return ApiResult.success(treeService.buildTreePreview()); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/AlarmReportEnums.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/AlarmReportEnums.java new file mode 100644 index 0000000..03c61bd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/AlarmReportEnums.java @@ -0,0 +1,44 @@ +package com.sz.admin.monitor.enums; + +import lombok.Getter; + +/** + * ClassName: AlarmReportEnums + * Package: com.sz.admin.monitor.enums + * Description: 移位报警 + */ +@Getter +public enum AlarmReportEnums { + DISPLACEMENT_ALARM("Displacement",1,"移位报警"), + FIRE_ALARM("Fire",2,"明烟明火报警"), + FACE_ID_ALARM("FaceId",3,"人脸识别报警"), + CAPTURE_FACE_ALARM("CaptureFace", 4, "抓拍到人脸报警"), + HELMET_ALARM("NoHelmet", 5, "未戴安全帽报警"); + private final String alarmType; + private final Integer alarmCode; + private final String alarmDescription; + AlarmReportEnums(String alarmType, Integer alarmCode, String alarmDescription) { + this.alarmType = alarmType; + this.alarmCode = alarmCode; + this.alarmDescription = alarmDescription; + + } + // 根据alarmCode获取枚举值 + public static AlarmReportEnums getAlarmReportEnums(Integer alarmCode) { + for (AlarmReportEnums alarmReportEnums : AlarmReportEnums.values()) { + if (alarmReportEnums.getAlarmCode().equals(alarmCode)) { + return alarmReportEnums; + } + } + return null; + } + public static AlarmReportEnums getAlarmReportEnums(String alarmType) { + for (AlarmReportEnums alarmReportEnums : AlarmReportEnums.values()) { + if (alarmReportEnums.getAlarmType().equals(alarmType)) { + return alarmReportEnums; + } + } + return null; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/DriverEnums.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/DriverEnums.java new file mode 100644 index 0000000..ad66588 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/DriverEnums.java @@ -0,0 +1,6 @@ +package com.sz.admin.monitor.enums; + +public enum DriverEnums { + HKSDK, + DHSDK +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/HCPlayControlEnum.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/HCPlayControlEnum.java new file mode 100644 index 0000000..4ac6622 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/HCPlayControlEnum.java @@ -0,0 +1,56 @@ +package com.sz.admin.monitor.enums; + + +import com.sz.admin.monitor.sdk.hkSdk.HCNetSDK; + +public enum HCPlayControlEnum { + ZOOM_IN(HCNetSDK.ZOOM_IN, "焦距变大"), + ZOOM_OUT(HCNetSDK.ZOOM_OUT, "焦距变小"), + FOCUS_NEAR(HCNetSDK.FOCUS_NEAR, "焦点前调"), + FOCUS_FAR(HCNetSDK.FOCUS_FAR, "焦点后调"), + IRIS_OPEN(HCNetSDK.IRIS_OPEN, "光圈扩大"), + IRIS_CLOSE(HCNetSDK.IRIS_CLOSE, "光圈缩小"), + + TILT_UP(HCNetSDK.TILT_UP, "云台上仰"), + TILT_DOWN(HCNetSDK.TILT_DOWN, "云台下俯"), + PAN_LEFT(HCNetSDK.PAN_LEFT, "云台左转"), + PAN_RIGHT(HCNetSDK.PAN_RIGHT, "云台右转"), + UP_LEFT(HCNetSDK.UP_LEFT, "云台上仰和左转"), + UP_RIGHT(HCNetSDK.UP_RIGHT, "云台上仰和右转"), + DOWN_LEFT(HCNetSDK.DOWN_LEFT, "云台下俯和左转"), + DOWN_RIGHT(HCNetSDK.DOWN_RIGHT, "云台下俯和右转"); + + private Integer code; + private String msg; + + private Integer value; + + private HCPlayControlEnum(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + // 根据Code查找enum + public static HCPlayControlEnum getByCode(Integer code) { + for (HCPlayControlEnum item : HCPlayControlEnum.values()) { + if (item.getCode().equals(code)) { + return item; + } + } + return null; + } + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/HKPTZPreEnum.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/HKPTZPreEnum.java new file mode 100644 index 0000000..3a71643 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/enums/HKPTZPreEnum.java @@ -0,0 +1,41 @@ +package com.sz.admin.monitor.enums; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * ClassName: HKPTZPreEnum + * Package: com.sz.admin.monitor.enums + * Description: + */ +@AllArgsConstructor +@NoArgsConstructor +public enum HKPTZPreEnum { + SET_PRESET("8", "设置预置位"), + CLE_PRESET("9","清除预置位"), + GOTO_PRESET("39","转到预置位"); + private String value; + private String description; + + public static HKPTZPreEnum fromValue(String value) { + for (HKPTZPreEnum item : values()) { + if (item.value.equals(value)) { + return item; + } + } + throw new IllegalArgumentException("Invalid value: " + value); + } + public String getValue() { + return value; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public void setValue(String value) { + this.value = value; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/AlgorithmTaskMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/AlgorithmTaskMapper.java new file mode 100644 index 0000000..be446a0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/AlgorithmTaskMapper.java @@ -0,0 +1,21 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.query.QueryWrapper; +import com.sz.admin.monitor.pojo.po.AlgorithmTask; +import com.sz.admin.monitor.pojo.po.CameraAlarm; + +/** + * ClassName: AlgorithmTaskMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface AlgorithmTaskMapper extends BaseMapper { + default AlgorithmTask selectByCameraId(Long removeId) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(AlgorithmTask.class) + .where(AlgorithmTask::getCameraId).eq(removeId); + return selectOneByQuery(wrapper); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraAlarmMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraAlarmMapper.java new file mode 100644 index 0000000..a4775fc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraAlarmMapper.java @@ -0,0 +1,17 @@ +package com.sz.admin.monitor.mapper; + + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.monitor.pojo.po.CameraAlarm; + +/** + *

+ * 告警工单表 Mapper 接口 + *

+ * + * @author Lz + * @since 2026-02-10 + */ +public interface CameraAlarmMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraMapper.java new file mode 100644 index 0000000..5f109d1 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraMapper.java @@ -0,0 +1,50 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.table.CameraTableDef; + +import java.util.List; + +/** + * ClassName: BzCameraMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface CameraMapper extends BaseMapper { + // 根据NvrId删除摄像头 + default void deleteByNvrId(Long nvrId) + { + QueryWrapper queryWrapper = QueryWrapper.create() + .where(CameraTableDef.CAMERA.NVR_ID.eq(nvrId)); + this.deleteByQuery(queryWrapper); + } + + // 根据NvrId查询摄像头 + default List selectByNvrId(Long id){ + QueryWrapper queryWrapper = QueryWrapper.create() + .where(CameraTableDef.CAMERA.NVR_ID.eq(id)); + return this.selectListByQuery(queryWrapper); + } + + default List selectIdsByEdgeBoxId(Long boxId) { + QueryWrapper queryWrapper = QueryWrapper.create() + .select(CameraTableDef.CAMERA.ID) + .from(CameraTableDef.CAMERA) + .eq(Camera::getBoxId, boxId); + List cameraList = selectListByQuery(queryWrapper); + return cameraList.stream().map(Camera::getId).toList(); + } + + default void updateBoxIdForCameras(Long boxId, List addedIds) { + if (addedIds == null || addedIds.isEmpty()) { + return; + } + UpdateChain.of(Camera.class) + .set(Camera::getBoxId, boxId) + .in(Camera::getId, addedIds) + .update(); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraSnapshotMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraSnapshotMapper.java new file mode 100644 index 0000000..399aa2d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/CameraSnapshotMapper.java @@ -0,0 +1,23 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.query.QueryWrapper; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.CameraSnapshot; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: CameraSnapshotMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface CameraSnapshotMapper extends BaseMapper { + + default void removeByCameraIds(List cameraIds) { + QueryWrapper wrapper = QueryWrapper.create().select().from(CameraSnapshot.class) + .where(CameraSnapshot::getCameraId).in(cameraIds); + this.deleteByQuery(wrapper); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/EdgeBoxMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/EdgeBoxMapper.java new file mode 100644 index 0000000..de6a560 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/EdgeBoxMapper.java @@ -0,0 +1,17 @@ +package com.sz.admin.monitor.mapper; + + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.monitor.pojo.po.EdgeBox; + +/** + *

+ * 边缘盒子 Mapper 接口 + *

+ * + * @author Lz + * @since 2026-03-05 + */ +public interface EdgeBoxMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceImageMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceImageMapper.java new file mode 100644 index 0000000..78d6df0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceImageMapper.java @@ -0,0 +1,13 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.monitor.pojo.po.FaceImage; +import com.sz.admin.monitor.pojo.po.FaceInfo; + +/** + * ClassName: FaceImageMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface FaceImageMapper extends BaseMapper { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceInfoMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceInfoMapper.java new file mode 100644 index 0000000..01ac1a6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceInfoMapper.java @@ -0,0 +1,21 @@ +package com.sz.admin.monitor.mapper; + + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.query.QueryWrapper; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.po.table.FaceInfoTableDef; + +import java.io.Serializable; +import java.util.List; + +/** +*

+* 人脸信息表 Mapper 接口 +*

+* +* @author Lz +* @since 2026-02-26 +*/ +public interface FaceInfoMapper extends BaseMapper { +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceLibraryMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceLibraryMapper.java new file mode 100644 index 0000000..e7733ea --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/FaceLibraryMapper.java @@ -0,0 +1,13 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.po.FaceLibrary; + +/** + * ClassName: FaceLibraryMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface FaceLibraryMapper extends BaseMapper { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/NvrMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/NvrMapper.java new file mode 100644 index 0000000..b6eaf60 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/NvrMapper.java @@ -0,0 +1,12 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.monitor.pojo.po.Nvr; + +/** + * ClassName: BzNvrMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface NvrMapper extends BaseMapper { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/PresetMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/PresetMapper.java new file mode 100644 index 0000000..60c5f96 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/PresetMapper.java @@ -0,0 +1,24 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.query.QueryWrapper; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.Preset; +import com.sz.admin.monitor.pojo.po.table.PresetTableDef; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: PresetMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface PresetMapper extends BaseMapper { + default void removeByCameraIds(List cameraIds) { + QueryWrapper wrapper = QueryWrapper.create() + .from(PresetTableDef.PRESET) + .where(PresetTableDef.PRESET.CAMERA_ID.in(cameraIds)); + this.deleteByQuery(wrapper); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/RegionMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/RegionMapper.java new file mode 100644 index 0000000..9f72a05 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/RegionMapper.java @@ -0,0 +1,12 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.monitor.pojo.po.Region; + +/** + * ClassName: BzRegionMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface RegionMapper extends BaseMapper { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/SubstationMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/SubstationMapper.java new file mode 100644 index 0000000..615c83a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/mapper/SubstationMapper.java @@ -0,0 +1,12 @@ +package com.sz.admin.monitor.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.monitor.pojo.po.Substation; + +/** + * ClassName: BzSubstationMapper + * Package: com.sz.admin.monitor.mapper + * Description: + */ +public interface SubstationMapper extends BaseMapper { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/Ipchannel/ControlDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/Ipchannel/ControlDTO.java new file mode 100644 index 0000000..0f92fd0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/Ipchannel/ControlDTO.java @@ -0,0 +1,16 @@ +package com.sz.admin.monitor.pojo.dto.Ipchannel; + +import lombok.Data; + +/** + * ClassName: ControlDTO + * Package: com.sz.admin.monitor.pojo.dto.Ipchannel + * Description: + */ +@Data +public class ControlDTO { + private Long id; + private Integer direction; + private Integer speed; + private Integer startFlag; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraDTO.java new file mode 100644 index 0000000..8f220cc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraDTO.java @@ -0,0 +1,17 @@ +package com.sz.admin.monitor.pojo.dto.camera; + +import com.sz.admin.monitor.pojo.po.Camera; +import lombok.Data; + +/** + * ClassName: CameraDTO + * Package: com.sz.admin.monitor.pojo.dto + * Description: + */ +@Data +public class CameraDTO extends Camera { + // 摄像头的ip地址 + private String ipAddress; + // 摄像头的管理端口 + private String port; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraListDTO.java new file mode 100644 index 0000000..5205ded --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraListDTO.java @@ -0,0 +1,48 @@ +package com.sz.admin.monitor.pojo.dto.camera; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: CameraListDTO + * Package: com.sz.admin.monitor.pojo.dto.camera + * Description: + */ +@Data +@Schema(description = "Camera查询DTO") +public class CameraListDTO extends PageQuery { + + @Schema(description = "摄像头id") + private Long id; + + @Schema(description = "摄像头名称") + private String name; + + @Schema(description = "所属 NVR") + private Long nvrId; + @Schema(description = "所属 NVR的名称") + private String nvrName; + + @Schema(description = "通道号") + private Integer channelId; + + @Schema(description = "摄像头地址") + private String ipAddress; + + @Schema(description = "1-可见光 2-热成像") + private Integer videoType; + + @Schema(description = "0-枪机 1-球体") + private Integer type; + + @Schema(description = "通道类型 0-海康 1-大华") + private Integer channelDriver; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraUpdateDTO.java new file mode 100644 index 0000000..cf648c5 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/CameraUpdateDTO.java @@ -0,0 +1,47 @@ +package com.sz.admin.monitor.pojo.dto.camera; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: CameraUpdateDTO + * Package: com.sz.admin.monitor.pojo.dto.camera + * Description: + */ +@Data +@Schema(description = "Camera更新DTO") +public class CameraUpdateDTO { + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "摄像机编号") + private String cameraNo; + + @Schema(description = "摄像头名称") + private String name; + + + @Schema(description = "0-枪机 1-球体") + private Integer type; + + @Schema(description = "通道类型 0-海康 1-大华") + private Integer channelDriver; + + @Schema(description = "1-可见光 2-热成像") + private Integer videoType; + + @Schema(description = "是否开启巡检 0-关闭,1-开启") + private Integer enableInspection; + + @Schema(description = "排序号") + private Integer sortOrder; + + @Schema(description = "具体安装位置") + private String installLocation; + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/HistoryDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/HistoryDTO.java new file mode 100644 index 0000000..c71fa03 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/camera/HistoryDTO.java @@ -0,0 +1,22 @@ +package com.sz.admin.monitor.pojo.dto.camera; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; + +/** + * ClassName: HistoryDTO + * Package: com.sz.admin.monitor.pojo.dto + * Description: + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class HistoryDTO { + // 开始时间 + private LocalDate startTime; + // 结束时间 + private LocalDate endTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmCreateDTO.java new file mode 100644 index 0000000..7789b3f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmCreateDTO.java @@ -0,0 +1,57 @@ +package com.sz.admin.monitor.pojo.dto.cameraalarm; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * CameraAlarm添加DTO + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Data +@Schema(description = "CameraAlarm添加DTO") +public class CameraAlarmCreateDTO { + + @Schema(description = "摄像头ID") + private Long cameraId; + + @Schema(description = "通道号") + private Long channelId; + + @Schema(description = "关联的预置位号") + private Integer presetIndex; + + @Schema(description = "报警类型: 1-移位, 2-遮挡") + private Integer alarmType; + + @Schema(description = "基准图路径 ") + private String baseImage; + + @Schema(description = "抓拍图路径") + private String captureImage; + + @Schema(description = "算法返回的详细JSON") + private String algoResult; + + @Schema(description = "状态: 0-未处理, 1-已忽略, 2-已修复") + private Integer status; + + @Schema(description = "处理时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime handleTime; + + @Schema(description = "处理人") + private String handleBy; + + @Schema(description = "处理备注") + private String handleRemark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmImportDTO.java new file mode 100644 index 0000000..cf3c01a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmImportDTO.java @@ -0,0 +1,71 @@ +package com.sz.admin.monitor.pojo.dto.cameraalarm; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelProperty; +import com.sz.excel.annotation.DictFormat; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * CameraAlarm导入DTO + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Data +@Schema(description = "CameraAlarm导入DTO") +public class CameraAlarmImportDTO { + + @ExcelProperty(value = "摄像头ID") + @Schema(description = "摄像头ID") + private Long cameraId; + + @ExcelProperty(value = "通道号") + @Schema(description = "通道号") + private Integer channelId; + + @ExcelProperty(value = "关联的预置位号") + @Schema(description = "关联的预置位号") + private Integer presetIndex; + + @ExcelProperty(value = "报警类型: 1-移位, 2-遮挡") + @DictFormat(dictType = "alarm_type") + @Schema(description = "报警类型: 1-移位, 2-遮挡") + private Integer alarmType; + + @ExcelProperty(value = "基准图路径 ") + @Schema(description = "基准图路径 ") + private String baseImage; + + @ExcelProperty(value = "抓拍图路径") + @Schema(description = "抓拍图路径") + private String captureImage; + + @ExcelProperty(value = "算法返回的详细JSON") + @Schema(description = "算法返回的详细JSON") + private String algoResult; + + @ExcelProperty(value = "状态: 0-未处理, 1-已忽略, 2-已修复") + @DictFormat(dictType = "alarm_status") + @Schema(description = "状态: 0-未处理, 1-已忽略, 2-已修复") + private Integer status; + + @Schema(description = "处理时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime handleTime; + + @ExcelProperty(value = "处理人") + @Schema(description = "处理人") + private String handleBy; + + @ExcelProperty(value = "处理备注") + @Schema(description = "处理备注") + private String handleRemark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmListDTO.java new file mode 100644 index 0000000..94a5ad5 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmListDTO.java @@ -0,0 +1,73 @@ +package com.sz.admin.monitor.pojo.dto.cameraalarm; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import com.sz.core.common.entity.PageQuery; + +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * CameraAlarm查询DTO + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Data +@Schema(description = "CameraAlarm查询DTO") +public class CameraAlarmListDTO extends PageQuery { + + @Schema(description = "摄像头ID") + private Long cameraId; + + @Schema(description = "通道号") + private Integer channelId; + + @Schema(description = "关联的预置位号") + private Integer presetIndex; + + @Schema(description = "报警类型: 1-移位, 2-遮挡") + private Integer alarmType; + + @Schema(description = "基准图路径 ") + private String baseImage; + + @Schema(description = "抓拍图路径") + private String captureImage; + + @Schema(description = "算法返回的详细JSON") + private String algoResult; + + @Schema(description = "状态: 0-未处理, 1-已忽略, 2-已修复") + private Integer status; + + @Schema(description = "处理时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime handleTimeStart; + + @Schema(description = "处理时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime handleTimeEnd; + + @Schema(description = "处理人") + private String handleBy; + + @Schema(description = "处理备注") + private String handleRemark; + + @Schema(description = "告警区域id") + private Long alarmAreaId; + + @Schema(description = "创建时间") + private LocalDateTime alarmTimeStart; + + @Schema(description = "结束时间") + private LocalDateTime alarmTimeEnd; + + @Schema(description = "告警区域") + private String alarmArea; +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmUpdateDTO.java new file mode 100644 index 0000000..c654396 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/cameraalarm/CameraAlarmUpdateDTO.java @@ -0,0 +1,60 @@ +package com.sz.admin.monitor.pojo.dto.cameraalarm; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * CameraAlarm修改DTO + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Data +@Schema(description = "CameraAlarm修改DTO") +public class CameraAlarmUpdateDTO { + + @Schema(description = "主键") + private Long id; + + @Schema(description = "摄像头ID") + private Long cameraId; + + @Schema(description = "通道号") + private Integer channelId; + + @Schema(description = "关联的预置位号") + private Integer presetIndex; + + @Schema(description = "报警类型: 1-移位, 2-遮挡") + private Integer alarmType; + + @Schema(description = "基准图路径 ") + private String baseImage; + + @Schema(description = "抓拍图路径") + private String captureImage; + + @Schema(description = "算法返回的详细JSON") + private String algoResult; + + @Schema(description = "状态: 0-未处理, 1-已忽略, 2-已修复") + private Integer status; + + @Schema(description = "处理时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime handleTime; + + @Schema(description = "处理人") + private String handleBy; + + @Schema(description = "处理备注") + private String handleRemark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/AlarmReportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/AlarmReportDTO.java new file mode 100644 index 0000000..7b5f977 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/AlarmReportDTO.java @@ -0,0 +1,115 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.ToString; +import java.io.Serializable; +import java.util.List; + +/** + */ +@Data +public class AlarmReportDTO implements Serializable { + + + /** + * 告警唯一标识 (用于去重) + */ + @JsonProperty("AlarmId") + private String alarmId; + + /** + * 设备 IP (用于区分是哪个盒子发来的) + */ + @JsonProperty("BoardIp") + private String boardIp; + + /** + * 告警类型标识 + */ + @JsonProperty("Summary") + private String summary; + + /** + * 任务描述 + */ + @JsonProperty("TaskDesc") + private String taskDesc; + + /** + * 任务的标识 + */ + @JsonProperty("TaskSession") + private String taskSession; + + /** + * 告警时间字符串 (2023-12-12 16:36:37) + */ + @JsonProperty("Time") + private String time; + + + /** + * 告警图 (Base64) + * + */ + @JsonProperty("ImageData") + private String imageData; + + /** + * 标注图 (画了框的图,Base64) + */ + @JsonProperty("ImageDataLabeled") + private String imageDataLabeled; + + /** + * 标注图本地路径 (用于前端展示) + */ + @JsonProperty("LocalLabeledPath") + private String localLabeledPath; + + @JsonProperty("LocalRawPath") + private String localRawPath; + + @JsonProperty("Result") + private SimpleResult result; + + + @Data + public static class SimpleResult { + + /** + * 告警中文描述 (如: "未佩戴安全帽") + */ + @JsonProperty("Description") + private String description; + + /** + * 详细属性列表 (如: 置信度、人脸小图等) + */ + @JsonProperty("Properties") + private List properties; + } + + @Data + public static class SimpleProperty { + /** + * 属性名 (如: FrontFaceScore) + */ + @JsonProperty("property") + private String property; + + /** + * 属性中文名 (如: 人脸置信度) + */ + @JsonProperty("desc") + private String desc; + + /** + * 属性值 (可能是数字、字符串或 Base64) + */ + @JsonProperty("value") + @ToString.Exclude + private Object value; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/AlgorithmTaskDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/AlgorithmTaskDTO.java new file mode 100644 index 0000000..1f66271 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/AlgorithmTaskDTO.java @@ -0,0 +1,216 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.Builder; + +import java.io.Serializable; +import java.util.List; + +/** + * 边缘盒子算法任务配置 DTO + * 对应下发给盒子的 JSON 结构 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AlgorithmTaskDTO implements Serializable { + + private Long id; + /** + * 摄像机id + */ + private Long cameraId; + /** + * 任务会话名称 (建议使用唯一标识或 UUID) + */ + @JsonProperty("AlgTaskSession") + private String algTaskSession; + + /** + * 摄像头名称 (如: "cam66" 或 "机柜球机") + */ + @JsonProperty("MediaName") + private String mediaName; + + /** + * 访问第三方服务器的url + */ + private String url; + + + /** + * 任务描述 + */ + @JsonProperty("TaskDesc") + private String taskDesc; + + + /** + * 需要配置的算法 ID 列表 + * 例如: [8, 52] (8-烟火, 52-人脸) + */ + @JsonProperty("AlgInfo") + private List algInfo; + + + /** + * 核心算法参数配置 (嵌套对象) + */ + @JsonProperty("UserData") + private UserDataDto userData; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class UserDataDto implements Serializable { + + /** + * 方法配置 ID 列表 + */ + @JsonProperty("MethodConfig") + private List methodConfig; + + /** + * 是否启用烟火误报过滤 (true: 开启过滤, false: 高灵敏度) + */ + @JsonProperty("enable_fire_smoke_filter") + private Boolean enableFireSmokeFilter; + + /** + * 火焰置信度阈值 (0.0 - 1.0) + */ + @JsonProperty("fire_threshold") + private Double fireThreshold; + + /** + * 烟雾置信度阈值 (0.0 - 1.0) + */ + @JsonProperty("smoke_threshold") + private Double smokeThreshold; + + /** + * 烟火持续时长 (秒),需持续多久才报警 + */ + @JsonProperty("fire_smoke_keep_sec") + private Integer fireSmokeKeepSec; + + /** + * 烟火告警间隔 (秒) + */ + @JsonProperty("fire_smoke_alarm_interval_sec") + private Integer fireSmokeAlarmIntervalSec; + + /** + * 人脸比对相似度阈值 + */ + @JsonProperty("face_reg_similarity") + private Double faceRegSimilarity; + + /** + * 是否启用 GA/T-1400 标准 + */ + @JsonProperty("face_reg_enable_gat1400") + private Boolean faceRegEnableGat1400; + + /** + * 是否启用多次确认 (防抖动) + */ + @JsonProperty("face_reg_enable_multi_check") + private Boolean faceRegEnableMultiCheck; + + /** + * 陌生人阈值 (低于此值视为陌生人) + */ + @JsonProperty("face_low_similarity") + private Double faceLowSimilarity; + + /** + * 人脸ID重复上报间隔 (毫秒) + */ + @JsonProperty("face_id_upload_interval_ms") + private Integer faceIdUploadIntervalMs; + + /** + * 最小人脸像素 (例如 30px) + */ + @JsonProperty("front_face_min_pixel") + private Integer frontFaceMinPixel; + + /** + * 人脸库 ID (例如 1) + */ + @JsonProperty("face_repositories") + private Integer faceRepositories; + + /** + * 是否启用火焰深度模式 + */ + @JsonProperty("enable_fire_deep_mode") + private Boolean enableFireDeepMode; + + /** + * 人脸检测基础阈值 + */ + @JsonProperty("threshold_for_face") + private Double thresholdForFace; + + /** + * 启用 GA/T-1400 + */ + @JsonProperty("capture_is_gat1400_enable") + private Boolean captureIsGat1400Enable; + + /** + * 扩大脸部区域 + */ + @JsonProperty("expand_face_area") + private Boolean expandFaceArea; + + /** + * 更新间隔 + */ + @JsonProperty("face_repeat_upload_ms") + private Integer faceRepeatUploadMs; + + /** + * 抓拍阈值 + */ + @JsonProperty("front_face_threshold") + private Double frontFaceThreshold; + + /** + * 仅上报正脸 + */ + @JsonProperty("is_front_only") + private Boolean isFrontOnly; + + /** + * 上传裁剪的人脸图 + */ + @JsonProperty("upload_cropped_face_image") + private Boolean uploadCroppedFaceImage; + + /** + * 安全帽阈值 + */ + @JsonProperty("helmet_det_threshold") + private Double helmetDetThreshold; + + /** + * 无安全帽阈值 + */ + @JsonProperty("no_helmet_det_threshold") + private Double noHelmetDetThreshold; + + /** + * 违规持续时长 + */ + @JsonProperty("helmet_v3_keep_no_sec") + private Integer helmetV3KeepNoSec; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/BoxAlarmReportDto.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/BoxAlarmReportDto.java new file mode 100644 index 0000000..18d9afc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/BoxAlarmReportDto.java @@ -0,0 +1,39 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import cn.idev.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.sz.admin.monitor.pojo.vo.edgebox.AlarmReportVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import java.time.LocalDateTime; + +/** + * ClassName: BoxAlarmReportDto + * Package: com.sz.admin.monitor.pojo.dto.edgebox + * Description: + */ +@Data +public class BoxAlarmReportDto { + @Schema(description = "摄像头名称") + private String cameraName; + @Schema(description = "摄像机编号") + private String cameraNo; + @Schema(description = "摄像头ID") + private Long cameraId; + @Schema(description = "报警的url") + private String url; + @Schema(description = "报警的类型") + private String alarmReportType; + @Schema(description = "报警的时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime alarmReportTime; + @Schema(description = "基准图") + private String baseImage; + @Schema(description = "抓拍图") + private String captureImage; + @Schema(description = "报警的原因") + private String description; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxBindCamerasDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxBindCamerasDTO.java new file mode 100644 index 0000000..3d7f3e4 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxBindCamerasDTO.java @@ -0,0 +1,19 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * ClassName: EdgeBoxBindCamerasDTO + * Package: com.sz.admin.monitor.pojo.dto.edgebox + * Description: + */ +@Data +public class EdgeBoxBindCamerasDTO { + @Schema(description = "盒子的id") + private Long boxId; + @Schema(description = "要绑定的摄像头id的集合") + private List cameraIds; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxCreateDTO.java new file mode 100644 index 0000000..80ac296 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxCreateDTO.java @@ -0,0 +1,43 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * EdgeBox添加DTO + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Data +@Schema(description = "EdgeBox添加DTO") +public class EdgeBoxCreateDTO { + + @Schema(description = "盒子的名称") + private String name; + + @Schema(description = "盒子的IP地址") + private String ip; + @Schema(description = "盒子的端口") + private String port; + + @Schema(description = "子网掩码") + private String mask; + + @Schema(description = "网关地址") + private String gateway; + + @Schema(description = "盒子的账号") + private String account; + + @Schema(description = "密码") + private String password; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxImportDTO.java new file mode 100644 index 0000000..a5ddb9e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxImportDTO.java @@ -0,0 +1,51 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * EdgeBox导入DTO + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Data +@Schema(description = "EdgeBox导入DTO") +public class EdgeBoxImportDTO { + + @ExcelProperty(value = "盒子的名称") + @Schema(description = "盒子的名称") + private String name; + + @ExcelProperty(value = "盒子的IP地址") + @Schema(description = "盒子的IP地址") + private String ip; + @ExcelProperty(value = "盒子的端口") + @Schema(description = "盒子的端口") + private String port; + + @ExcelProperty(value = "子网掩码") + @Schema(description = "子网掩码") + private String mask; + + @ExcelProperty(value = "网关地址") + @Schema(description = "网关地址") + private String gateway; + + @ExcelProperty(value = "盒子的账号") + @Schema(description = "盒子的账号") + private String account; + + @ExcelProperty(value = "密码") + @Schema(description = "密码") + private String password; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxListDTO.java new file mode 100644 index 0000000..3b1b302 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxListDTO.java @@ -0,0 +1,44 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import com.sz.core.common.entity.PageQuery; + +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * EdgeBox查询DTO + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Data +@Schema(description = "EdgeBox查询DTO") +public class EdgeBoxListDTO extends PageQuery { + + @Schema(description = "盒子的名称") + private String name; + + @Schema(description = "盒子的IP地址") + private String ip; + @Schema(description = "盒子的端口") + private String port; + + @Schema(description = "子网掩码") + private String mask; + + @Schema(description = "网关地址") + private String gateway; + + @Schema(description = "盒子的账号") + private String account; + + @Schema(description = "密码") + private String password; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxUpdateDTO.java new file mode 100644 index 0000000..5c13b2d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/EdgeBoxUpdateDTO.java @@ -0,0 +1,46 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * EdgeBox修改DTO + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Data +@Schema(description = "EdgeBox修改DTO") +public class EdgeBoxUpdateDTO { + + @Schema(description = "主键") + private Long id; + + @Schema(description = "盒子的名称") + private String name; + + @Schema(description = "盒子的IP地址") + private String ip; + + @Schema(description = "盒子的端口") + private String port; + + @Schema(description = "子网掩码") + private String mask; + + @Schema(description = "网关地址") + private String gateway; + + @Schema(description = "盒子的账号") + private String account; + + @Schema(description = "密码") + private String password; +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/SetupChannelDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/SetupChannelDTO.java new file mode 100644 index 0000000..e87b340 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/edgebox/SetupChannelDTO.java @@ -0,0 +1,18 @@ +package com.sz.admin.monitor.pojo.dto.edgebox; + +import lombok.Data; + +/** + * ClassName: SetupChannelDTO + * Package: com.sz.admin.monitor.pojo.dto.edgebox + * Description: + */ +@Data +public class SetupChannelDTO { + // 必选 + private String MediaName; + // 必选 + private String mediaUrl; + // 通道别名 可选 + private String mediaDesc; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoCreateDTO.java new file mode 100644 index 0000000..ea3bc1b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoCreateDTO.java @@ -0,0 +1,37 @@ +package com.sz.admin.monitor.pojo.dto.faceinfo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * FaceInfo添加DTO + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceInfo添加DTO") +public class FaceInfoCreateDTO { + + @Schema(description = "用户标识") + private String faceSign; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "人脸库id") + private Long libraryId; + + @Schema(description = "人脸url") + private String imageUrl; + + @Schema(description = "注册时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime registerTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoImportDTO.java new file mode 100644 index 0000000..5aba4fe --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoImportDTO.java @@ -0,0 +1,38 @@ +package com.sz.admin.monitor.pojo.dto.faceinfo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; +/** + *

+ * FaceInfo导入DTO + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceInfo导入DTO") +public class FaceInfoImportDTO { + + @ExcelProperty(value = "用户标识") + @Schema(description = "用户标识") + private String faceSign; + + @ExcelProperty(value = "姓名") + @Schema(description = "姓名") + private String name; + + @ExcelProperty(value = "人脸库id") + @Schema(description = "人脸库id") + private Long libraryId; + + @Schema(description = "注册时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime registerTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoListDTO.java new file mode 100644 index 0000000..d40aacc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoListDTO.java @@ -0,0 +1,38 @@ +package com.sz.admin.monitor.pojo.dto.faceinfo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import com.sz.core.common.entity.PageQuery; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; +/** + *

+ * FaceInfo查询DTO + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceInfo查询DTO") +public class FaceInfoListDTO extends PageQuery { + + @Schema(description = "用户标识") + private String faceSign; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "人脸库id") + private Long libraryId; + + @Schema(description = "注册时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime registerTimeStart; + + @Schema(description = "注册时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime registerTimeEnd; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoUpdateDTO.java new file mode 100644 index 0000000..1e37999 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/faceinfo/FaceInfoUpdateDTO.java @@ -0,0 +1,37 @@ +package com.sz.admin.monitor.pojo.dto.faceinfo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * FaceInfo修改DTO + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceInfo修改DTO") +public class FaceInfoUpdateDTO { + + @Schema(description = "") + private Long id; + + @Schema(description = "用户标识") + private String faceSign; + + @Schema(description = "姓名") + private String name; + + @Schema(description = "人脸库id") + private Long libraryId; + + @Schema(description = "注册时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime registerTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryCreateDTO.java new file mode 100644 index 0000000..66f7afb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryCreateDTO.java @@ -0,0 +1,18 @@ +package com.sz.admin.monitor.pojo.dto.facelibrary; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ClassName: FaceLibraryCreateDTO + * Package: com.sz.admin.monitor.pojo.dto.faceinfo + * Description: + */ +@Data +@Schema(description = "FaceLibrary添加DTO") +public class FaceLibraryCreateDTO { + @Schema(description = "库名称") + private String name; + @Schema(description = "边缘盒子的id") + private Long boxId; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryImportDTO.java new file mode 100644 index 0000000..0b0aae2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryImportDTO.java @@ -0,0 +1,24 @@ +package com.sz.admin.monitor.pojo.dto.facelibrary; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import cn.idev.excel.annotation.ExcelProperty; +/** + *

+ * FaceLibrary导入DTO + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceLibrary导入DTO") +public class FaceLibraryImportDTO { + + @ExcelProperty(value = "库名称") + @Schema(description = "库名称") + private String name; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryListDTO.java new file mode 100644 index 0000000..cc0981a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryListDTO.java @@ -0,0 +1,23 @@ +package com.sz.admin.monitor.pojo.dto.facelibrary; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +/** + * ClassName: FaceLibraryListDTO + * Package: com.sz.admin.monitor.pojo.dto.facelibrary + * Description: + */ +@Data +@Schema(description = "FaceLibrary查询DTO") +public class FaceLibraryListDTO extends PageQuery { + @Schema(description = "人脸库名称") + private String name; + @Schema(description = "边缘盒子的id") + private Long boxId; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryUpdateDTO.java new file mode 100644 index 0000000..3c45712 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/facelibrary/FaceLibraryUpdateDTO.java @@ -0,0 +1,25 @@ +package com.sz.admin.monitor.pojo.dto.facelibrary; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +/** + *

+ * FaceLibrary修改DTO + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceLibrary修改DTO") +public class FaceLibraryUpdateDTO { + + @Schema(description = "") + private Long id; + + @Schema(description = "库名称") + private String name; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrCreateDTO.java new file mode 100644 index 0000000..c5b87c1 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrCreateDTO.java @@ -0,0 +1,45 @@ +package com.sz.admin.monitor.pojo.dto.nvr; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: RegionCreateDTO + * Package: com.sz.admin.monitor.pojo.dto.region + * Description: + */ +@Data +@Schema(description = "NVR添加DTO") +public class NvrCreateDTO { + + + @Schema(description = "NVR设备名称") + private String name; + + @Schema(description = "所属变电站Id") + private Long stationId; + + @Schema(description = "IP地址") + private String ip; + + @Schema(description = "端口号") + private Integer port; + + @Schema(description = "登录用户名") + private String account; + + @Schema(description = "密码") + private String password; + + + @Schema(description = "nvr的类型,1-大华, 0-海康威视") + private Integer driver; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrDTO.java new file mode 100644 index 0000000..ba87c81 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrDTO.java @@ -0,0 +1,28 @@ +package com.sz.admin.monitor.pojo.dto.nvr; + +import com.sz.admin.monitor.pojo.dto.camera.CameraDTO; +import com.sz.admin.monitor.pojo.dto.camera.HistoryDTO; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.sdk.hkSdk.HCNetTools; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * ClassName: CameraDTO + * Package: com.sz.admin.monitor.pojo.dto + * Description: + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class NvrDTO extends Nvr { + // 通道列表 + private List channelList; + private HCNetTools hcNetTools; + private HistoryDTO historyDTO; + // IPC地址 + private String ipcAddress; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrListDTO.java new file mode 100644 index 0000000..abe14ec --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrListDTO.java @@ -0,0 +1,45 @@ +package com.sz.admin.monitor.pojo.dto.nvr; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: NvrListDTO + * Package: com.sz.admin.monitor.pojo.dto.nvr + * Description: + */ +@Data +@Schema(description = "NVR查询DTO") +public class NvrListDTO extends PageQuery { + + + @Schema(description = "NVR设备ID") + private Long id; + + @Schema(description = "NVR设备名称") + private String name; + + @Schema(description = "所属变电站Id") + private Long stationId; + + @Schema(description = "IP地址") + private String ip; + + @Schema(description = "端口号") + private Integer port; + + + @Schema(description = "nvr的类型,1-大华, 0-海康威视") + private Integer driver; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrUpdateDTO.java new file mode 100644 index 0000000..731a2eb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/nvr/NvrUpdateDTO.java @@ -0,0 +1,47 @@ +package com.sz.admin.monitor.pojo.dto.nvr; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: NvrUpdateDTO + * Package: com.sz.admin.monitor.pojo.dto.nvr + * Description: + */ +@Data +@Schema(description = "NVR修改DTO") +public class NvrUpdateDTO { + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "NVR设备名称") + private String name; + + @Schema(description = "所属变电站Id") + private Long stationId; + + @Schema(description = "IP地址") + private String ip; + + @Schema(description = "端口号") + private Integer port; + + @Schema(description = "登录用户名") + private String account; + + @Schema(description = "密码") + private String password; + + + @Schema(description = "nvr的类型,1-大华, 0-海康威视") + private Integer driver; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/preset/PresetCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/preset/PresetCreateDTO.java new file mode 100644 index 0000000..71b7d23 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/preset/PresetCreateDTO.java @@ -0,0 +1,31 @@ +package com.sz.admin.monitor.pojo.dto.preset; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ClassName: PresetCreateDTO + * Package: com.sz.admin.monitor.pojo.dto.preset + * Description: + */ +@Data +@Schema(description = "Preset添加DTO") +public class PresetCreateDTO { + @Schema(description = "预置位id") + private Integer presetId; + + @Schema(description = "摄像机通道id") + private Integer channelId; + @Schema(description = "摄像机id") + private Long cameraId; + + @Schema(description = "预置位名称") + private String presetName; + + @Schema(description = "预置位描述") + private String description; + @Schema(description = "0-不是基准点,1-为基准点") + private Integer isBasicPoint; + @Schema(description = "上报的url") + private String presetUrl; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/preset/PresetDeleteDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/preset/PresetDeleteDTO.java new file mode 100644 index 0000000..0924370 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/preset/PresetDeleteDTO.java @@ -0,0 +1,20 @@ +package com.sz.admin.monitor.pojo.dto.preset; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ClassName: PresetDeleteDTO + * Package: com.sz.admin.monitor.pojo.dto.preset + * Description: + */ +@Data +@Schema(description = "Preset删除DTO") +public class PresetDeleteDTO { + @Schema(description = "摄像机id") + private Long cameraId; + @Schema(description = "通道id") + private Integer channelId; + @Schema(description = "当前预置点") + private Integer currentPresetIndex; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionCreateDTO.java new file mode 100644 index 0000000..cd4d478 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionCreateDTO.java @@ -0,0 +1,36 @@ +package com.sz.admin.monitor.pojo.dto.region; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: RegionCreateDTO + * Package: com.sz.admin.monitor.pojo.dto.region + * Description: + */ +@Data +@Schema(description = "Region添加DTO") +public class RegionCreateDTO { + + @Schema(description = "区域名称") + private String name; + + @Schema(description = "父级ID") + private Long parentId; + + @Schema(description = "1-市级 2-区县级") + private Integer level; + + @Schema(description = "0-区县 1-超高压") + private Integer type; + + @Schema(description = "行政编码/业务编码") + private String code; + + @Schema(description = "排序字段") + private Integer sort; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionListDTO.java new file mode 100644 index 0000000..7152275 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionListDTO.java @@ -0,0 +1,32 @@ +package com.sz.admin.monitor.pojo.dto.region; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: RegionListDTO + * Package: com.sz.admin.monitor.pojo.dto.region + * Description: + */ +@Data +@Schema(description = "Region查询DTO") +public class RegionListDTO extends PageQuery { + + @Schema(description = "区域名称") + private String name; + + @Schema(description = "1-市级 2-区县级") + private Integer level; + + @Schema(description = "0-区县 1-超高压") + private Integer type; + + @Schema(description = "行政编码/业务编码") + private String code; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionUpdateDTO.java new file mode 100644 index 0000000..f430c95 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/region/RegionUpdateDTO.java @@ -0,0 +1,36 @@ +package com.sz.admin.monitor.pojo.dto.region; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: RegionUpdateDTO + * Package: com.sz.admin.monitor.pojo.dto.region + * Description: + */ +@Data +@Schema(description = "Region修改DTO") +public class RegionUpdateDTO { + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "区域名称") + private String name; + + @Schema(description = "父级ID (0表示根节点)") + private Long parentId; + + @Schema(description = "1-市级 2-区县级") + private Integer level; + + @Schema(description = "0-区县 1-超高压") + private Integer type; + + @Schema(description = "行政编码/业务编码") + private String code; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationCreateDTO.java new file mode 100644 index 0000000..99fb068 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationCreateDTO.java @@ -0,0 +1,33 @@ +package com.sz.admin.monitor.pojo.dto.substation; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Substation添加DTO + *

+ * + * @author Lz + * @since 2026-03-06 + */ +@Data +@Schema(description = "Substation添加DTO") +public class SubstationCreateDTO { + + @Schema(description = "变电站名称") + private String name; + + @Schema(description = "所属区域") + private Long regionId; + + @Schema(description = "1- 普通变电站 2-超高压变电站") + private Integer type; + + @Schema(description = "详细地址") + private String address; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationImportDTO.java new file mode 100644 index 0000000..fcb4f91 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationImportDTO.java @@ -0,0 +1,38 @@ +package com.sz.admin.monitor.pojo.dto.substation; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; +/** + *

+ * Substation导入DTO + *

+ * + * @author Lz + * @since 2026-03-06 + */ +@Data +@Schema(description = "Substation导入DTO") +public class SubstationImportDTO { + + @ExcelProperty(value = "变电站名称") + @Schema(description = "变电站名称") + private String name; + + @ExcelProperty(value = "所属区域") + @Schema(description = "所属区域") + private Long regionId; + + @ExcelProperty(value = "1- 普通变电站 2-超高压变电站") + @Schema(description = "1- 普通变电站 2-超高压变电站") + private Integer type; + + @ExcelProperty(value = "详细地址") + @Schema(description = "详细地址") + private String address; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationListDTO.java new file mode 100644 index 0000000..6796ac3 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationListDTO.java @@ -0,0 +1,33 @@ +package com.sz.admin.monitor.pojo.dto.substation; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import com.sz.core.common.entity.PageQuery; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; +/** + *

+ * Substation查询DTO + *

+ * + * @author Lz + * @since 2026-03-06 + */ +@Data +@Schema(description = "Substation查询DTO") +public class SubstationListDTO extends PageQuery { + + @Schema(description = "变电站名称") + private String name; + + @Schema(description = "所属区域") + private Long regionId; + + @Schema(description = "1- 普通变电站 2-超高压变电站") + private Integer type; + + @Schema(description = "详细地址") + private String address; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationUpdateDTO.java new file mode 100644 index 0000000..3f6e7fb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/dto/substation/SubstationUpdateDTO.java @@ -0,0 +1,36 @@ +package com.sz.admin.monitor.pojo.dto.substation; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Substation修改DTO + *

+ * + * @author Lz + * @since 2026-03-06 + */ +@Data +@Schema(description = "Substation修改DTO") +public class SubstationUpdateDTO { + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "变电站名称") + private String name; + + @Schema(description = "所属区域") + private Long regionId; + + @Schema(description = "1- 普通变电站 2-超高压变电站") + private Integer type; + + @Schema(description = "详细地址") + private String address; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/AlgorithmTask.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/AlgorithmTask.java new file mode 100644 index 0000000..b941a71 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/AlgorithmTask.java @@ -0,0 +1,92 @@ +package com.sz.admin.monitor.pojo.po; + +import com.fasterxml.jackson.databind.JsonNode; +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.mybatisflex.core.activerecord.Model; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 算法任务实体类 + */ +@Data +@Table(value = "ry_algorithm_task",onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "算法任务实体类") +public class AlgorithmTask implements Serializable { + + + @Serial + private static final long serialVersionUID = 1L; + /** + * 主键 + */ + @Id(keyType = KeyType.Auto) + private Long id; + + /** + * 摄像机id + */ + private Long cameraId; + + /** + * 访问第三方服务器的url + */ + private String url; + + /** + * 任务编号 + */ + private String algTaskSession; + + /** + * 摄像头名称 + */ + private String mediaName; + + /** + * 任务描述 + */ + private String taskDesc; + + /** + * 算法列表 + */ + @Column(typeHandler = JacksonTypeHandler.class) + private List algInfo; + + /** + * 算法参数(json格式) + */ + @Column(typeHandler = JacksonTypeHandler.class) + private JsonNode userData; + + /** + * 逻辑删除标识:0-正常,1-已删除 + */ + @Column(isLogicDelete = true) + @Schema(description = "是否删除") + private String isDeleted; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Camera.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Camera.java new file mode 100644 index 0000000..0f0c7d6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Camera.java @@ -0,0 +1,95 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.*; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.io.Serial; +import java.time.LocalDateTime; + +/** + *

+ * 变电站摄像头业务表 + *

+ * + * @author sz + * @since 2026-02-03 + */ +@Data +@Table(value = "ry_camera", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "变电站摄像头业务表") +public class Camera implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "摄像机编号") + private String cameraNo; + + @Schema(description = "摄像头名称") + private String name; + + @Schema(description = "所属 NVR") + private Long nvrId; + + @Schema(description = "边缘盒子的id") + private Long boxId; + + @Schema(description = "通道号") + private Integer channelId; + + @Schema(description = "摄像头地址") + private String ipAddress; + + @Schema(description = "1-可见光 2-热成像") + private Integer videoType; + + @Schema(description = "0-枪机 1-球体 2-云台") + private Integer type; + + @Schema(description = "守望位 1-开启,0-关闭") + private Integer watchfulState; + + @Schema(description = "守望归位的时间(单位秒)") + private Integer watchfulTime; + + @Schema(description = "守望归位的预置位") + private Integer watchfulIndex; + + @Schema(description = "基准图") + private String homeImagePath; + + @Schema(description = "是否开启巡检 0-关闭,1-开启") + private Integer enableInspection; + + @Schema(description = "通道类型 0-海康 1-大华") + private Integer channelDriver; + + @Schema(description = "具体安装位置") + private String installLocation; + + @Schema(description = "排序号") + private Integer sortOrder; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + /** + * 逻辑删除标识:0-正常,1-已删除 + */ + @Column(isLogicDelete = true) + @Schema(description = "是否删除") + private String isDeleted; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/CameraAlarm.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/CameraAlarm.java new file mode 100644 index 0000000..24276ef --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/CameraAlarm.java @@ -0,0 +1,86 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.io.Serial; + +import com.sz.mysql.EntityChangeListener; + +import java.time.LocalDateTime; + +/** + *

+ * 告警工单表 + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Data +@Table(value = "ry_camera_alarm", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "告警工单表") +public class CameraAlarm implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "主键") + private Long id; + + @Schema(description = "摄像头ID") + private Long cameraId; + + @Schema(description = "摄像头名称") + private String cameraName; + + @Schema(description = "摄像机编号") + private String cameraNo; + + @Schema(description = "通道号") + private Integer channelId; + + @Schema(description = "关联的预置位号") + private Integer presetIndex; + + @Schema(description = "告警区域id") + private Long alarmAreaId; + + @Schema(description = "报警类型: 1-移位, 2-明烟明火报警,3-人脸识别,4-脸部抓拍,5-安全帽检测") + private Integer alarmType; + + @Schema(description = "基准图路径 ") + private String baseImage; + + @Schema(description = "抓拍图路径") + private String captureImage; + + @Schema(description = "算法返回的详细JSON") + private String algoResult; + @Schema(description = "违规描述") + private String summary; + @Schema(description = "任务描述") + private String taskDesc; + @Schema(description = "任务会话") + private String taskSession; + @Schema(description = "报警盒子IP") + private String boardIp; + @Schema(description = "状态: 0-未处理, 1-已忽略, 2-已修复") + private Integer status; + @Schema(description = "处理时间") + private LocalDateTime handleTime; + + @Schema(description = "处理人") + private String handleBy; + + @Schema(description = "处理备注") + private String handleRemark; + + @Schema(description = "") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/CameraSnapshot.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/CameraSnapshot.java new file mode 100644 index 0000000..80e482c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/CameraSnapshot.java @@ -0,0 +1,57 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * ClassName: CameraSnapshot + * Package: com.sz.admin.monitor.pojo.po + * Description: + */ +@Data +@Table(value = "ry_camera_snapshot", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "摄像头抓图表") +public class CameraSnapshot implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "摄像头ID") + private Long cameraId; + + @Schema(description = "通道id") + private Integer channelId; + + @Schema(description = "预置点索引") + private Integer presetIndex; + + @Schema(description = "图片保存路径") + private String imagePath; + + @Schema(description = "1-定时巡检, 2-守望归位检测, 3-手动抓拍") + private Integer checkType; + + @Schema(description = "0-正常, 1-移位") + private Integer isAbnormal; + + /** + * 逻辑删除标识:0-正常,1-已删除 + */ + @Column(isLogicDelete = true) + @Schema(description = "是否删除") + private String isDeleted; + + @Schema(description = "抓拍时间") + private LocalDateTime createTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/EdgeBox.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/EdgeBox.java new file mode 100644 index 0000000..e0da1e4 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/EdgeBox.java @@ -0,0 +1,61 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.io.Serial; + +import com.sz.mysql.EntityChangeListener; + +import java.time.LocalDateTime; + +/** + *

+ * 边缘盒子 + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Data +@Table(value = "ry_edge_box", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "边缘盒子") +public class EdgeBox implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "主键") + private Long id; + + @Schema(description = "盒子的名称") + private String name; + + @Schema(description = "盒子的IP地址") + private String ip; + + @Schema(description = "盒子的端口") + private String port; + @Schema(description = "子网掩码") + private String mask; + + @Schema(description = "网关地址") + private String gateway; + + @Schema(description = "盒子的账号") + private String account; + + @Schema(description = "密码") + private String password; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceImage.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceImage.java new file mode 100644 index 0000000..34ab745 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceImage.java @@ -0,0 +1,30 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: FaceImage + * Package: com.sz.admin.monitor.pojo.po + * Description: + */ +@Data +@Table(value = "ry_face_image", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "人脸图片表") +public class FaceImage { + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + @Schema(description = "人脸信息表id") + private Long faceInfoId; + @Schema(description = "图片路径") + private String imageUrl; + @Schema(description = "上传时间") + private LocalDateTime uploadTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceInfo.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceInfo.java new file mode 100644 index 0000000..928892a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceInfo.java @@ -0,0 +1,32 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: FaceInfo + * Package: com.sz.admin.monitor.pojo.po + * Description: + */ +@Data +@Table(value = "ry_face_info", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "人脸信息表") +public class FaceInfo { + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + @Schema(description = "用户标识") + private String faceSign; + @Schema(description = "姓名") + private String name; + @Schema(description = "人脸库id") + private Long libraryId; + @Schema(description = "注册时间") + private LocalDateTime registerTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceLibrary.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceLibrary.java new file mode 100644 index 0000000..7c346d9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/FaceLibrary.java @@ -0,0 +1,33 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.mybatisflex.core.keygen.KeyGenerators; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.Getter; + +import java.io.Serializable; + +/** + * 人脸库表 实体类 + */ + +@Data +@Table(value = "ry_face_library", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "人脸库表") +public class FaceLibrary implements Serializable { + + private static final long serialVersionUID = 1L; + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + @Schema(description = "库名称") + private String name; + @Schema(description = "库ID") + private Integer albumId; + @Schema(description = "边缘盒子的id") + private Long boxId; +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Nvr.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Nvr.java new file mode 100644 index 0000000..6d1d681 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Nvr.java @@ -0,0 +1,66 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.*; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.io.Serial; +import java.time.LocalDateTime; + +/** + *

+ * NVR录像机设备表 + *

+ * + * @author sz + * @since 2026-02-03 + */ +@Data +@Table(value = "ry_nvr", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "NVR录像机设备表") +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Nvr implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "NVR设备名称") + private String name; + + @Schema(description = "所属变电站Id") + private Long stationId; + + @Schema(description = "IP地址") + private String ip; + + @Schema(description = "端口号") + private Integer port; + + @Schema(description = "登录用户名") + private String account; + + @Schema(description = "密码") + private String password; + + + @Schema(description = "nvr的类型,1-大华, 0-海康威视") + private Integer driver; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Preset.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Preset.java new file mode 100644 index 0000000..153e786 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Preset.java @@ -0,0 +1,59 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * ClassName: Preset + * Package: com.sz.admin.monitor.pojo.po + * Description: + */ +@Data +@Table(value = "ry_preset", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "预置位业务表") +public class Preset { + @Id(keyType = KeyType.Auto) + @Schema(description = "主键") + private Long id; + + @Schema(description = "预置位id") + private Integer presetId; + + @Schema(description = "摄像机id") + private Long cameraId; + + @Schema(description = "通道id") + private Integer channelId; + + @Schema(description = "预置位名称") + private String presetName; + + @Schema(description = "预置位描述") + private String description; + + @Schema(description = "0-不是基准点,1-为基准点") + private Integer isBasicPoint; + + @Schema(description = "上报的url") + private String presetUrl; + + /** + * 逻辑删除标识:0-正常,1-已删除 + */ + @Column(isLogicDelete = true) + @Schema(description = "是否删除") + private String isDeleted; + + @Schema(description = "创建时间") + private LocalDateTime createdTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/RecordFile.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/RecordFile.java new file mode 100644 index 0000000..2b4d151 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/RecordFile.java @@ -0,0 +1,17 @@ +package com.sz.admin.monitor.pojo.po; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RecordFile { + + private String fileName; // 录像文件名 + private LocalDateTime startTime; // 录像开始时间 + private LocalDateTime stopTime; // 录像结束时间 + private long fileSize; // 录像文件大小 (字节) +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Region.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Region.java new file mode 100644 index 0000000..dc36f1c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Region.java @@ -0,0 +1,53 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.*; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.io.Serial; +import java.time.LocalDateTime; + +/** + *

+ * 区县表 + *

+ * + * @author sz + * @since 2026-02-03 + */ +@Data +@Table(value = "ry_region", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "区县表") +public class Region implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "区域名称") + private String name; + + @Schema(description = "父级ID (0表示根节点)") + private Long parentId; + + @Schema(description = "1-市级 2-区县级") + private Integer level; + + @Schema(description = "0-区县 1-超高压") + private Integer type; + + @Schema(description = "行政编码/业务编码") + private String code; + + @Schema(description = "排序字段") + private Integer sort; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Substation.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Substation.java new file mode 100644 index 0000000..0294b14 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/po/Substation.java @@ -0,0 +1,50 @@ +package com.sz.admin.monitor.pojo.po; + +import com.mybatisflex.annotation.*; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.io.Serial; +import java.time.LocalDateTime; + +/** + *

+ * 变电站和超高压信息表 + *

+ * + * @author sz + * @since 2026-02-03 + */ +@Data +@Table(value = "ry_substation", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "变电站和超高压信息表") +public class Substation implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "变电站名称") + private String name; + + @Schema(description = "所属区域") + private Long regionId; + + @Schema(description = "1- 普通变电站 2-超高压变电站") + private Integer type; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "0-停用 1-启用") + private Integer status; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/Region/RegionVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/Region/RegionVO.java new file mode 100644 index 0000000..bba336e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/Region/RegionVO.java @@ -0,0 +1,44 @@ +package com.sz.admin.monitor.pojo.vo.Region; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * ClassName: RegionVO + * Package: com.sz.admin.monitor.pojo.vo.Region + * Description: + */ +@Data +@Schema(description = "Region返回vo") +public class RegionVO { + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "区域名称") + private String name; + + @Schema(description = "父级ID (0表示根节点)") + private Long parentId; + + @Schema(description = "1-市级 2-区县级") + private Integer level; + + @Schema(description = "0-区县 1-超高压") + private Integer type; + + @Schema(description = "行政编码/业务编码") + private String code; + + @Schema(description = "排序字段") + private Integer sort; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/camera/CameraVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/camera/CameraVO.java new file mode 100644 index 0000000..97cbc05 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/camera/CameraVO.java @@ -0,0 +1,97 @@ +package com.sz.admin.monitor.pojo.vo.camera; + +import cn.idev.excel.annotation.ExcelProperty; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * ClassName: CameraVO + * Package: com.sz.admin.monitor.pojo.vo + * Description: + */ +@Data +@Schema(description = "camera返回vo") +public class CameraVO { + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "摄像头名称") + private String name; + + @Schema(description = "摄像机编号") + private String cameraNo; + + @Schema(description = "所属 NVR") + private Long nvrId; + + @Schema(description = "边缘盒子的id") + private Long boxId; + @Schema(description = "所属 NVR的名称") + private String nvrName; + + @Schema(description = "通道号") + private Integer channelId; + + @Schema(description = "摄像头地址") + private String ipAddress; + + @Schema(description = "1-可见光 2-热成像") + private Integer videoType; + + @Schema(description = "0-枪机 1-球体") + private Integer type; + + @ExcelProperty(value = "摄像头id") + @Schema(description = "摄像头id") + private String cameraId; + + @Schema(description = "基准图") + private String homeImagePath; + + @Schema(description = "是否开启巡检 0-关闭,1-开启") + private Integer enableInspection; + + @Schema(description = "守望位 1-开启,0-关闭") + private Integer watchfulState; + + @Schema(description = "守望归位的时间(单位秒)") + private Integer watchfulTime; + + @Schema(description = "守望归位的预置位") + private Integer watchfulIndex; + + @Schema(description = "通道类型 0-海康 1-大华") + private Integer channelDriver; + + @Schema(description = "具体安装位置") + private String installLocation; + + @Schema(description = "排序号") + private Integer sortOrder; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "rtsp流") + private String rtsp; + + @Schema(description = "算法列表") + private List algInfo; + @Data + public static class CameraTypeEnum { + + private long id; + + private String cameraId; + + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/cameraalarm/CameraAlarmVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/cameraalarm/CameraAlarmVO.java new file mode 100644 index 0000000..7e91783 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/cameraalarm/CameraAlarmVO.java @@ -0,0 +1,87 @@ +package com.sz.admin.monitor.pojo.vo.cameraalarm; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import com.sz.excel.annotation.DictFormat; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * CameraAlarm返回vo + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Data +@Schema(description = "CameraAlarm返回vo") +public class CameraAlarmVO { + + @ExcelIgnore + @Schema(description = "主键") + private Long id; + @ExcelProperty(value = "摄像头名称") + @Schema(description = "摄像头名称") + private String cameraName; + @ExcelProperty(value = "摄像机编号") + @Schema(description = "摄像机编号") + private String cameraNo; + @ExcelProperty(value = "摄像头ID") + @Schema(description = "摄像头ID") + private Long cameraId; + + @ExcelProperty(value = "通道号") + @Schema(description = "通道号") + private Integer channelId; + + @ExcelProperty(value = "告警区域id") + @Schema(description = "告警区域id") + private Long alarmAreaId; + + @ExcelProperty(value = "关联的预置位号") + @Schema(description = "关联的预置位号") + private Integer presetIndex; + + @ExcelProperty(value = "报警类型: 1-移位, 2-遮挡") + @DictFormat(dictType = "alarm_type") + @Schema(description = "报警类型: 1-移位, 2-明烟明火报警,3-人脸识别,4-脸部抓拍,5-安全帽检测") + private Integer alarmType; + + @ExcelProperty(value = "基准图路径 ") + @Schema(description = "基准图路径 ") + private String baseImage; + + @ExcelProperty(value = "抓拍图路径") + @Schema(description = "抓拍图路径") + private String captureImage; + + @ExcelProperty(value = "状态: 0-未处理, 1-已忽略, 2-已修复") + @DictFormat(dictType = "alarm_status") + @Schema(description = "状态: 0-未处理, 1-已忽略, 2-已修复") + private Integer status; + + @ExcelProperty(value = "处理时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "处理时间") + private LocalDateTime handleTime; + + @ExcelProperty(value = "处理人") + @Schema(description = "处理人") + private String handleBy; + + @ExcelProperty(value = "处理备注") + @Schema(description = "处理备注") + private String handleRemark; + + @ExcelProperty(value = "") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/camerasnapshot/CameraSnapshotVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/camerasnapshot/CameraSnapshotVO.java new file mode 100644 index 0000000..833ebd9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/camerasnapshot/CameraSnapshotVO.java @@ -0,0 +1,43 @@ +package com.sz.admin.monitor.pojo.vo.camerasnapshot; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.time.LocalDateTime; + +/** + * ClassName: CameraSnapshotVO + * Package: com.sz.admin.monitor.pojo.vo.camerasnapshot + * Description: + */ +@Data +@Schema(description = "cameraSnapshot返回vo") +public class CameraSnapshotVO { + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "通道id") + private Integer channelId; + + @Schema(description = "摄像头ID") + private Long cameraId; + + @Schema(description = "预置点索引") + private Integer presetIndex; + + @Schema(description = "图片保存路径") + private String imagePath; + + @Schema(description = "1-定时巡检, 2-守望归位检测, 3-手动抓拍") + private Integer checkType; + + @Schema(description = "0-正常, 1-移位") + private Integer isAbnormal; + + @Schema(description = "抓拍时间") + private LocalDateTime createTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/AlarmReportVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/AlarmReportVO.java new file mode 100644 index 0000000..ff16625 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/AlarmReportVO.java @@ -0,0 +1,74 @@ +package com.sz.admin.monitor.pojo.vo.edgebox; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.sz.admin.monitor.pojo.dto.edgebox.AlarmReportDTO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import java.util.List; + +/** + * ClassName: AlarmReportVO + * Package: com.sz.admin.monitor.pojo.vo.edgebox + * Description: + */ +@Data +@Schema(description = "alarmReport返回vo") +public class AlarmReportVO { + @Schema(description = "违规描述") + private String summary; + @Schema(description = "任务描述") + private String taskDesc; + @Schema(description = "任务会话") + private String taskSession; + @Schema(description = "报警盒子IP") + private String boardIp; + @Schema(description = "告警类别") + private String alarmType; + @Schema(description = "视频Rtsp地址") + private String rtspUrl; + @Schema(description = "基准图路径 ") + private String baseImage; + @Schema(description = "抓拍图路径") + private String captureImage; + @Schema(description = "报警结果") + private SimpleResult result; + @Data + public static class SimpleResult { + + /** + * 告警中文描述 + */ + @JsonProperty("Description") + private String description; + + /** + * 详细属性列表 (如: 置信度、人脸小图等) + */ + @JsonProperty("Properties") + private List properties; + } + + @Data + public static class SimpleProperty { + /** + * 属性名 (如: FrontFaceScore) + */ + @JsonProperty("property") + private String property; + + /** + * 属性中文名 (如: 人脸置信度) + */ + @JsonProperty("desc") + private String desc; + + /** + * 属性值 (可能是数字、字符串或 Base64) + */ + @JsonProperty("value") + @ToString.Exclude + private Object value; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/AlgorithmTaskVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/AlgorithmTaskVO.java new file mode 100644 index 0000000..00f612e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/AlgorithmTaskVO.java @@ -0,0 +1,69 @@ +package com.sz.admin.monitor.pojo.vo.edgebox; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * ClassName: AlgorithmTaskVO + * Package: com.sz.admin.monitor.pojo.vo.edgebox + * Description: + */ +@Data +@Schema(description = "algorithmTask返回vo") +public class AlgorithmTaskVO { + + /** + * 主键 + */ + private Long id; + + /** + * 摄像机ID + */ + private Long cameraId; + + /** + * 访问第三方服务器的url + */ + private String url; + + /** + * 任务编号 + */ + private String algTaskSession; + + /** + * 摄像头名称 + */ + private String mediaName; + + /** + * 任务描述 + */ + private String taskDesc; + + /** + * 算法列表 + */ + private List algInfo; + + /** + * 算法参数 (JSON 格式) + * mybatis-flex 会自动处理 JsonNode 与 JSON 字符串之间的转换(如果配置了 Jackson) + */ + private JsonNode userData; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/EdgeBoxVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/EdgeBoxVO.java new file mode 100644 index 0000000..b54d93d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/edgebox/EdgeBoxVO.java @@ -0,0 +1,66 @@ +package com.sz.admin.monitor.pojo.vo.edgebox; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * EdgeBox返回vo + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Data +@Schema(description = "EdgeBox返回vo") +public class EdgeBoxVO { + + @ExcelIgnore + @Schema(description = "主键") + private Long id; + + @ExcelProperty(value = "盒子的名称") + @Schema(description = "盒子的名称") + private String name; + + @ExcelProperty(value = "盒子的IP地址") + @Schema(description = "盒子的IP地址") + private String ip; + @ExcelProperty(value = "盒子的端口") + @Schema(description = "盒子的端口") + private String port; + + @ExcelProperty(value = "子网掩码") + @Schema(description = "子网掩码") + private String mask; + + @ExcelProperty(value = "网关地址") + @Schema(description = "网关地址") + private String gateway; + + @ExcelProperty(value = "盒子的账号") + @Schema(description = "盒子的账号") + private String account; + + @ExcelProperty(value = "密码") + @Schema(description = "密码") + private String password; + + @ExcelProperty(value = "创建时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @ExcelProperty(value = "更新时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/faceimage/FaceImageVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/faceimage/FaceImageVO.java new file mode 100644 index 0000000..c3452ca --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/faceimage/FaceImageVO.java @@ -0,0 +1,22 @@ +package com.sz.admin.monitor.pojo.vo.faceimage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ClassName: FaceImageVO + * Package: com.sz.admin.monitor.pojo.vo.faceimage + * Description: + */ +@Data +@Schema(description = "FaceImage返回vo") +public class FaceImageVO { + @Schema(description = "主键ID") + private Long id; + @Schema(description = "人脸信息表id") + private Long faceInfoId; + @Schema(description = "图片路径") + private String imageUrl; + @Schema(description = "上传时间") + private String uploadTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/faceinfo/FaceInfoVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/faceinfo/FaceInfoVO.java new file mode 100644 index 0000000..ef151cd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/faceinfo/FaceInfoVO.java @@ -0,0 +1,53 @@ +package com.sz.admin.monitor.pojo.vo.faceinfo; + +import com.sz.admin.monitor.pojo.vo.faceimage.FaceImageVO; +import com.sz.admin.monitor.pojo.vo.facelibrary.FaceLibraryVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import java.util.List; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * FaceInfo返回vo + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceInfo返回vo") +public class FaceInfoVO { + + @ExcelIgnore + @Schema(description = "") + private Long id; + + @ExcelProperty(value = "用户标识") + @Schema(description = "用户标识") + private String faceSign; + + @ExcelProperty(value = "姓名") + @Schema(description = "姓名") + private String name; + + @Schema(description = "人脸库id") + private Long libraryId; + @ExcelProperty(value = "人脸库") + @Schema(description = "人脸库") + private FaceLibraryVO faceLibraryVO; + + @Schema(description = "人脸图片列表") + private List faceImageList; + + @ExcelProperty(value = "注册时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "注册时间") + private LocalDateTime registerTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/facelibrary/FaceLibraryVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/facelibrary/FaceLibraryVO.java new file mode 100644 index 0000000..58b337d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/facelibrary/FaceLibraryVO.java @@ -0,0 +1,33 @@ +package com.sz.admin.monitor.pojo.vo.facelibrary; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +/** + *

+ * FaceInfo返回vo + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Data +@Schema(description = "FaceLibrary返回vo") +public class FaceLibraryVO { + + @Schema(description = "id") + private Long id; + + @Schema(description = "人脸库名称") + private String name; + + @Schema(description = "库ID") + private Integer albumId; + @Schema(description = "边缘盒子的id") + private Long boxId; +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/nvr/NvrVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/nvr/NvrVO.java new file mode 100644 index 0000000..068b92e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/nvr/NvrVO.java @@ -0,0 +1,57 @@ +package com.sz.admin.monitor.pojo.vo.nvr; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.sz.admin.monitor.pojo.dto.camera.CameraDTO; +import com.sz.admin.monitor.pojo.po.Nvr; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * ClassName: NvrVO + * Package: com.sz.admin.monitor.pojo.vo + * Description: + */ +@Data +@Schema(description = "Nvr返回vo") +public class NvrVO { + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "NVR设备名称") + private String name; + + @Schema(description = "所属变电站Id") + private Long stationId; + + @Schema(description = "IP地址") + private String ip; + + @Schema(description = "端口号") + private Integer port; + + @Schema(description = "登录用户名") + private String account; + + @Schema(description = "密码") + private String password; + + + @Schema(description = "nvr的类型,1-大华, 0-海康威视") + private Integer driver; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + + // 用于表格按钮刷新加载 + private Boolean isLoading=false; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/offset/OffsetVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/offset/OffsetVO.java new file mode 100644 index 0000000..de9b1a1 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/offset/OffsetVO.java @@ -0,0 +1,26 @@ +package com.sz.admin.monitor.pojo.vo.offset; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * ClassName: ShiftVO + * Package: com.sz.admin.monitor.pojo.vo.shift + * Description: + */ +@Data +@Schema(description = "offset返回vo") +@AllArgsConstructor +@NoArgsConstructor +public class OffsetVO { + @Schema(description = "x坐标") + private String x; + @Schema(description = "y坐标") + private String y; + @Schema(description = "单位") + private String unit; // 添加单位字段 + @Schema(description = "描述") + private String description; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/preset/PresetVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/preset/PresetVO.java new file mode 100644 index 0000000..ebea42e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/preset/PresetVO.java @@ -0,0 +1,28 @@ +package com.sz.admin.monitor.pojo.vo.preset; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ClassName: PresetVO + * Package: com.sz.admin.monitor.pojo.vo.preset + * Description: + */ +@Data +@Schema(description = "Preset返回vo") +public class PresetVO { + @Schema(description = "预置位id") + private Long id; + @Schema(description = "摄像机id") + private Long cameraId; + @Schema(description = "预置位") + private Integer presetIndex; + @Schema(description = "预置位名称") + private String presetName; + @Schema(description = "是否被设置") + private Boolean isSet; + @Schema(description = "0-不是基准点,1-为基准点") + private Integer isBasicPoint; + @Schema(description = "上报的url") + private String presetUrl; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/ptz/PTZVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/ptz/PTZVO.java new file mode 100644 index 0000000..648b82c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/ptz/PTZVO.java @@ -0,0 +1,16 @@ +package com.sz.admin.monitor.pojo.vo.ptz; + +import lombok.Data; + +/** + * ClassName: PTZVO + * Package: com.sz.admin.monitor.pojo.vo.ptz + * Description: + */ +@Data +public class PTZVO { + private Long cameraId; + private Integer pan; + private Integer tilt; + private Integer zoom; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/substation/SubstationVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/substation/SubstationVO.java new file mode 100644 index 0000000..a7377c0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/substation/SubstationVO.java @@ -0,0 +1,48 @@ +package com.sz.admin.monitor.pojo.vo.substation; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Substation返回vo + *

+ * + * @author Lz + * @since 2026-03-06 + */ +@Data +@Schema(description = "Substation返回vo") +public class SubstationVO { + + @ExcelIgnore + @Schema(description = "主键ID") + private Long id; + + @ExcelProperty(value = "变电站名称") + @Schema(description = "变电站名称") + private String name; + + @ExcelProperty(value = "所属区域") + @Schema(description = "所属区域") + private Long regionId; + + @ExcelProperty(value = "1- 普通变电站 2-超高压变电站") + @Schema(description = "1- 普通变电站 2-超高压变电站") + private Integer type; + + @ExcelProperty(value = "详细地址") + @Schema(description = "详细地址") + private String address; + + @ExcelProperty(value = "创建时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/CameraNodeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/CameraNodeVO.java new file mode 100644 index 0000000..725605e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/CameraNodeVO.java @@ -0,0 +1,13 @@ +package com.sz.admin.monitor.pojo.vo.tree; + +import lombok.Data; + +/** + * ClassName: CameraNodeVO + * Package: com.sz.admin.monitor.pojo.vo.tree + * Description: + */ +@Data +public class CameraNodeVO extends TreeNodeVO { + private Integer status; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/NvrNodeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/NvrNodeVO.java new file mode 100644 index 0000000..2f02c2a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/NvrNodeVO.java @@ -0,0 +1,39 @@ +package com.sz.admin.monitor.pojo.vo.tree; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ClassName: NvrNodeDTO + * Package: com.sz.admin.monitor.pojo.dto.tree + * Description: + */ +@Data + +public class NvrNodeVO extends TreeNodeVO { + + @Schema(description = "IP地址") + private String ip; + + @Schema(description = "端口号") + private Integer port; + + + @Schema(description = "厂商") + private String manufacturer; + + @Schema(description = "nvr的类型,1-大华, 0-海康威视") + private Integer driver; + + @Schema(description = "在线状态:1-在线, 0-离线") + private Integer status; + + + public NvrNodeVO(Long id, String name, String ip, Integer port, Integer driver, Integer status) { + super(id, name, 2); + this.ip = ip; + this.port = port; + this.driver = driver; + this.status = status; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/TreeNodeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/TreeNodeVO.java new file mode 100644 index 0000000..86acc22 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/tree/TreeNodeVO.java @@ -0,0 +1,27 @@ +package com.sz.admin.monitor.pojo.vo.tree; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * ClassName: TreeNode + * Package: com.sz.admin.monitor.pojo.dto.tree + * Description: 通用树节点 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TreeNodeVO { + private Long id; + private String name; + private Integer type; // 0: Region, 1: Substation, 2: NVR,3: Camera + private List children; + public TreeNodeVO(Long id, String name, Integer type) { + this.id = id; + this.name = name; + this.type = type; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/watchful/WatchfulVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/watchful/WatchfulVO.java new file mode 100644 index 0000000..c2c0e0d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/pojo/vo/watchful/WatchfulVO.java @@ -0,0 +1,23 @@ +package com.sz.admin.monitor.pojo.vo.watchful; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * ClassName: WatchfulVO + * Package: com.sz.admin.monitor.pojo.vo.watchful + * Description: + */ +@Data +@Schema(description = "守望参数返回vo") +public class WatchfulVO { + @Schema(description = "id") + private Integer id; + @Schema(description = "0-不启用,1-启用 ") + private Integer watchfulState; + @Schema(description = "守望归位时间(单位秒)") + private Integer watchfulTime; + @Schema(description = "守望归位的预置位") + private Integer watchfulIndex; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/AbstractNVR.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/AbstractNVR.java new file mode 100644 index 0000000..147f6ca --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/AbstractNVR.java @@ -0,0 +1,42 @@ +package com.sz.admin.monitor.sdk; + +/** + * ClassName: AbstractNVR + * Package: com.sz.admin.monitor.hik + * Description: 抽象类 + */ +public abstract class AbstractNVR { + private String ipAddress; + private String port; + private String userName; + private String password; + private int lUserID; + /** + * 注册SDK + * @return 返回对象 + */ + public abstract Object registerPlugin(); + /** + * 登陆vcr + * @return 返回句柄 + */ + public abstract int loginVcr(String ipAddress,String port,String userName,String password); + /** + * 云台控制 + * @return true成功 false失败 + */ + public abstract boolean ptzControl(int luerId,int iChannel,String ptzCommand,String dwStop,int dwSpeed); + /** + * 预制点设置调用删除 + * @return true成功 false失败 + */ + public abstract boolean ptzPreset(int luerId,int iChannel,int ptzPresetCmd,String dwPresetIndex); + + public abstract boolean ptzPreset(int luerId, int iChannel, int ptzPresetCmd, String dwPresetIndex, String pointName); + + /** + * 设备抓图 + * @return true成功 false失败 + */ + public abstract String capturePic(int luerId,int iChannel,String fileName); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/ManageNVR.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/ManageNVR.java new file mode 100644 index 0000000..fa4f655 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/ManageNVR.java @@ -0,0 +1,752 @@ +package com.sz.admin.monitor.sdk; + + +import com.mybatisflex.core.query.QueryWrapper; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.RecordFile; +import com.sz.admin.monitor.pojo.vo.ptz.PTZVO; +import com.sz.admin.monitor.pojo.vo.watchful.WatchfulVO; +import com.sz.admin.monitor.sdk.hkSdk.HCNetSDK; +import com.sz.admin.monitor.sdk.hkSdk.HkNVR; +import com.sz.admin.monitor.service.CameraService; +import com.sz.admin.monitor.service.DeviceService; +import com.sz.admin.monitor.service.IpChannelService; +import com.sz.admin.monitor.service.NvrService; +import com.sz.admin.monitor.utils.ThreeDPtz; +import com.sz.admin.monitor.utils.VcrlUserIdContainer; +import com.sz.core.util.BeanCopyUtils; +import com.sz.mysql.DataScopeProperties; +import jakarta.annotation.Resource; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.modelmapper.ModelMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 所有NVR类型的管理类 + * + * @author zxsong + * @since 2024-1-4 10:29:15 + */ +@Component +@Slf4j +public class ManageNVR { + public static final String INVOKE_POINT_CMD = "39"; + @Resource + private HkNVR hkNVR; + @Resource + private NvrService nvrService; + @Resource + private CameraService cameraService; + + @Resource + private VcrlUserIdContainer vcrlUserIdContainer; + @Resource + private DataScopeProperties dataScopeProperties; + + /** + * 项目启动注册所有sdk和登录所有nvr + */ + @Bean + public Object nvrInit() { + //海康sdk注册 + HCNetSDK hcNetSDK = hkNVR.registerPlugin(); + Nvr nvr = new Nvr(); + nvr.setDriver(0); + // 从数据库中查询出所有的nvr + List devicesList = nvrService.list(QueryWrapper.create(nvr)); + if (null == devicesList) { + return hcNetSDK; + } + // 遍历每个nvr,进行一个注册 + for (Nvr n : devicesList) { + int lUserId = hkNVR.loginVcr(n.getIp(), n.getPort().toString(), n.getAccount(), n.getPassword()); + if (lUserId == -1) { + // 如果注册失败,将状态设置为离线 + nvrService.upStatusById(n.getId(), 0); + } else { + //将vcr的唯一Id和登录回调句柄luserid存储 + log.info("NVR登录成功,ID:{}", lUserId); + vcrlUserIdContainer.addData(n.getId().intValue(), lUserId); + nvrService.upStatusById(n.getId(), 1); + } + } + return hcNetSDK; + } + +// @Bean +// public Object dhNvrInit() { +// //大华sdk注册 +// NetSDKLib netSDKLib = dhNVR.registerPlugin(null, null); +// +// IpDevice ipDevices = new IpDevice(); +// ipDevices.setDriver(1); +// List devicesListHk = ipDevicesService.list(QueryWrapper.create(ipDevices)); +// if (null == devicesListHk) { +// return netSDKLib; +// } +// for (IpDevice devices : devicesListHk) { +// NetSDKLib.LLong lLong = dhNVR.loginVcr2(devices.getIpAddress(), String.valueOf(devices.getAdminPort()), devices.getUsername(), devices.getPassword()); +// if (lLong.toString().equals("0")) { +// ipDevicesService.upStatusById(devices.getId(), 0); +// } else { +// //将vcr的唯一Id和登录回调句柄luserid存储 +// vcrlUserIdContainer.addData(devices.getId(), lLong); +// ipDevicesService.upStatusById(devices.getId(), 1); +// } +// } +// return netSDKLib; +// } + + + /** + * 新增nvr时登录 + * + * @param ip + * @param port + * @param userName + * @param password + * @param deviceType + * @return + */ + public Object loginOne(Long id, String ip, String port, String userName, String password, String deviceType) { + Object loginVcr = 0; + if ("0".equals(deviceType)) { + // 海康登录 + loginVcr = hkNVR.loginVcr(ip, port, userName, password); + } else if ("1".equals(deviceType)) { + // 大华登录 + // loginVcr = dhNVR.loginVcr2(ip, port, userName, password); + } else { + return 0; + } + Nvr devices = nvrService.getOne(QueryWrapper + .create() + .select() + .from(Nvr.class) + .eq(Nvr::getId, id)); + vcrlUserIdContainer.addData(devices.getId().intValue(), loginVcr); + return loginVcr; + } + + /** + * 登陆单个camera + * + * @param ip + * @param port + * @param userName + * @param password + * @param deviceType + * @return + */ + public int loginOneCamera(String ip, String port, String userName, String password, String deviceType) { + int loginVcr = 0; + if ("0".equals(deviceType)) { + loginVcr = hkNVR.loginVcr(ip, port, userName, password); + } else if ("1".equals(deviceType)) { + // loginVcr = dhNVR.loginVcr(ip, port, userName, password); + } else { + return 0; + } + return loginVcr; + } + + /** + * 云台控制 + * + * @param channelId 通道id + * @param dwCmd 云台控制命令 + * @param speed 速度 + * @param dwStop 停止命令 + */ + public boolean ptzCon(int channelId, String dwCmd, String speed, String dwStop) { + // 根据通道id获取摄像机 + Camera camera = cameraService.getById(channelId); + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Nvr nvr = nvrService.getById(camera.getNvrId()); + // + if (0 == nvr.getDriver()) { + return hkNVR.ptzControl(userId, camera.getChannelId(), dwCmd, dwStop, Integer.parseInt(speed)); + } else { + return false; + } + + } + + + /** + * 预置位的设置调用 + *设置预置位 = “记录”当前位置,给它一个号码。 + * 调用预置位 = “跳转”到那个号码对应的位置 + * @param + * @param ptzPresetCmd + * @param dwPresetIndex + * @return + */ + public boolean ptzPresets(int channelId, int ptzPresetCmd, String dwPresetIndex,String pointName) { + Camera camera = cameraService.getById(channelId); + if (camera == null) { + return false; + } + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Nvr nvr = nvrService.getById(camera.getNvrId()); + if (userId == null) { + log.error("录像机不在线:{}-{}", nvr.getIp(), nvr.getName()); + return false; + } + if (0 == nvr.getDriver()) { + boolean b = hkNVR.ptzPreset(userId, camera.getChannelId(), ptzPresetCmd, dwPresetIndex, pointName); + if (!b) { + int channelUserId = hkNVR.login_V40(camera.getIpAddress(), nvr.getPort().shortValue(), nvr.getAccount(), nvr.getPassword()); + boolean preset = hkNVR.ptzPreset(channelUserId, 1, ptzPresetCmd, dwPresetIndex, pointName); + hkNVR.loginOut(channelUserId, camera.getIpAddress()); + return preset; + } else { + return true; + } + } else { + return false; + } + } + + /** + * 获取海康大华通道信息 + * + * @param lUserID 登录的句柄 + * @param ipDeviceId 设备的id + * @param deviceType 设备的类型 0表示海康,1表示大华 + * @return 通道列表 + * @throws UnsupportedEncodingException + */ + public List getChannel(Object lUserID, long ipDeviceId, int deviceType) throws UnsupportedEncodingException { + List cameraList = new ArrayList<>(); + ModelMapper modelMapper = new ModelMapper(); + if (deviceType == 0) { + List ipChannelInfo = hkNVR.getIPChannelInfo(Integer.parseInt(lUserID.toString()), ipDeviceId); + for (Camera objectIpChannel : ipChannelInfo) { + Camera camera = modelMapper.map(objectIpChannel, Camera.class); + cameraList.add(camera); + } + } else { + // 获取大华通道信息 +// List ipChannelInfo = dhNVR.getIPChannelInfo(lUserID, ipDeviceId); +// for (Camera objectIpChannel : ipChannelInfo) { +// Camera ipChannel = modelMapper.map(objectIpChannel, Camera.class); +// cameraList.add(ipChannel); +// } + } + return cameraList; + } + + /** + * 抓图 + * + * @param cameraId + * @return + */ + public synchronized String capturePic(int cameraId, String fileName) { +// try { +// Thread.sleep(500); +// } catch (InterruptedException e) { +// throw new RuntimeException(e); +// } +// return "!23"; + Camera camera = cameraService.getById(cameraId); + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Nvr nvr = nvrService.getById(camera.getNvrId()); + if(camera.getChannelDriver() == 0){ + int loginOne = this.loginOneCamera(camera.getIpAddress(), String.valueOf(nvr.getPort()), + nvr.getAccount(), nvr.getPassword(), String.valueOf(0)); + String path; + if (loginOne == -1){ + // 登录失败 + path = hkNVR.capturePic(userId, camera.getChannelId(), fileName); + }else { + path = hkNVR.capturePic(loginOne, camera.getVideoType(), fileName); + if (path.contains("抓图失败")) { + log.error("抓图失败:{}", camera.getIpAddress()); + path = hkNVR.capturePic(userId, camera.getChannelId(),fileName); + } + hkNVR.loginOut(loginOne, camera.getIpAddress()); + } + return path; + }else { + return hkNVR.capturePic(userId, camera.getChannelId(),fileName); + } + } + + + /** + * 判断两个ip是否在同一网段 + * + * @param ip1 + * @param ip2 + * @return + */ + public boolean isSameNetworkSimple(String ip1, String ip2) { + String[] parts1 = ip1.split("\\."); + String[] parts2 = ip2.split("\\."); + return parts1[0].equals(parts2[0]) + && parts1[1].equals(parts2[1]) + && parts1[2].equals(parts2[2]); + } + + /** + * 3Dptz功能 + *通过鼠标在NVR或IPC(网络摄像机)的实时视频画面上进行交互操作, + * 来控制摄像头的云台转动和镜头变焦,实现一种直观、精确的定位方式 + * @param channelId + * @param threeDPtz + * @return + */ + public boolean threeDPtz(int channelId, ThreeDPtz threeDPtz) { + Camera camera = cameraService.getById(channelId); + Integer lUserID = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Nvr nvr = nvrService.getById(camera.getNvrId()); + if (0 == nvr.getDriver()) { + return hkNVR.threeDPositioning(lUserID, camera.getChannelId(), threeDPtz); + } else { + return false; + } + } + + + /** + * 云台守望功能 + * 当云台摄像机(PTZ摄像机)在一段时间内没有接收到任何控制指令后,会自动回到一个预先设定好的默认位置(预置点)并保持静止。 + * @param channelId 通道id + * @param openOrNo 0表示关闭,1表示开启 + * @param watchTime 云台守望时间,单位为秒 + */ + public boolean watchful(int channelId, int openOrNo, int watchTime, int presetIndex) { + Camera camera = cameraService.getById(channelId); + Integer lUserId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Nvr nvr = nvrService.getById(camera.getNvrId()); + if (camera.getChannelDriver() != 0 ||camera.getType() == 0 || camera.getType() == 3){ + return false; + } + if(openOrNo == 1){ + if (0 == nvr.getDriver()) { + boolean ptzPresets = this.ptzPresets(channelId, 39, String.valueOf(presetIndex), ""); + if (ptzPresets){ + try { + // 延时一秒钟 + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + // 开启云台守卫功能 + boolean b = hkNVR.enableParkActionToPreset(lUserId, camera.getChannelId(), watchTime, presetIndex); + if(b){ + // 更新该摄像机的守望位为1 表示开启了守望功能 + cameraService.updateWatchfulStateByIp(camera.getIpAddress(), 1); + } + return b; + } + } + return false; + }else { + if (0 == nvr.getDriver()) { + boolean b = hkNVR.disableParkAction(lUserId, camera.getChannelId()); + if(b){ + // 更新该摄像机的守望位为0 表示关闭了守望功能 + cameraService.updateWatchfulStateByIp(camera.getIpAddress(), 0); + } + return b; + } else { + return false; + } + } + + } + + + /** + * 获取海康的云台守望的参数信息 + * + * @param channelId 通道id + * @return 云台守望数据 + */ + public WatchfulVO getWatchful(Long channelId) { + Camera camera = cameraService.getById(channelId); + log.info("摄像头参数信息:{}", camera); + int userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG watchCfg = HkNVR.getWatchCfg(HCNetSDK.INSTANCE, userId, camera.getChannelId()); + log.info("守望参数:{}", watchCfg); + WatchfulVO watchfulVO = new WatchfulVO(); + if (watchCfg != null) { + watchfulVO.setWatchfulState((int) watchCfg.byEnable); + watchfulVO.setWatchfulIndex((int) watchCfg.wID); + watchfulVO.setWatchfulTime(watchCfg.dwParkTime); + return watchfulVO; + } + return watchfulVO; + } + + /** + * 获取图片分辨率 + * + * @param imagePath + * @return + */ + public int[] getImageResolution(String imagePath) { + try { + BufferedImage image = ImageIO.read(new File(imagePath)); + if (image == null) { + throw new RuntimeException("读取图片分辨率失败,测温抓图失败"); + } + int width = image.getWidth(); + int height = image.getHeight(); + return new int[]{width, height}; + } catch (IOException e) { + throw new RuntimeException("读取图片分辨率失败: " + imagePath, e); + } + } + + /** + * 获取红外探测器分辨率 + * + * @param dataPath + * @return + */ + public int[] guessResolution(String dataPath) { + File file = new File(dataPath); + if (!file.exists()) { + return null; + } + long fileSize = file.length(); + if (fileSize % 4 != 0) { + return null; + } + long points = fileSize / 4; + if (points == 80L * 60) return new int[]{80, 60}; + if (points == 120L * 90) return new int[]{120, 90}; + if (points == 160L * 120) return new int[]{160, 120}; + if (points == 256L * 192) return new int[]{256, 192}; + if (points == 320L * 240) return new int[]{320, 240}; + if (points == 384L * 288) return new int[]{384, 288}; + if (points == 512L * 384) return new int[]{512, 384}; + if (points == 512L * 480) return new int[]{512, 480}; + if (points == 640L * 480) return new int[]{640, 480}; + if (points == 640L * 512) return new int[]{640, 512}; + if (points == 1024L * 768) return new int[]{1024, 768}; + return null; + } + + /** + * 根据红外二进制原始图片 获取全屏温度 + * + * @param srcPath + * @param width + * @return + */ + public static String handleImageData(String srcPath, int width) { + int k = srcPath.indexOf("."); + if (k == -1) { + return null; + } + // 目标文件 + String desPath = srcPath.substring(0, k) + ".json"; + + File file = new File(srcPath); + if (!file.exists()) { + return null; + } + // 65, 13, -88, 65, 44, -117, -87, 65, 13, 30, -87, 65, 35, -96, -89, 65, -87, -21, -91, 65, 77, -92, -92 + try (FileInputStream fis = new FileInputStream(file)) { + byte[] buffer = new byte[4]; + ArrayList list = new ArrayList<>(); + int bytesRead; + while ((bytesRead = fis.read(buffer)) != -1) { + // 处理读取的字节数据 + int l; + l = buffer[0]; + l &= 0xff; + l |= ((long) buffer[1] << 8); + l &= 0xffff; + l |= ((long) buffer[2] << 16); + l &= 0xffffff; + l |= ((long) buffer[3] << 24); + String tempData = Float.intBitsToFloat(l) + ""; + String number = String.format("%.2f", Double.parseDouble(tempData)); + list.add(number); + } + BufferedWriter bw = new BufferedWriter(new FileWriter(desPath)); + for (int i = 0; i < list.size(); i++) { + String s = list.get(i); + bw.write(s); + bw.write(","); + int j = i + 1; + if (j % width == 0) { + bw.newLine(); + } + } + bw.close(); + return desPath; + + } catch (IOException e) { + e.printStackTrace(); + + } + return null; + } +//@Data +// public static class MaxValueWithCoordinates { +// public double maxValue; +// public int maxX; +// public int maxY; +// public String filePath; +// public MaxValueWithCoordinates(double maxValue, int maxX, int maxY,String filePath) { +// this.maxValue = maxValue; +// this.maxX = maxX; +// this.maxY = maxY; +// this.filePath = filePath; +// } +// +// @Override +// public String toString() { +// return "MaxValue: " + maxValue + " at (" + maxX + ", " + maxY + ")"; +// } +// } + + @Data + public static class MaxMinValueWithCoordinates { + public double maxValue; + public int maxX; + public int maxY; + + public double minValue; + public int minX; + public int minY; + + public String filePath; + + public MaxMinValueWithCoordinates(double maxValue, int maxX, int maxY, + double minValue, int minX, int minY, + String filePath) { + this.maxValue = maxValue; + this.maxX = maxX; + this.maxY = maxY; + this.minValue = minValue; + this.minX = minX; + this.minY = minY; + this.filePath = filePath; + } + + @Override + public String toString() { + return "MaxValue: " + maxValue + " at (" + maxX + ", " + maxY + "), " + + "MinValue: " + minValue + " at (" + minX + ", " + minY + ")"; + } + } + + + /** + * 获取框最大温度或则点 + * + * @param path + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @return + */ +// public static MaxValueWithCoordinates getJsonHeightTemp(String path, int x1, int y1, int x2, int y2) { +// File file = new File(path); +// try { +// FileReader fileReader = new FileReader(file); +// BufferedReader reader = new BufferedReader(fileReader); +// String line; +// ArrayList list = new ArrayList<>(); +// while ((line = reader.readLine()) != null) { +// String[] split = line.split(","); +// list.add(split); +// } +// reader.close(); +// fileReader.close(); +// +// double max = Double.NEGATIVE_INFINITY; +// int maxX = -1; +// int maxY = -1; +// +// for (int i = y1; i <= y2 && i < list.size(); i++) { +// for (int j = x1; j <= x2 && j < list.get(i).length; j++) { +// String[] strings = list.get(i); +// String s = strings[j]; +// double value = Double.parseDouble(s); +// +// if (value > max) { +// max = value; +// maxX = j; +// maxY = i; +// } +// } +// } +// +// return new MaxValueWithCoordinates(max, maxX, maxY,null); +// } catch (Exception e) { +// e.printStackTrace(); // 打印异常堆栈信息 +// } +// return new MaxValueWithCoordinates(-1.0, -1, -1,null); +// } + public static MaxMinValueWithCoordinates getJsonHeightTemp(String path, int x1, int y1, int x2, int y2) { + File file = new File(path); + + try (FileReader fileReader = new FileReader(file); + BufferedReader reader = new BufferedReader(fileReader)) { + + String line; + ArrayList list = new ArrayList<>(); + while ((line = reader.readLine()) != null) { + list.add(line.split(",")); + } + + double max = Double.NEGATIVE_INFINITY; + int maxX = -1, maxY = -1; + + double min = Double.POSITIVE_INFINITY; + int minX = -1, minY = -1; + + for (int i = y1; i <= y2 && i < list.size(); i++) { + String[] row = list.get(i); + for (int j = x1; j <= x2 && j < row.length; j++) { + String s = row[j]; + if (s == null || s.isEmpty()) continue; // 防御:空值跳过 + + double value; + try { + value = Double.parseDouble(s); + } catch (NumberFormatException ex) { + continue; // 防御:脏数据跳过 + } + + if (value > max) { + max = value; + maxX = j; + maxY = i; + } + + if (value < min) { + min = value; + minX = j; + minY = i; + } + } + } + + return new MaxMinValueWithCoordinates(max, maxX, maxY, min, minX, minY, path); + + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + /** + * 检测录像机在线状态 + * + * @param deviceId + * @return + */ + public int getDeviceStatus(Integer deviceId, Integer driver) { + int deviceStatus = 0; + Nvr ipDevice = nvrService.getById(deviceId); + if (driver == 0) { + deviceStatus = hkNVR.getDeviceStatus(ipDevice); + } else if (driver == 1) { + // TODO 检查大华的设备在线状态 + // deviceStatus = dhNVR.getDeviceStatus(ipDevice); + } + return deviceStatus; + } + + /** + * 视频录像 + * @param fileName 文件名称 + * @param channelId 通道ID + * @param isRecord 是否录像 + * @return + */ + public String videotaped(String fileName, int channelId, boolean isRecord) { + Camera camera = cameraService.getById(channelId); + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Nvr nvr = nvrService.getById(camera.getNvrId().intValue()); + if (0 == nvr.getDriver()) { + return hkNVR.videotaped(userId, camera.getChannelId(), isRecord, fileName); + } + return ""; + } + + public List findFileByDate(int channelId, LocalDateTime startTime, LocalDateTime endTime) throws UnsupportedEncodingException { + Camera camera = cameraService.getById(channelId); + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Nvr ipDevices = nvrService.getById(camera.getNvrId().intValue()); + if (0 == ipDevices.getDriver()) { + return hkNVR.findRecordFile(userId, camera.getChannelId(), startTime, endTime); + } + return null; + } + + /** + * 获取nvr的硬盘问题 + * + * @return + */ + public Map getDevCfg(String ip, int port, String user, String psw) { + return hkNVR.getDevCfg(ip, port, user, psw); + } + + + /** + * 获取通道录像起止时间 + */ + public List getChannelCfg(int channelId, LocalDateTime startTime, LocalDateTime endTime) { + Camera camera = cameraService.getById(channelId); + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + return hkNVR.getChannelyRecordTime(userId, camera.getChannelId(), startTime, endTime); + } + + /** + * 检查通道是否支持3Dptz + * @param channelId + * @return + */ + public boolean checkCameraThreePTZ(Integer channelId){ + Camera camera = cameraService.getById(channelId); + if (camera.getChannelDriver() != 0 || camera.getType() == 0 || camera.getType() == 3){ + return false; + } + Nvr ipDevices = nvrService.getById(camera.getNvrId().intValue()); + int userId = hkNVR.loginVcr(camera.getIpAddress(), String.valueOf(8000), ipDevices.getAccount(), ipDevices.getPassword()); + boolean checkCameraThree = hkNVR.checkCameraThree(userId); + hkNVR.loginOut(userId,camera.getIpAddress()); + return checkCameraThree; + } + // 返回最后操作的错误码 + public int getLastError() + { + return hkNVR.getLastError(); + } + + // 定义获取 PTZ 坐标的专用函数 + public PTZVO getPTZLocation(Long id) { + Camera camera = cameraService.getById(id); + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(camera.getNvrId().intValue()); + Map map = hkNVR.NET_DVR_GetPTZPos(userId, camera.getChannelId()); + return BeanCopyUtils.copy(map, PTZVO.class); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HCNetSDK.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HCNetSDK.java new file mode 100644 index 0000000..e5e665d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HCNetSDK.java @@ -0,0 +1,10892 @@ +package com.sz.admin.monitor.sdk.hkSdk; + + +import com.sun.jna.*; +import com.sun.jna.examples.win32.W32API; +import com.sun.jna.examples.win32.W32API.HWND; +import com.sun.jna.ptr.ByteByReference; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.ShortByReference; +import com.sz.admin.monitor.common.CommonKit; + +import java.util.Arrays; +import java.util.List; + +//SDK接口说明,HCNetSDK.dll +public interface HCNetSDK extends Library { + + HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary(CommonKit.getLibPath(),HCNetSDK.class); + /*** 宏定义 ***/ + //常量 + + public static final int MAX_NAMELEN = 16; //DVR本地登陆名 + public static final int MAX_RIGHT = 32; //设备支持的权限(1-12表示本地权限,13-32表示远程权限) + public static final int NAME_LEN = 32; //用户名长度 + public static final int PASSWD_LEN = 16; //密码长度 + public static final int SERIALNO_LEN = 48; //序列号长度 + public static final int MACADDR_LEN = 6; //mac地址长度 + public static final int MAX_ETHERNET = 2; //设备可配以太网络 + public static final int PATHNAME_LEN = 128; //路径长度 + public static final int MAX_TIMESEGMENT_V30 = 8; //9000设备最大时间段数 + public static final int MAX_TIMESEGMENT = 4; //8000设备最大时间段数 + public static final int MAX_SHELTERNUM = 4; //8000设备最大遮挡区域数 + public static final int MAX_DAYS = 7; //每周天数 + public static final int PHONENUMBER_LEN = 32; //pppoe拨号号码最大长度 + public static final int MAX_DISKNUM_V30 = 33; //9000设备最大硬盘数/* 最多33个硬盘(包括16个内置SATA硬盘、1个eSATA硬盘和16个NFS盘) */ + public static final int MAX_DISKNUM = 16; //8000设备最大硬盘数 + public static final int MAX_DISKNUM_V10 = 8; //1.2版本之前版本 + public static final int MAX_WINDOW_V30 = 32; //9000设备本地显示最大播放窗口数 + public static final int MAX_WINDOW = 16; //8000设备最大硬盘数 + public static final int MAX_VGA_V30 = 4; //9000设备最大可接VGA数 + public static final int MAX_VGA = 1; //8000设备最大可接VGA数 + public static final int MAX_USERNUM_V30 = 32; //9000设备最大用户数 + public static final int MAX_USERNUM = 16; //8000设备最大用户数 + public static final int MAX_EXCEPTIONNUM_V30 = 32; //9000设备最大异常处理数 + public static final int MAX_EXCEPTIONNUM = 16; //8000设备最大异常处理数 + public static final int MAX_LINK = 6; //8000设备单通道最大视频流连接数 + public static final int MAX_DECPOOLNUM = 4; //单路解码器每个解码通道最大可循环解码数 + public static final int MAX_DECNUM = 4; //单路解码器的最大解码通道数(实际只有一个,其他三个保留) + public static final int MAX_TRANSPARENTNUM = 2; //单路解码器可配置最大透明通道数 + public static final int MAX_CYCLE_CHAN = 16; //单路解码器最大轮循通道数 + public static final int MAX_DIRNAME_LENGTH = 80; //最大目录长度 + public static final int MAX_STRINGNUM_V30 = 8; //9000设备最大OSD字符行数数 + public static final int MAX_STRINGNUM = 4; //8000设备最大OSD字符行数数 + public static final int MAX_STRINGNUM_EX = 8; //8000定制扩展 + public static final int MAX_AUXOUT_V30 = 16; //9000设备最大辅助输出数 + public static final int MAX_AUXOUT = 4; //8000设备最大辅助输出数 + public static final int MAX_HD_GROUP = 16; //9000设备最大硬盘组数 + public static final int MAX_NFS_DISK = 8; //8000设备最大NFS硬盘数 + public static final int IW_ESSID_MAX_SIZE = 32; //WIFI的SSID号长度 + public static final int IW_ENCODING_TOKEN_MAX = 32; //WIFI密锁最大字节数 + public static final int MAX_SERIAL_NUM = 64; //最多支持的透明通道路数 + public static final int MAX_DDNS_NUMS = 10; //9000设备最大可配ddns数 + public static final int MAX_DOMAIN_NAME = 64; /* 最大域名长度 */ + + public static final int MAX_EMAIL_ADDR_LEN = 48; //最大email地址长度 + public static final int MAX_EMAIL_PWD_LEN = 32; //最大email密码长度 + public static final int MAXPROGRESS = 100; //回放时的最大百分率 + public static final int MAX_SERIALNUM = 2; //8000设备支持的串口数 1-232, 2-485 + public static final int CARDNUM_LEN = 20; //卡号长度 + public static final int MAX_VIDEOOUT_V30 = 4; //9000设备的视频输出数 + public static final int MAX_VIDEOOUT = 2; //8000设备的视频输出数 + public static final int MAX_PRESET_V30 = 256; /* 9000设备支持的云台预置点数 */ + public static final int MAX_TRACK_V30 = 256; /* 9000设备支持的云台数 */ + public static final int MAX_CRUISE_V30 = 256; /* 9000设备支持的云台巡航数 */ + public static final int MAX_PRESET = 128; /* 8000设备支持的云台预置点数 */ + public static final int MAX_TRACK = 128; /* 8000设备支持的云台数 */ + public static final int MAX_CRUISE = 128; /* 8000设备支持的云台巡航数 */ + public static final int CRUISE_MAX_PRESET_NUMS = 32; /* 一条巡航最多的巡航点 */ + public static final int MAX_SERIAL_PORT = 8; //9000设备支持232串口数 + public static final int MAX_PREVIEW_MODE = 8; /* 设备支持最大预览模式数目 1画面,4画面,9画面,16画面.... */ + public static final int MAX_MATRIXOUT = 16; /* 最大模拟矩阵输出个数 */ + public static final int LOG_INFO_LEN = 11840; /* 日志附加信息 */ + public static final int DESC_LEN = 16; /* 云台描述字符串长度 */ + public static final int PTZ_PROTOCOL_NUM = 200; /* 9000最大支持的云台协议数 */ + public static final int MAX_AUDIO = 1; //8000语音对讲通道数 + public static final int MAX_AUDIO_V30 = 2; //9000语音对讲通道数 + public static final int MAX_CHANNUM = 16; //8000设备最大通道数 + public static final int MAX_ALARMIN = 16; //8000设备最大报警输入数 + public static final int MAX_ALARMOUT = 4; //8000设备最大报警输出数 + //9000 IPC接入 + public static final int MAX_ANALOG_CHANNUM = 32; //最大32个模拟通道 + public static final int MAX_ANALOG_ALARMOUT = 32; //最大32路模拟报警输出 + public static final int MAX_ANALOG_ALARMIN = 32; //最大32路模拟报警输入 + public static final int MAX_IP_ALARMIN_V40 = 4096; //允许加入的最多报警输入数 + public static final int MAX_IP_ALARMOUT_V40 = 4096; //允许加入的最多报警输出数 + public static final int MAX_ALARMOUT_V40 = (MAX_IP_ALARMOUT_V40 + MAX_ANALOG_ALARMOUT); //4128 + public static final int MAX_ALARMIN_V40 = (MAX_IP_ALARMIN_V40 + MAX_ANALOG_ALARMOUT); //4128 + public static final int MAX_CHANNUM_V40 = 512; + public static final int MAX_IP_DEVICE = 32; //允许接入的最大IP设备数 + public static final int MAX_IP_CHANNEL = 32; //允许加入的最多IP通道数 + public static final int MAX_IP_ALARMIN = 128; //允许加入的最多报警输入数 + public static final int MAX_IP_ALARMOUT = 64; //允许加入的最多报警输出数 + + /* 最大支持的通道数 最大模拟加上最大IP支持 */ + public static final int MAX_CHANNUM_V30 = (MAX_ANALOG_CHANNUM + MAX_IP_CHANNEL);//64 + public static final int MAX_ALARMOUT_V30 = (MAX_ANALOG_ALARMOUT + MAX_IP_ALARMOUT);//96 + public static final int MAX_ALARMIN_V30 = (MAX_ANALOG_ALARMIN + MAX_IP_ALARMIN);//160 + public static final int MAX_IP_DEVICE_V40 = 64; + public static final int STREAM_ID_LEN = 32; + + public static final int MAX_LICENSE_LEN = 16; + public static final int MAX_LICENSE_LEN_EX = 32; //车牌号最大长度 + public static final int MAX_CARDNO_LEN = 48; //卡号最大长度 + public static final int VCA_MAX_POLYGON_POINT_NUM = 10; + + public static final int MAX_ID_NUM_LEN = 32; //最大身份证号长度 + public static final int MAX_ID_NAME_LEN = 128; //最大姓名长度 + public static final int MAX_ID_ADDR_LEN = 280; //最大住址长度 + public static final int MAX_ID_ISSUING_AUTHORITY_LEN = 128; //最大签发机关长度 + public static final int MAX_CARD_READER_NUM_512 = 512; //最大读卡器数 + public static final int ERROR_MSG_LEN = 32; //下发错误信息 + public static final int MAX_FACE_NUM = 2; //最大人脸数 + public static final int MAX_FINGER_PRINT_LEN = 768; //最大指纹长度 + + public static final int DEV_TYPE_NAME_LEN = 24; //设备类型名称长度 + public static final int MAX_FACE_PIC_NUM = 30; /*人脸子图个数*/ + public static final int CARDNUM_LEN_V30 = 40; + + public static final int MAX_NOTICE_NUMBER_LEN = 32; //公告编号最大长度 + public static final int MAX_NOTICE_THEME_LEN = 64; //公告主题最大长度 + public static final int MAX_NOTICE_DETAIL_LEN = 1024; //公告详情最大长度 + public static final int MAX_NOTICE_PIC_NUM = 6; //公告信息最大图片数量 + public static final int MAX_DEV_NUMBER_LEN = 32; //设备编号最大长度 + public static final int LOCK_NAME_LEN = 32; //锁名称 + + public static final int NET_SDK_EMPLOYEE_NO_LEN = 32; //工号长度 + public static final int NET_SDK_UUID_LEN = 36; //UUID长度 + + public static final int MAX_INQUEST_CDRW_NUM = 4; //最大刻录机数目 + public static final int INQUEST_MESSAGE_LEN = 44; //审讯重点标记信息长度 + public static final int INQUEST_MAX_ROOM_NUM = 2; //最大审讯室个数 + public static final int MAX_RESUME_SEGMENT = 2; //支持同时恢复的片段数目 + + public static final int SUPPORT_PD_NUM = 16; + public static final int SUPPORT_ARRAY_NUM = 8; + public static final int SUPPORT_VD_NUM = 128; + public static final int SUPPORT_PD_NUM_ = 16; + public static final int SUPPORT_PD_NUM_PARTTWO = 8; + + public static final int CARDNUM_LEN_OUT = 32; //外部结构体卡号长度 + public static final int GUID_LEN = 16; //GUID长度 + + public static final int MAX_ROIDETECT_NUM = 8; //支持的ROI区域数 + public static final int MAX_LANERECT_NUM = 5; //最大车牌识别区域数 + public static final int MAX_FORTIFY_NUM = 10; //最大布防个数 + public static final int MAX_INTERVAL_NUM = 4; //最大时间间隔个数 + public static final int MAX_CHJC_NUM = 3; //最大车辆省份简称字符个数 + public static final int MAX_VL_NUM = 5; //最大虚拟线圈个数 + public static final int MAX_DRIVECHAN_NUM = 16; //最大车道数 + public static final int MAX_COIL_NUM = 3; //最大线圈个数 + public static final int MAX_SIGNALLIGHT_NUM = 6; //最大信号灯个数 + public static final int MAX_IOSPEED_GROUP_NUM = 4; //IO测速组个数 + public static final int MAX_IOOUT_NUM = 4; //最大IO输出口个数 + public static final int MAX_IOIN_NUM = 8; //最大IO输入口个数 + public static final int MAX_RELAY_NUM = 12; //继电器控制设备最大数 2013-11-04 + public static final int MAX_VEHICLE_TYPE_NUM = 8; //车辆信息管控最大数2013-11-04 + public static final int MAX_IOIN_NUMEX = 10; //最大IO输入口个数(扩展) + public static final int MAX_ITC_LANE_NUM = 6; //最大车道个数 + public static final int MAX_LANEAREA_NUM = 2; //单车道最大区域个数 + public static final int ITC_MAX_POLYGON_POINT_NUM = 20; //检测区域最多支持20个点的多边形 + public static final int MAX_ITC_SERIALCHECK_NUM = 8; //串口校验类型个数 + public static final int MAX_LIGHT_NUM = 6; //最大交通灯数 + public static final int MAX_VIDEO_INTERVAL_NUM = 2; //最大抓拍间隔数 + public static final int MAX_VIDEO_DETECT_LIGHT_NUM = 12; //视频检测的最大检测区域 + public static final int MAX_CALIB_RECOG_NUM = 2; //标定区域个数 + public static final int MAX_RS485_NUM = 12; //485口最大支持数 + public static final int MAX_MOBILE_POLYGON_NUM = 3; //移动布防支持最大牌识区域个数 + public static final int MAX_MOBILE_DETECTLINE_NUM = 3; //移动布防支持最大违规检测线个数 + public static final int MAX_IOOUT_K_NUM = 8; //K系列最大IO输出口个数 + + public static final int NET_SDK_MAX_FDID_LEN = 256; //人脸库ID最大长度 + public static final int NET_SDK_MAX_PICID_LEN = 256; //人脸ID最大长度 + public static final int NET_SDK_MAX_INDENTITY_KEY_LEN = 64; //交互操作口令长度 + + public static final int SEARCH_EVENT_INFO_LEN = 300; //事件信息长度 + public static final int SEARCH_EVENT_INFO_LEN_V40 = 800; + public static final int MAX_POS_KEYWORDS_NUM = 3; //支持关键字查找条数 + public static final int MAX_POS_KEYWORD_LEN = 128; //每条关键字长度 + public static final int INQUEST_CASE_LEN = 64; //审讯信息长度 + + public static final int SEARCH_CASE_NO_LEN = 56; + public static final int SEARCH_CASE_NAME_LEN = 100; + public static final int SEARCH_LITIGANT_LEN = 32; + public static final int SEARCH_CHIEF_JUDGE_LEN = 32; + public static final int CASE_NO_RET_LEN = 52; + public static final int CASE_NAME_RET_LEN = 64; + public static final int LITIGANT_RET_LEN = 24; + public static final int CHIEF_JUDGE_RET_LEN = 24; + public static final int NET_SDK_CASETYPE_LEN = 32; + public static final int NET_SDK_MAX_TAPE_INDEX_LEN = 32; //磁带编号最大长度 + public static final int NET_SDK_MAX_FILE_LEN = 256; //文件名最大长度 + /******************************************************************/ + + /******************* + * 全局错误码 begin + **********************/ + public static final int NET_DVR_NOERROR = 0; //没有错误 + public static final int NET_DVR_PASSWORD_ERROR = 1; //用户名密码错误 + public static final int NET_DVR_NOENOUGHPRI = 2;//权限不足 + public static final int NET_DVR_NOINIT = 3;//没有初始化 + public static final int NET_DVR_CHANNEL_ERROR = 4; //通道号错误 + public static final int NET_DVR_OVER_MAXLINK = 5; //连接到DVR的客户端个数超过最大 + public static final int NET_DVR_VERSIONNOMATCH = 6; //版本不匹配 + public static final int NET_DVR_NETWORK_FAIL_CONNECT = 7;//连接服务器失败 + public static final int NET_DVR_NETWORK_SEND_ERROR = 8; //向服务器发送失败 + public static final int NET_DVR_NETWORK_RECV_ERROR = 9; //从服务器接收数据失败 + public static final int NET_DVR_NETWORK_RECV_TIMEOUT = 10; //从服务器接收数据超时 + public static final int NET_DVR_NETWORK_ERRORDATA = 11; //传送的数据有误 + public static final int NET_DVR_ORDER_ERROR = 12; //调用次序错误 + public static final int NET_DVR_OPERNOPERMIT = 13; //无此权限 + public static final int NET_DVR_COMMANDTIMEOUT = 14; //DVR命令执行超时 + public static final int NET_DVR_ERRORSERIALPORT = 15; //串口号错误 + public static final int NET_DVR_ERRORALARMPORT = 16; //报警端口错误 + public static final int NET_DVR_PARAMETER_ERROR = 17;//参数错误 + public static final int NET_DVR_CHAN_EXCEPTION = 18; //服务器通道处于错误状态 + public static final int NET_DVR_NODISK = 19; //没有硬盘 + public static final int NET_DVR_ERRORDISKNUM = 20; //硬盘号错误 + public static final int NET_DVR_DISK_FULL = 21; //服务器硬盘满 + public static final int NET_DVR_DISK_ERROR = 22;//服务器硬盘出错 + public static final int NET_DVR_NOSUPPORT = 23;//服务器不支持 + public static final int NET_DVR_BUSY = 24;//服务器忙 + public static final int NET_DVR_MODIFY_FAIL = 25;//服务器修改不成功 + public static final int NET_DVR_PASSWORD_FORMAT_ERROR = 26;//密码输入格式不正确 + public static final int NET_DVR_DISK_FORMATING = 27; //硬盘正在格式化,不能启动操作 + public static final int NET_DVR_DVRNORESOURCE = 28; //DVR资源不足 + public static final int NET_DVR_DVROPRATEFAILED = 29; //DVR操作失败 + public static final int NET_DVR_OPENHOSTSOUND_FAIL = 30; //打开PC声音失败 + public static final int NET_DVR_DVRVOICEOPENED = 31; //服务器语音对讲被占用 + public static final int NET_DVR_TIMEINPUTERROR = 32; //时间输入不正确 + public static final int NET_DVR_NOSPECFILE = 33; //回放时服务器没有指定的文件 + public static final int NET_DVR_CREATEFILE_ERROR = 34; //创建文件出错 + public static final int NET_DVR_FILEOPENFAIL = 35; //打开文件出错 + public static final int NET_DVR_OPERNOTFINISH = 36; //上次的操作还没有完成 + public static final int NET_DVR_GETPLAYTIMEFAIL = 37; //获取当前播放的时间出错 + public static final int NET_DVR_PLAYFAIL = 38; //播放出错 + public static final int NET_DVR_FILEFORMAT_ERROR = 39;//文件格式不正确 + public static final int NET_DVR_DIR_ERROR = 40; //路径错误 + public static final int NET_DVR_ALLOC_RESOURCE_ERROR = 41;//资源分配错误 + public static final int NET_DVR_AUDIO_MODE_ERROR = 42; //声卡模式错误 + public static final int NET_DVR_NOENOUGH_BUF = 43; //缓冲区太小 + public static final int NET_DVR_CREATESOCKET_ERROR = 44; //创建SOCKET出错 + public static final int NET_DVR_SETSOCKET_ERROR = 45; //设置SOCKET出错 + public static final int NET_DVR_MAX_NUM = 46; //个数达到最大 + public static final int NET_DVR_USERNOTEXIST = 47; //用户不存在 + public static final int NET_DVR_WRITEFLASHERROR = 48;//写FLASH出错 + public static final int NET_DVR_UPGRADEFAIL = 49;//DVR升级失败 + public static final int NET_DVR_CARDHAVEINIT = 50; //解码卡已经初始化过 + public static final int NET_DVR_PLAYERFAILED = 51; //调用播放库中某个函数失败 + public static final int NET_DVR_MAX_USERNUM = 52; //设备端用户数达到最大 + public static final int NET_DVR_GETLOCALIPANDMACFAIL = 53;//获得客户端的IP地址或物理地址失败 + public static final int NET_DVR_NOENCODEING = 54; //该通道没有编码 + public static final int NET_DVR_IPMISMATCH = 55; //IP地址不匹配 + public static final int NET_DVR_MACMISMATCH = 56;//MAC地址不匹配 + public static final int NET_DVR_UPGRADELANGMISMATCH = 57;//升级文件语言不匹配 + public static final int NET_DVR_MAX_PLAYERPORT = 58;//播放器路数达到最大 + public static final int NET_DVR_NOSPACEBACKUP = 59;//备份设备中没有足够空间进行备份 + public static final int NET_DVR_NODEVICEBACKUP = 60; //没有找到指定的备份设备 + public static final int NET_DVR_PICTURE_BITS_ERROR = 61; //图像素位数不符,限24色 + public static final int NET_DVR_PICTURE_DIMENSION_ERROR = 62;//图片高*宽超限, 限128*256 + public static final int NET_DVR_PICTURE_SIZ_ERROR = 63; //图片大小超限,限100K + public static final int NET_DVR_LOADPLAYERSDKFAILED = 64; //载入当前目录下Player Sdk出错 + public static final int NET_DVR_LOADPLAYERSDKPROC_ERROR = 65; //找不到Player Sdk中某个函数入口 + public static final int NET_DVR_LOADDSSDKFAILED = 66; //载入当前目录下DSsdk出错 + public static final int NET_DVR_LOADDSSDKPROC_ERROR = 67; //找不到DsSdk中某个函数入口 + public static final int NET_DVR_DSSDK_ERROR = 68; //调用硬解码库DsSdk中某个函数失败 + public static final int NET_DVR_VOICEMONOPOLIZE = 69; //声卡被独占 + public static final int NET_DVR_JOINMULTICASTFAILED = 70; //加入多播组失败 + public static final int NET_DVR_CREATEDIR_ERROR = 71; //建立日志文件目录失败 + public static final int NET_DVR_BINDSOCKET_ERROR = 72; //绑定套接字失败 + public static final int NET_DVR_SOCKETCLOSE_ERROR = 73; //socket连接中断,此错误通常是由于连接中断或目的地不可达 + public static final int NET_DVR_USERID_ISUSING = 74; //注销时用户ID正在进行某操作 + public static final int NET_DVR_SOCKETLISTEN_ERROR = 75; //监听失败 + public static final int NET_DVR_PROGRAM_EXCEPTION = 76; //程序异常 + public static final int NET_DVR_WRITEFILE_FAILED = 77; //写文件失败 + public static final int NET_DVR_FORMAT_READONLY = 78;//禁止格式化只读硬盘 + public static final int NET_DVR_WITHSAMEUSERNAME = 79;//用户配置结构中存在相同的用户名 + public static final int NET_DVR_DEVICETYPE_ERROR = 80; /*导入参数时设备型号不匹配*/ + public static final int NET_DVR_LANGUAGE_ERROR = 81; /*导入参数时语言不匹配*/ + public static final int NET_DVR_PARAVERSION_ERROR = 82; /*导入参数时软件版本不匹配*/ + public static final int NET_DVR_IPCHAN_NOTALIVE = 83; /*预览时外接IP通道不在线*/ + public static final int NET_DVR_RTSP_SDK_ERROR = 84; /*加载高清IPC通讯库StreamTransClient.dll失败*/ + public static final int NET_DVR_CONVERT_SDK_ERROR = 85; /*加载转码库失败*/ + public static final int NET_DVR_IPC_COUNT_OVERFLOW = 86; /*超出最大的ip接入通道数*/ + public static final int NET_PLAYM4_NOERROR = 500; //no error + public static final int NET_PLAYM4_PARA_OVER = 501;//input parameter is invalid; + public static final int NET_PLAYM4_ORDER_ERROR = 502;//The order of the function to be called is error. + public static final int NET_PLAYM4_TIMER_ERROR = 503;//Create multimedia clock failed; + public static final int NET_PLAYM4_DEC_VIDEO_ERROR = 504;//Decode video data failed. + public static final int NET_PLAYM4_DEC_AUDIO_ERROR = 505;//Decode audio data failed. + public static final int NET_PLAYM4_ALLOC_MEMORY_ERROR = 506; //Allocate memory failed. + public static final int NET_PLAYM4_OPEN_FILE_ERROR = 507; //Open the file failed. + public static final int NET_PLAYM4_CREATE_OBJ_ERROR = 508;//Create thread or event failed + public static final int NET_PLAYM4_CREATE_DDRAW_ERROR = 509;//Create DirectDraw object failed. + public static final int NET_PLAYM4_CREATE_OFFSCREEN_ERROR = 510;//failed when creating off-screen surface. + public static final int NET_PLAYM4_BUF_OVER = 511; //buffer is overflow + public static final int NET_PLAYM4_CREATE_SOUND_ERROR = 512; //failed when creating audio device. + public static final int NET_PLAYM4_SET_VOLUME_ERROR = 513;//Set volume failed + public static final int NET_PLAYM4_SUPPORT_FILE_ONLY = 514;//The function only support play file. + public static final int NET_PLAYM4_SUPPORT_STREAM_ONLY = 515;//The function only support play stream. + public static final int NET_PLAYM4_SYS_NOT_SUPPORT = 516;//System not support. + public static final int NET_PLAYM4_FILEHEADER_UNKNOWN = 517; //No file header. + public static final int NET_PLAYM4_VERSION_INCORRECT = 518; //The version of decoder and encoder is not adapted. + public static final int NET_PALYM4_INIT_DECODER_ERROR = 519; //Initialize decoder failed. + public static final int NET_PLAYM4_CHECK_FILE_ERROR = 520; //The file data is unknown. + public static final int NET_PLAYM4_INIT_TIMER_ERROR = 521; //Initialize multimedia clock failed. + public static final int NET_PLAYM4_BLT_ERROR = 522;//Blt failed. + public static final int NET_PLAYM4_UPDATE_ERROR = 523;//Update failed. + public static final int NET_PLAYM4_OPEN_FILE_ERROR_MULTI = 524; //openfile error, streamtype is multi + public static final int NET_PLAYM4_OPEN_FILE_ERROR_VIDEO = 525; //openfile error, streamtype is video + public static final int NET_PLAYM4_JPEG_COMPRESS_ERROR = 526; //JPEG compress error + public static final int NET_PLAYM4_EXTRACT_NOT_SUPPORT = 527; //Don't support the version of this file. + public static final int NET_PLAYM4_EXTRACT_DATA_ERROR = 528; //extract video data failed. + /*******************全局错误码 end**********************/ + /************************************************* + * NET_DVR_IsSupport()返回值 + * 1-9位分别表示以下信息(位与是TRUE)表示支持; + **************************************************/ + public static final int NET_DVR_SUPPORT_DDRAW = 0x01;//支持DIRECTDRAW,如果不支持,则播放器不能工作; + public static final int NET_DVR_SUPPORT_BLT = 0x02;//显卡支持BLT操作,如果不支持,则播放器不能工作; + public static final int NET_DVR_SUPPORT_BLTFOURCC = 0x04;//显卡BLT支持颜色转换,如果不支持,播放器会用软件方法作RGB转换; + public static final int NET_DVR_SUPPORT_BLTSHRINKX = 0x08;//显卡BLT支持X轴缩小;如果不支持,系统会用软件方法转换; + public static final int NET_DVR_SUPPORT_BLTSHRINKY = 0x10;//显卡BLT支持Y轴缩小;如果不支持,系统会用软件方法转换; + public static final int NET_DVR_SUPPORT_BLTSTRETCHX = 0x20;//显卡BLT支持X轴放大;如果不支持,系统会用软件方法转换; + public static final int NET_DVR_SUPPORT_BLTSTRETCHY = 0x40;//显卡BLT支持Y轴放大;如果不支持,系统会用软件方法转换; + public static final int NET_DVR_SUPPORT_SSE = 0x80;//CPU支持SSE指令, Pentium3以上支持SSE指令; + public static final int NET_DVR_SUPPORT_MMX = 0x100;//CPU支持MMX指令集, Pentium3以上支持SSE指令; + /********************** + * 云台控制命令 begin + *************************/ + public static final int LIGHT_PWRON = 2; /* 接通灯光电源 */ + public static final int WIPER_PWRON = 3; /* 接通雨刷开关 */ + public static final int FAN_PWRON = 4; /* 接通风扇开关 */ + public static final int HEATER_PWRON = 5; /* 接通加热器开关 */ + public static final int AUX_PWRON1 = 6; /* 接通辅助设备开关 */ + public static final int AUX_PWRON2 = 7; /* 接通辅助设备开关 */ + public static final int SET_PRESET = 8; /* 设置预置点 */ + public static final int CLE_PRESET = 9; /* 清除预置点 */ + public static final int ZOOM_IN = 11; /* 焦距以速度SS变大(倍率变大) 调焦 */ + public static final int ZOOM_OUT = 12; /* 焦距以速度SS变小(倍率变小) */ + public static final int FOCUS_NEAR = 13; /* 焦点以速度SS前调 */ + public static final int FOCUS_FAR = 14; /* 焦点以速度SS后调 */ + public static final int IRIS_OPEN = 15; /* 光圈以速度SS扩大 */ + public static final int IRIS_CLOSE = 16; /* 光圈以速度SS缩小 */ + public static final int TILT_UP = 21; /* 云台以SS的速度上仰 */ + public static final int TILT_DOWN = 22; /* 云台以SS的速度下俯 */ + public static final int PAN_LEFT = 23; /* 云台以SS的速度左转 */ + public static final int PAN_RIGHT = 24; /* 云台以SS的速度右转 */ + public static final int UP_LEFT = 25; /* 云台以SS的速度上仰和左转 */ + public static final int UP_RIGHT = 26; /* 云台以SS的速度上仰和右转 */ + public static final int DOWN_LEFT = 27; /* 云台以SS的速度下俯和左转 */ + public static final int DOWN_RIGHT = 28; /* 云台以SS的速度下俯和右转 */ + public static final int PAN_AUTO = 29; /* 云台以SS的速度左右自动扫描 */ + public static final int FILL_PRE_SEQ = 30; /* 将预置点加入巡航序列 */ + public static final int SET_SEQ_DWELL = 31; /* 设置巡航点停顿时间 */ + public static final int SET_SEQ_SPEED = 32; /* 设置巡航速度 */ + public static final int CLE_PRE_SEQ = 33;/* 将预置点从巡航序列中删除 */ + public static final int STA_MEM_CRUISE = 34;/* 开始记录 */ + public static final int STO_MEM_CRUISE = 35;/* 停止记录 */ + public static final int RUN_CRUISE = 36; /* 开始 */ + public static final int RUN_SEQ = 37; /* 开始巡航 */ + public static final int STOP_SEQ = 38; /* 停止巡航 */ + public static final int GOTO_PRESET = 39; /* 快球转到预置点 */ + + /**********************云台控制命令 end*************************/ + /************************************************* + * 回放时播放控制命令宏定义 + * NET_DVR_PlayBackControl + * NET_DVR_PlayControlLocDisplay + * NET_DVR_DecPlayBackCtrl的宏定义 + * 具体支持查看函数说明和代码 + **************************************************/ + public static final int NET_DVR_PLAYSTART = 1;//开始播放 + public static final int NET_DVR_PLAYSTOP = 2;//停止播放 + public static final int NET_DVR_PLAYPAUSE = 3;//暂停播放 + public static final int NET_DVR_PLAYRESTART = 4;//恢复播放 + public static final int NET_DVR_PLAYFAST = 5;//快放 + public static final int NET_DVR_PLAYSLOW = 6;//慢放 + public static final int NET_DVR_PLAYNORMAL = 7;//正常速度 + public static final int NET_DVR_PLAYFRAME = 8;//单帧放 + public static final int NET_DVR_PLAYSTARTAUDIO = 9;//打开声音 + public static final int NET_DVR_PLAYSTOPAUDIO = 10;//关闭声音 + public static final int NET_DVR_PLAYAUDIOVOLUME = 11;//调节音量 + public static final int NET_DVR_PLAYSETPOS = 12;//改变文件回放的进度 + public static final int NET_DVR_PLAYGETPOS = 13;//获取文件回放的进度 + public static final int NET_DVR_PLAYGETTIME = 14;//获取当前已经播放的时间(按文件回放的时候有效) + public static final int NET_DVR_PLAYGETFRAME = 15;//获取当前已经播放的帧数(按文件回放的时候有效) + public static final int NET_DVR_GETTOTALFRAMES = 16;//获取当前播放文件总的帧数(按文件回放的时候有效) + public static final int NET_DVR_GETTOTALTIME = 17;//获取当前播放文件总的时间(按文件回放的时候有效) + public static final int NET_DVR_THROWBFRAME = 20;//丢B帧 + public static final int NET_DVR_SETSPEED = 24;//设置码流速度 + public static final int NET_DVR_KEEPALIVE = 25;//保持与设备的心跳(如果回调阻塞,建议2秒发送一次) + public static final int NET_DVR_SET_TRANS_TYPE = 32; //设置转码格式 + + //远程按键定义如下: + /* key value send to CONFIG program */ + public static final int KEY_CODE_1 = 1; + public static final int KEY_CODE_2 = 2; + public static final int KEY_CODE_3 = 3; + public static final int KEY_CODE_4 = 4; + public static final int KEY_CODE_5 = 5; + public static final int KEY_CODE_6 = 6; + public static final int KEY_CODE_7 = 7; + public static final int KEY_CODE_8 = 8; + public static final int KEY_CODE_9 = 9; + public static final int KEY_CODE_0 = 10; + public static final int KEY_CODE_POWER = 11; + public static final int KEY_CODE_MENU = 12; + public static final int KEY_CODE_ENTER = 13; + public static final int KEY_CODE_CANCEL = 14; + public static final int KEY_CODE_UP = 15; + public static final int KEY_CODE_DOWN = 16; + public static final int KEY_CODE_LEFT = 17; + public static final int KEY_CODE_RIGHT = 18; + public static final int KEY_CODE_EDIT = 19; + public static final int KEY_CODE_ADD = 20; + public static final int KEY_CODE_MINUS = 21; + public static final int KEY_CODE_PLAY = 22; + public static final int KEY_CODE_REC = 23; + public static final int KEY_CODE_PAN = 24; + public static final int KEY_CODE_M = 25; + public static final int KEY_CODE_A = 26; + public static final int KEY_CODE_F1 = 27; + public static final int KEY_CODE_F2 = 28; + + /* for PTZ control */ + public static final int KEY_PTZ_UP_START = KEY_CODE_UP; + public static final int KEY_PTZ_UP_STO = 32; + public static final int KEY_PTZ_DOWN_START = KEY_CODE_DOWN; + public static final int KEY_PTZ_DOWN_STOP = 33; + public static final int KEY_PTZ_LEFT_START = KEY_CODE_LEFT; + public static final int KEY_PTZ_LEFT_STOP = 34; + public static final int KEY_PTZ_RIGHT_START = KEY_CODE_RIGHT; + public static final int KEY_PTZ_RIGHT_STOP = 35; + public static final int KEY_PTZ_AP1_START = KEY_CODE_EDIT;/* 光圈+ */ + public static final int KEY_PTZ_AP1_STOP = 36; + public static final int KEY_PTZ_AP2_START = KEY_CODE_PAN;/* 光圈- */ + public static final int KEY_PTZ_AP2_STOP = 37; + public static final int KEY_PTZ_FOCUS1_START = KEY_CODE_A;/* 聚焦+ */ + public static final int KEY_PTZ_FOCUS1_STOP = 38; + public static final int KEY_PTZ_FOCUS2_START = KEY_CODE_M;/* 聚焦- */ + public static final int KEY_PTZ_FOCUS2_STOP = 39; + public static final int KEY_PTZ_B1_START = 40;/* 变倍+ */ + public static final int KEY_PTZ_B1_STOP = 41; + public static final int KEY_PTZ_B2_START = 42;/* 变倍- */ + public static final int KEY_PTZ_B2_STOP = 43; + //9000新增 + public static final int KEY_CODE_11 = 44; + public static final int KEY_CODE_12 = 45; + public static final int KEY_CODE_13 = 46; + public static final int KEY_CODE_14 = 47; + public static final int KEY_CODE_15 = 48; + public static final int KEY_CODE_16 = 49; + /************************* + * 参数配置命令 begin + *******************************/ +//用于NET_DVR_SetDVRConfig和NET_DVR_GetDVRConfig,注意其对应的配置结构 + public static final int NET_DVR_GET_DEVICECFG = 100; //获取设备参数 + public static final int NET_DVR_SET_DEVICECFG = 101; //设置设备参数 + public static final int NET_DVR_GET_DEVICECFG_V40 = 1100; //获取扩展设备参数 + public static final int NET_DVR_SET_DEVICECFG_V40 = 1101; //设置扩展设备参数 + public static final int NET_DVR_GET_NETCFG = 102; //获取网络参数 + public static final int NET_DVR_SET_NETCFG = 103; //设置网络参数 + public static final int NET_DVR_GET_PICCFG = 104; //获取图象参数 + public static final int NET_DVR_SET_PICCFG = 105; //设置图象参数 + public static final int NET_DVR_GET_COMPRESSCFG = 106; //获取压缩参数 + public static final int NET_DVR_SET_COMPRESSCFG = 107; //设置压缩参数 + public static final int NET_DVR_GET_RECORDCFG = 108; //获取录像时间参数 + public static final int NET_DVR_SET_RECORDCFG = 109; //设置录像时间参数 + public static final int NET_DVR_GET_DECODERCFG = 110; //获取解码器参数 + public static final int NET_DVR_SET_DECODERCFG = 111; //设置解码器参数 + public static final int NET_DVR_GET_RS232CFG = 112; //获取232串口参数 + public static final int NET_DVR_SET_RS232CFG = 113; //设置232串口参数 + public static final int NET_DVR_GET_ALARMINCFG = 114; //获取报警输入参数 + public static final int NET_DVR_SET_ALARMINCFG = 115; //设置报警输入参数 + public static final int NET_DVR_GET_ALARMOUTCFG = 116; //获取报警输出参数 + public static final int NET_DVR_SET_ALARMOUTCFG = 117; //设置报警输出参数 + public static final int NET_DVR_GET_TIMECFG = 118; //获取DVR时间 + public static final int NET_DVR_SET_TIMECFG = 119; //设置DVR时间 + public static final int NET_DVR_GET_PREVIEWCFG = 120; //获取预览参数 + public static final int NET_DVR_SET_PREVIEWCFG = 121; //设置预览参数 + public static final int NET_DVR_GET_VIDEOOUTCFG = 122; //获取视频输出参数 + public static final int NET_DVR_SET_VIDEOOUTCFG = 123; //设置视频输出参数 + public static final int NET_DVR_GET_USERCFG = 124; //获取用户参数 + public static final int NET_DVR_SET_USERCFG = 125; //设置用户参数 + public static final int NET_DVR_GET_EXCEPTIONCFG = 126; //获取异常参数 + public static final int NET_DVR_SET_EXCEPTIONCFG = 127; //设置异常参数 + public static final int NET_DVR_GET_ZONEANDDST = 128; //获取时区和夏时制参数 + public static final int NET_DVR_SET_ZONEANDDST = 129; //设置时区和夏时制参数 + public static final int NET_DVR_GET_SHOWSTRING = 130; //获取叠加字符参数 + public static final int NET_DVR_SET_SHOWSTRING = 131; //设置叠加字符参数 + public static final int NET_DVR_GET_EVENTCOMPCFG = 132; //获取事件触发录像参数 + public static final int NET_DVR_SET_EVENTCOMPCFG = 133; //设置事件触发录像参数 + public static final int NET_DVR_GET_AUXOUTCFG = 140; //获取报警触发辅助输出设置(HS设备辅助输出2006-02-28) + public static final int NET_DVR_SET_AUXOUTCFG = 141; //设置报警触发辅助输出设置(HS设备辅助输出2006-02-28) + public static final int NET_DVR_GET_PREVIEWCFG_AUX = 142; //获取-s系列双输出预览参数(-s系列双输出2006-04-13) + public static final int NET_DVR_SET_PREVIEWCFG_AUX = 143; //设置-s系列双输出预览参数(-s系列双输出2006-04-13) + public static final int NET_DVR_GET_PICCFG_EX = 200; //获取图象参数(SDK_V14扩展命令) + public static final int NET_DVR_SET_PICCFG_EX = 201; //设置图象参数(SDK_V14扩展命令) + public static final int NET_DVR_GET_USERCFG_EX = 202; //获取用户参数(SDK_V15扩展命令) + public static final int NET_DVR_SET_USERCFG_EX = 203; //设置用户参数(SDK_V15扩展命令) + public static final int NET_DVR_GET_COMPRESSCFG_EX = 204; //获取压缩参数(SDK_V15扩展命令2006-05-15) + public static final int NET_DVR_SET_COMPRESSCFG_EX = 205; //设置压缩参数(SDK_V15扩展命令2006-05-15) + public static final int NET_DVR_GET_NETAPPCFG = 222; //获取网络应用参数 NTP/DDNS/EMAIL + public static final int NET_DVR_SET_NETAPPCFG = 223; //设置网络应用参数 NTP/DDNS/EMAIL + public static final int NET_DVR_GET_NTPCFG = 224; //获取网络应用参数 NTP + public static final int NET_DVR_SET_NTPCFG = 225; //设置网络应用参数 NTP + public static final int NET_DVR_GET_DDNSCFG = 226; //获取网络应用参数 DDNS + public static final int NET_DVR_SET_DDNSCFG = 227; //设置网络应用参数 DDNS + //对应NET_DVR_EMAILPARA + public static final int NET_DVR_GET_EMAILCFG = 228; //获取网络应用参数 EMAIL + public static final int NET_DVR_SET_EMAILCFG = 229; //设置网络应用参数 EMAIL + public static final int NET_DVR_GET_NFSCFG = 230; /* NFS disk config */ + public static final int NET_DVR_SET_NFSCFG = 231; /* NFS disk config */ + public static final int NET_DVR_GET_SHOWSTRING_EX = 238; //获取叠加字符参数扩展(支持8条字符) + public static final int NET_DVR_SET_SHOWSTRING_EX = 239; //设置叠加字符参数扩展(支持8条字符) + public static final int NET_DVR_GET_NETCFG_OTHER = 244; //获取网络参数 + public static final int NET_DVR_SET_NETCFG_OTHER = 245; //设置网络参数 + //对应NET_DVR_EMAILCFG结构 + public static final int NET_DVR_GET_EMAILPARACFG = 250; //Get EMAIL parameters + public static final int NET_DVR_SET_EMAILPARACFG = 251; //Setup EMAIL parameters + public static final int NET_DVR_GET_DDNSCFG_EX = 274;//获取扩展DDNS参数 + public static final int NET_DVR_SET_DDNSCFG_EX = 275;//设置扩展DDNS参数 + public static final int NET_DVR_SET_PTZPOS = 292; //云台设置PTZ位置 + public static final int NET_DVR_GET_PTZPOS = 293; //云台获取PTZ位置 + public static final int NET_DVR_GET_PTZSCOPE = 294;//云台获取PTZ范围 + public static final int NET_DVR_GET_PTZLOCKCFG=3287;//获取云台锁定信息 + public static final int NET_DVR_SET_PTZLOCKCFG=3288;//设置云台锁定信息 + + public static final int NET_DVR_COMPLETE_RESTORE_CTRL = 3420; //设置完全恢复出厂值 + /*************************** + * DS9000新增命令(_V30) begin + *****************************/ +//网络(NET_DVR_NETCFG_V30结构) + public static final int NET_DVR_GET_NETCFG_V30 = 1000; //获取网络参数 + public static final int NET_DVR_SET_NETCFG_V30 = 1001; //设置网络参数 + //图象(NET_DVR_PICCFG_V30结构) + public static final int NET_DVR_GET_PICCFG_V30 = 1002; //获取图象参数 + public static final int NET_DVR_SET_PICCFG_V30 = 1003; //设置图象参数 + public static final int NET_DVR_GET_PICCFG_V40 = 6179; //获取图象参数 + public static final int NET_DVR_SET_PICCFG_V40 = 6180; //设置图象参数 + public static final int NET_DVR_GET_AES_KEY = 6113; //获取设备AES加密密钥 + //录像时间(NET_DVR_RECORD_V30结构) + public static final int NET_DVR_GET_RECORDCFG_V30 = 1004; //获取录像参数 + public static final int NET_DVR_SET_RECORDCFG_V30 = 1005; //设置录像参数 + //用户(NET_DVR_USER_V30结构) + public static final int NET_DVR_GET_USERCFG_V30 = 1006; //获取用户参数 + public static final int NET_DVR_SET_USERCFG_V30 = 1007; //设置用户参数 + //9000DDNS参数配置(NET_DVR_DDNSPARA_V30结构) + public static final int NET_DVR_GET_DDNSCFG_V30 = 1010; //获取DDNS(9000扩展) + public static final int NET_DVR_SET_DDNSCFG_V30 = 1011; //设置DDNS(9000扩展) + //EMAIL功能(NET_DVR_EMAILCFG_V30结构) + public static final int NET_DVR_GET_EMAILCFG_V30 = 1012;//获取EMAIL参数 + public static final int NET_DVR_SET_EMAILCFG_V30 = 1013;//设置EMAIL参数 + //巡航参数 (NET_DVR_CRUISE_PARA结构) + public static final int NET_DVR_GET_CRUISE = 1020; + public static final int NET_DVR_SET_CRUISE = 1021; + //报警输入结构参数 (NET_DVR_ALARMINCFG_V30结构) + public static final int NET_DVR_GET_ALARMINCFG_V30 = 1024; + public static final int NET_DVR_SET_ALARMINCFG_V30 = 1025; + //报警输出结构参数 (NET_DVR_ALARMOUTCFG_V30结构) + public static final int NET_DVR_GET_ALARMOUTCFG_V30 = 1026; + public static final int NET_DVR_SET_ALARMOUTCFG_V30 = 1027; + //视频输出结构参数 (NET_DVR_VIDEOOUT_V30结构) + public static final int NET_DVR_GET_VIDEOOUTCFG_V30 = 1028; + public static final int NET_DVR_SET_VIDEOOUTCFG_V30 = 1029; + //叠加字符结构参数 (NET_DVR_SHOWSTRING_V30结构) + public static final int NET_DVR_GET_SHOWSTRING_V30 = 1030; + public static final int NET_DVR_SET_SHOWSTRING_V30 = 1031; + //异常结构参数 (NET_DVR_EXCEPTION_V30结构) + public static final int NET_DVR_GET_EXCEPTIONCFG_V30 = 1034; + public static final int NET_DVR_SET_EXCEPTIONCFG_V30 = 1035; + //串口232结构参数 (NET_DVR_RS232CFG_V30结构) + public static final int NET_DVR_GET_RS232CFG_V30 = 1036; + public static final int NET_DVR_SET_RS232CFG_V30 = 1037; + //压缩参数 (NET_DVR_COMPRESSIONCFG_V30结构) + public static final int NET_DVR_GET_COMPRESSCFG_V30 = 1040; + public static final int NET_DVR_SET_COMPRESSCFG_V30 = 1041; + //获取485解码器参数 (NET_DVR_DECODERCFG_V30结构) + public static final int NET_DVR_GET_DECODERCFG_V30 = 1042; //获取解码器参数 + public static final int NET_DVR_SET_DECODERCFG_V30 = 1043; //设置解码器参数 + //获取预览参数 (NET_DVR_PREVIEWCFG_V30结构) + public static final int NET_DVR_GET_PREVIEWCFG_V30 = 1044; //获取预览参数 + public static final int NET_DVR_SET_PREVIEWCFG_V30 = 1045; //设置预览参数 + //辅助预览参数 (NET_DVR_PREVIEWCFG_AUX_V30结构) + public static final int NET_DVR_GET_PREVIEWCFG_AUX_V30 = 1046; //获取辅助预览参数 + public static final int NET_DVR_SET_PREVIEWCFG_AUX_V30 = 1047; //设置辅助预览参数 + //IP接入配置参数 (NET_DVR_IPPARACFG结构) + public static final int NET_DVR_GET_IPPARACFG = 1048; //获取IP接入配置信息 + public static final int NET_DVR_SET_IPPARACFG = 1049; //设置IP接入配置信息 + //IP接入配置参数V40 (NET_DVR_IPPARACFG_V40结构) + public static final int NET_DVR_GET_IPPARACFG_V40 = 1062; //获取IP接入配置信息 + public static final int NET_DVR_SET_IPPARACFG_V40 = 1063; //设置IP接入配置信息 + //IP报警输入接入配置参数 (NET_DVR_IPALARMINCFG结构) + public static final int NET_DVR_GET_IPALARMINCFG = 1050; //获取IP报警输入接入配置信息 + public static final int NET_DVR_SET_IPALARMINCFG = 1051; //设置IP报警输入接入配置信息 + //IP报警输出接入配置参数 (NET_DVR_IPALARMOUTCFG结构) + public static final int NET_DVR_GET_IPALARMOUTCFG = 1052; //获取IP报警输出接入配置信息 + public static final int NET_DVR_SET_IPALARMOUTCFG = 1053; //设置IP报警输出接入配置信息 + //硬盘管理的参数获取 (NET_DVR_HDCFG结构) + public static final int NET_DVR_GET_HDCFG = 1054; //获取硬盘管理配置参数 + public static final int NET_DVR_SET_HDCFG = 1055; //设置硬盘管理配置参数 + //盘组管理的参数获取 (NET_DVR_HDGROUP_CFG结构) + public static final int NET_DVR_GET_HDGROUP_CFG = 1056; //获取盘组管理配置参数 + public static final int NET_DVR_SET_HDGROUP_CFG = 1057; //设置盘组管理配置参数 + //设备编码类型配置(NET_DVR_COMPRESSION_AUDIO结构) + public static final int NET_DVR_GET_COMPRESSCFG_AUD = 1058; //获取设备语音对讲编码参数 + public static final int NET_DVR_SET_COMPRESSCFG_AUD = 1059; //设置设备语音对讲编码参数 + + public static final int NET_SDK_FINDMEDICALFILE = 3954; //慧影科技智慧医疗查找录像文件 + public static final int NET_SDK_FINDMEDICALPICTURE = 3955; //慧影科技智慧医疗查找图片文件 + + public static final int NET_DVR_GET_RAPIDMOVE_DETECTION = 3539; //获取快速运动侦测配置 + public static final int NET_DVR_SET_RAPIDMOVE_DETECTION = 3540; //设置快速运动侦测配置 + + public static final int NET_DVR_GET_RAPIDMOVE_TRIGGER = 3543; //获取快速运动联动配置 + public static final int NET_DVR_SET_RAPIDMOVE_TRIGGER = 3544; //设置快速运动联动配置 + public static final int NET_DVR_GET_RAPIDMOVE_SCHEDULE = 3545; //获取快速运动的布防时间配置 + public static final int NET_DVR_SET_RAPIDMOVE_SCHEDULE = 3546; //设置快速运动的布防时间配置 + + public static final int NET_DVR_GET_PRESET_NAME = 3383; //获取预置点名称 + public static final int NET_DVR_SET_PRESET_NAME = 3382; //设置预置点名称 + public static final int NET_DVR_GET_RULECFG_V42 = 5049; //获取异常行为检测参数(支持16条规则扩展) + public static final int NET_DVR_SET_RULECFG_V42 = 5050; //设置异常行为检测参数(支持16条规则扩展) + + //车牌识别(NET_VCA_PLATE_CFG); + public static final int NET_DVR_SET_PLATECFG = 150;//设置车牌识别参数 + + public static final int NET_DVR_GET_PLATECFG = 151; //获取车牌识别参数 + //行为对应(NET_VCA_RULECFG) + public static final int NET_DVR_SET_RULECFG = 152; //设置异常行为检测规则 + public static final int NET_DVR_GET_RULECFG = 153;//获取异常行为检测规则 + //双摄像机标定参数(NET_DVR_LF_CFG) + public static final int NET_DVR_SET_LF_CFG = 160;//设置双摄像机的配置参数 + public static final int NET_DVR_GET_LF_CFG = 161;//获取双摄像机的配置参数 + //智能分析仪取流配置结构 + public static final int NET_DVR_SET_IVMS_STREAMCFG = 162; //设置智能分析仪取流参数 + public static final int NET_DVR_GET_IVMS_STREAMCFG = 163; //获取智能分析仪取流参数 + //智能控制参数结构 + public static final int NET_DVR_SET_VCA_CTRLCFG = 164; //设置智能控制参数 + public static final int NET_DVR_GET_VCA_CTRLCFG = 165; //获取智能控制参数 + //屏蔽区域NET_VCA_MASK_REGION_LIST + public static final int NET_DVR_SET_VCA_MASK_REGION = 166; //设置屏蔽区域参数 + public static final int NET_DVR_GET_VCA_MASK_REGION = 167; //获取屏蔽区域参数 + //ATM进入区域 NET_VCA_ENTER_REGION + public static final int NET_DVR_SET_VCA_ENTER_REGION = 168; //设置进入区域参数 + public static final int NET_DVR_GET_VCA_ENTER_REGION = 169; //获取进入区域参数 + //标定线配置NET_VCA_LINE_SEGMENT_LIST + public static final int NET_DVR_SET_VCA_LINE_SEGMENT = 170; //设置标定线 + public static final int NET_DVR_GET_VCA_LINE_SEGMENT = 171; //获取标定线 + // ivms屏蔽区域NET_IVMS_MASK_REGION_LIST + public static final int NET_DVR_SET_IVMS_MASK_REGION = 172; //设置IVMS屏蔽区域参数 + public static final int NET_DVR_GET_IVMS_MASK_REGION = 173; //获取IVMS屏蔽区域参数 + // ivms进入检测区域NET_IVMS_ENTER_REGION + public static final int NET_DVR_SET_IVMS_ENTER_REGION = 174; //设置IVMS进入区域参数 + public static final int NET_DVR_GET_IVMS_ENTER_REGION = 175; //获取IVMS进入区域参数 + public static final int NET_DVR_SET_IVMS_BEHAVIORCFG = 176;//设置智能分析仪行为规则参数 + public static final int NET_DVR_GET_IVMS_BEHAVIORCFG = 177; //获取智能分析仪行为规则参数 + public static final int NET_DVR_GET_TRAVERSE_PLANE_DETECTION = 3360; //获取越界侦测配置 + public static final int NET_DVR_SET_TRAVERSE_PLANE_DETECTION = 3361; + public static final int NET_DVR_GET_FIELD_DETECTION = 3362; //获取区域侦测配置 + public static final int NET_DVR_SET_FIELD_DETECTION = 3363; //设置区域侦测配置 + + public static final int NET_DVR_GET_STREAM_INFO = 6023; //获取已添加流ID信息 + public static final int NET_DVR_GET_STREAM_RECORD_STATUS = 6021; //获取流状态信息 + + public static final int NET_DVR_GET_ALL_VEHICLE_CONTROL_LIST = 3124; //获取所有车辆禁止和允许名单信息 + public static final int NET_DVR_VEHICLELIST_CTRL_START = 3133; //设置车辆禁止和允许名单信息(批量) + public static final int ENUM_SENDDATA = 0x0; //发送数据 + + public static final int NET_DVR_GET_LEDDISPLAY_CFG = 3673; + public static final int NET_DVR_SET_LEDDISPLAY_CFG = 3672; + public static final int NET_DVR_SET_VOICEBROADCAST_CFG = 3675; + public static final int NET_DVR_SET_CHARGE_ACCOUNTINFO = 3662; + + public static final int NET_DVR_GET_TRAFFIC_DATA = 3141; //长连接获取交通数据 + public static final int NET_DVR_GET_TRAFFIC_FLOW = 3142; //长连接获取交通流量 + + public static final int NET_DVR_GET_CCDPARAMCFG_EX = 3368;//获取前端参数(扩展) + public static final int NET_DVR_SET_CCDPARAMCFG_EX = 3369;//设置前端参数(扩展) + public static final int NET_DVR_GET_FOCUSMODECFG = 3305;//获取快球聚焦模式信息 + public static final int NET_DVR_SET_FOCUSMODECFG = 3306;//设置快球聚焦模式信息 + + public static final int NET_DVR_GET_SUPPLEMENTLIGHT = 3728; //获取内置补光灯配置协议 + public static final int NET_DVR_SET_SUPPLEMENTLIGHT = 3729; //设置内置补光灯配置协议 + + public static final int NET_DVR_GET_FACECONTRAST_TRIGGER = 3965;//获取人脸比对联动配置 + public static final int NET_DVR_SET_FACECONTRAST_TRIGGER = 3966;//设置人脸比对联动配置 + + public static final int NET_DVR_GET_FACECONTRAST_SCHEDULE = 3968;//获取人脸比对布防时间配置 + public static final int NET_DVR_SET_FACECONTRAST_SCHEDULE = 3969;//设置人脸比对布防时间配置 + + public static final int NET_DVR_INQUEST_GET_CDW_STATUS = 6350; //获取审讯机刻录状态-长连接 + + public static final int NET_DVR_GET_REALTIME_THERMOMETRY = 3629; //实时温度检测 + public static final int NET_DVR_GET_MANUALTHERM_INFO = 6706; //手动测温实时获取 + public static final int NET_DVR_GET_THERMOMETRY_MODE = 6765;//获取测温模式参数 + public static final int NET_DVR_SET_THERMOMETRY_MODE = 6766;//设置测温模式参数 + public static final int NET_DVR_GET_PTZABSOLUTEEX = 6696; + public static final int NET_DVR_GET_THERMOMETRY_PRESETINFO = 3624; //获取测温预置点关联配置参数 + public static final int NET_DVR_PTZ_PARKACTIONCFG = 3315; //获取测温预置点关联配置参数 + + public static final int NET_DVR_SET_THERMOMETRY_PRESETINFO = 3625; //设置测温预置点关联配置参数 + public static final int NET_DVR_GET_THERMOMETRYRULE_TEMPERATURE_INFO = 23001;//手动获取测温规则温度信息 + public static final int NET_DVR_SET_DEVSERVER_CFG = 3258;//设置模块服务配置 + + public static final int NET_DVR_GET_PHY_DISK_INFO = 6306; //获取物理磁盘信息 + public static final int NET_DVR_GET_WORK_STATUS = 6189; //获取设备工作状态 + public static final int NET_DVR_GET_MONTHLY_RECORD_DISTRIBUTION = 6164; //获取月历录像分布 + + public static final int NET_DVR_GET_CURTRIGGERMODE = 3130; //获取设备当前触发模式 + public static final int NET_ITC_GET_TRIGGERCFG = 3003; //获取触发参数 + public static final int NET_ITC_SET_TRIGGERCFG = 3004; //设置触发参数 + public static final int NET_ITC_GET_VIDEO_TRIGGERCFG = 3017; //获取视频电警触发参数 + public static final int NET_ITC_SET_VIDEO_TRIGGERCFG = 3018; //设置视频电警触发参数 + + public static final int NET_DVR_GET_MULTI_STREAM_COMPRESSIONCFG = 3216;//远程获取多码流压缩参数 + public static final int NET_DVR_SET_MULTI_STREAM_COMPRESSIONCFG = 3217;//远程设置多码流压缩参数 + + public static final int NET_DVR_GET_CMS_CFG = 2070; + public static final int NET_DVR_SET_CMS_CFG = 2071; + + public static final int NET_DVR_GET_ALARM_INFO = 4193; //获取报警事件数据 + /***************************DS9000新增命令(_V30) end *****************************/ + + /*************************参数配置命令 end*******************************/ + /*************************************特征识别门禁一体机1.0 begin**************************************/ + public static final int NET_DVR_GET_CARD_CFG = 2116; //获取卡参数 + public static final int NET_DVR_SET_CARD_CFG = 2117; //设置卡参数 + public static final int NET_DVR_GET_CARD_CFG_V50 = 2178; //获取新卡参数(V50) + public static final int NET_DVR_SET_CARD_CFG_V50 = 2179; //设置新卡参数(V50) + public static final int NET_DVR_GET_FACE_PARAM_CFG = 2507; //获取人脸参数 + public static final int NET_DVR_SET_FACE_PARAM_CFG = 2508; //设置人脸参数 + public static final int NET_DVR_DEL_FACE_PARAM_CFG = 2509; //删除人脸参数 + public static final int NET_DVR_CLEAR_ACS_PARAM = 2118; //清空门禁主机参数 + public static final int NET_DVR_DEL_FINGERPRINT_CFG = 2152; //删除指纹参数 + public static final int NET_DVR_GET_FINGERPRINT_CFG_V50 = 2183; //获取指纹参数V50 + public static final int NET_DVR_SET_FINGERPRINT_CFG_V50 = 2184; //设置指纹参数V50 + public static final int NET_DVR_DEL_FINGERPRINT_CFG_V50 = 2517; //删除指纹参数V50 + public static final int NET_DVR_GET_CARD_RIGHT_WEEK_PLAN_V50 = 2304; //获取卡权限周计划参数V50 + public static final int NET_DVR_SET_CARD_RIGHT_WEEK_PLAN_V50 = 2305; //设置卡权限周计划参数V50 + public static final int NET_DVR_GET_CARD_RIGHT_PLAN_TEMPLATE_V50 = 2322; //获取卡权限计划模板参数V50 + public static final int NET_DVR_SET_CARD_RIGHT_PLAN_TEMPLATE_V50 = 2323;//设置卡权限计划模板参数V50 + public static final int NET_DVR_SET_DOOR_STATUS_PLAN_TEMPLATE = 2107; //设置门状态计划模板参数 + public static final int NET_DVR_GET_DOOR_CFG = 2108; //获取门参数 + public static final int NET_DVR_SET_DOOR_CFG = 2109; //设置门参数 + public static final int NET_DVR_GET_DOOR_STATUS_PLAN = 2110; //获取门状态计划参数 + public static final int NET_DVR_SET_DOOR_STATUS_PLAN = 2111; //设置门状态计划参数 + public static final int NET_DVR_GET_WEEK_PLAN_CFG = 2100; //获取门状态周计划参数 + public static final int NET_DVR_SET_WEEK_PLAN_CFG = 2101; //设置门状态周计划参数 + public static final int NET_DVR_GET_EVENT_CARD_LINKAGE_CFG_V50 = 2181; //获取事件卡号联动配置参数(V50) + public static final int NET_DVR_SET_EVENT_CARD_LINKAGE_CFG_V50 = 2182; //设置事件卡号联动配置参数(V50) + public static final int NET_DVR_CAPTURE_FACE_INFO = 2510; //采集人脸信息 + public static final int NET_DVR_CAPTURE_FINGERPRINT_INFO = 2504; //采集指纹信息 + public static final int NET_DVR_GET_ACS_EVENT = 2514;//设备事件获取 + public static final int NET_DVR_GET_CARD_READER_CFG_V50 = 2505; //获取读卡器参数(V50) + public static final int NET_DVR_SET_CARD_READER_CFG_V50 = 2506; //设置读卡器参数(V50) + public static final int NET_DVR_GET_REGISTER_INFO = 2511; //登记信息获取 + public static final int NET_DVR_GET_SMSRELATIVEPARA_V50 = 2512; //获取短信相关参数 + public static final int NET_DVR_SET_SMSRELATIVEPARA_V50 = 2513; //设置短信相关参数 + public static final int NET_DVR_GET_MULTI_CARD_CFG_V50 = 2515; //获取多重卡参数V50 + public static final int NET_DVR_SET_MULTI_CARD_CFG_V50 = 2516; //设置多重卡参数V5 + public static final int NET_DVR_GET_EVENT_CARD_LINKAGE_CFG_V51 = 2518; //获取事件卡号联动配置参数(V51) + public static final int NET_DVR_SET_EVENT_CARD_LINKAGE_CFG_V51 = 2519; //设置事件卡号联动配置参数(V51) + + public static final int NET_DVR_SET_EXAM_INFO = 2530; //考试信息下发 + public static final int NET_DVR_SET_EXAMINEE_INFO = 2531; //考生信息下发 + public static final int NET_DVR_SEARCH_EXAM_COMPARE_RESULT = 2532; //考试比对结果查询 + public static final int NET_DVR_BULK_CHECK_FACE_PICTURE = 2533; //批量校验人脸图片 + public static final int NET_DVR_JSON_CONFIG = 2550; //JSON透传数据 + public static final int NET_DVR_FACE_DATA_RECORD = 2551; //添加人脸数据到人脸库 + public static final int NET_DVR_FACE_DATA_SEARCH = 2552; //查询人脸库中的人脸数据 + public static final int NET_DVR_FACE_DATA_MODIFY = 2553; //修改人脸库中的人脸数据 + public static final int NET_DVR_CAPTURE_DATA_SEARCH = 2554; //查询离线采集数据集中数据 + public static final int NET_DVR_SET_FORM_DATA = 2555; //长连接设置表单数据 + public static final int NET_DVR_GET_FORM_DATA = 2556; //长连接获取表单数据 + public static final int NET_DVR_GET_CARD = 2560; + public static final int NET_DVR_SET_CARD = 2561; + public static final int NET_DVR_GET_FACE = 2566; + public static final int NET_DVR_SET_FACE = 2567; + public static final int NET_DVR_DEL_CARD = 2562; + public static final int NET_DVR_GET_FINGERPRINT = 2563; + public static final int NET_DVR_SET_FINGERPRINT = 2564; //下发指纹 + public static final int NET_DVR_DEL_FINGERPRINT = 2565; //删除指纹 + public static final int NET_DVR_GET_ACS_WORK_STATUS_V50 = 2180; //获取门禁主机工作状态 + public static final int NET_DVR_GET_ACS_CFG = 2159; //获取门禁主机参数 + public static final int NET_DVR_SET_ACS_CFG = 2160; //设置门禁主机参数 + public static final int NET_DVR_BULK_UPLOAD_ID_BLOCKLIST = 2521; //批量上传身份证禁止名单 + + /*************************************特征识别门禁一体机1.0 end**************************************/ + public static final int NET_DVR_SET_SENSOR_CFG = 1180;//设置模拟量参数 + public static final int NET_DVR_GET_SENSOR_CFG = 1181;//获取模拟量参数 + public static final int NET_DVR_SET_ALARMIN_PARAM = 1182;//设置报警输入参数 + public static final int NET_DVR_GET_ALARMIN_PARAM = 1183; + ;//获取报警输入参数 + public static final int NET_DVR_SET_ALARMOUT_PARAM = 1184;//设置报警输出参数 + public static final int NET_DVR_GET_ALARMOUT_PARAM = 1185;//获取报警输出参数 + public static final int NET_DVR_SET_SIREN_PARAM = 1186;//设置警号参数 + public static final int NET_DVR_GET_SIREN_PARAM = 1187;//获取警号参数 + public static final int NET_DVR_SET_ALARM_RS485CFG = 1188;//设置报警主机485参数 + public static final int NET_DVR_GET_ALARM_RS485CFG = 1189;//获取报警主机485参数 + public static final int NET_DVR_GET_ALARMHOST_MAIN_STATUS = 1190;//获取报警主机主要状态 + public static final int NET_DVR_GET_ALARMHOST_OTHER_STATUS = 1191;//获取报警主机其他状态 + public static final int NET_DVR_SET_ALARMHOST_ENABLECFG = 1192;//获取报警主机使能状态 + public static final int NET_DVR_GET_ALARMHOST_ENABLECFG = 1193;//设置报警主机使能状态 + public static final int NET_DVR_SET_ALARM_CAMCFG = 1194;//设置视频综合平台报警触发CAM操作配置 + public static final int NET_DVR_GET_ALARM_CAMCFG = 1195;//设置视频综合平台报警触发CAM操作配置 + public static final int NET_DVR_SET_ALARMHOST_RS485_SLOT_CFG = 2055;// 设置报警主机485槽位参数 + public static final int NET_DVR_GET_ALARMHOST_RS485_SLOT_CFG = 2056;// 获取报警主机485槽位参数 + public static final int NET_DVR_SET_VIDEOWALLDISPLAYMODE = 1730;//设置电视墙拼接模式 + public static final int NET_DVR_GET_VIDEOWALLDISPLAYMODE = 1731;//获取电视墙拼接模式 + public static final int NET_DVR_GET_VIDEOWALLDISPLAYNO = 1732;//获取设备显示输出号 + public static final int NET_DVR_SET_VIDEOWALLDISPLAYPOSITION = 1733;//设置显示输出位置参数 + public static final int NET_DVR_GET_VIDEOWALLDISPLAYPOSITION = 1734;//获取显示输出位置参数 + public static final int NET_DVR_GET_VIDEOWALLWINDOWPOSITION = 1735;//获取电视墙窗口参数 + public static final int NET_DVR_SET_VIDEOWALLWINDOWPOSITION = 1736;//设置电视墙窗口参数 + public static final int NET_DVR_VIDEOWALLWINDOW_CLOSEALL = 1737;//电视墙关闭所有窗口 + public static final int NET_DVR_SET_VIRTUALLED = 1738;//虚拟LED设置 + public static final int NET_DVR_GET_VIRTUALLED = 1739;//虚拟LED获取 + public static final int NET_DVR_GET_IMAGE_CUT_MODE = 1740;//获取图像切割模式 + public static final int NET_DVR_SET_IMAGE_CUT_MODE = 1741;//设置图像切割模式 + public static final int NET_DVR_GET_USING_SERIALPORT = 1742;//获取当前使用串口 + public static final int NET_DVR_SET_USING_SERIALPORT = 1743;//设置当前使用串口 + public static final int NET_DVR_SCENE_CONTROL = 1744;//场景控制 + public static final int NET_DVR_GET_CURRENT_SCENE = 1745;//获取当前场景号 + public static final int NET_DVR_GET_VW_SCENE_PARAM = 1746;//获取电视墙场景模式参数 + public static final int NET_DVR_SET_VW_SCENE_PARAM = 1747;//设置电视墙场景模式参数 + public static final int NET_DVR_DISPLAY_CHANNO_CONTROL = 1748;//电视墙显示编号控制 + public static final int NET_DVR_GET_WIN_DEC_INFO = 1749;//获取窗口解码信息(批量) + public static final int NET_DVR_RESET_VIDEOWALLDISPLAYPOSITION = 1750; //解除电视墙输出接口绑定 + public static final int NET_DVR_SET_VW_AUDIO_CFG = 1752; //设置音频切换参数 + public static final int NET_DVR_GET_VW_AUDIO_CFG = 1753; //获取音频切换参数 + public static final int NET_DVR_GET_GBT28181_DECCHANINFO_CFG = 1754; //获取GBT28181协议接入设备的解码通道信息 + public static final int NET_DVR_SET_GBT28181_DECCHANINFO_CFG = 1755; //设置GBT28181协议接入设备的解码通道信息 + public static final int NET_DVR_SET_MAINBOARD_SERIAL = 1756; //设置主控板串口参数 + public static final int NET_DVR_GET_MAINBOARD_SERIAL = 1757;//获取主控板串口参数 + public static final int NET_DVR_GET_SUBBOARD_INFO = 1758; //获取子板信息 + public static final int NET_DVR_GET_SUBBOARD_EXCEPTION = 1759; //获取异常子板异常信息 + /*****************************电视墙 start****************************/ + public static final int NET_DVR_MATRIX_WALL_SET = 9001; //设置电视墙中屏幕参数 + public static final int NET_DVR_MATRIX_WALL_GET = 9002; //获取电视墙中屏幕参数 + public static final int NET_DVR_WALLWIN_GET = 9003; //电视墙中获取窗口参数 + public static final int NET_DVR_WALLWIN_SET = 9004; //电视墙中设置窗口参数 + public static final int NET_DVR_WALLWINPARAM_SET = 9005; + ; //设置电视墙窗口相关参数 + public static final int NET_DVR_WALLWINPARAM_GET = 9006; //获取电视墙窗口相关参数 + public static final int NET_DVR_WALLSCENEPARAM_GET = 9007; //设置场景模式参数 + public static final int NET_DVR_WALLSCENEPARAM_SET = 9008; //获取场景模式参数 + public static final int NET_DVR_MATRIX_GETWINSTATUS = 9009; //获取窗口解码状态 + public static final int NET_DVR_GET_WINASSOCIATEDDEVINFO = 9010; //电视墙中获取对应资源信息 + public static final int NET_DVR_WALLOUTPUT_GET = 9011; //电视墙中获取显示输出参数 + public static final int NET_DVR_WALLOUTPUT_SET = 9012; //电视墙中设置显示输出参数 + public static final int NET_DVR_GET_UNITEDMATRIXSYSTEM = 9013; //电视墙中获取对应资源 + public static final int NET_DVR_GET_WALL_CFG = 9014; //获取电视墙全局参数 + public static final int NET_DVR_SET_WALL_CFG = 9015; //设置电视墙全局参数 + public static final int NET_DVR_CLOSE_ALL_WND = 9016; //关闭所有窗口 + public static final int NET_DVR_SWITCH_WIN_TOP = 9017; //窗口置顶 + public static final int NET_DVR_SWITCH_WIN_BOTTOM = 9018; //窗口置底 + + public static final int NET_DVR_CLOSE_ALL_WND_V41 = 9019; //电视墙关闭所有窗口v41(有多个电视墙) + public static final int NET_DVR_GET_WALL_WINDOW_V41 = 9020; //获取电视墙中的窗口v41 + public static final int NET_DVR_SET_WALL_WINDOW_V41 = 9021; //设置电视墙中的窗口v41 + public static final int NET_DVR_GET_CURRENT_SCENE_V41 = 9022; //获取当前电视墙中正在使用的场景v41 + public static final int NET_DVR_GET_WALL_SCENE_PARAM_V41 = 9023; //获取当前电视墙中正在使用的场景v41 + public static final int NET_DVR_SET_WALL_SCENE_PARAM_V41 = 9024; //设置当前电视墙中正在使用的场景v41 + public static final int NET_DVR_GET_MATRIX_LOGO_CFG = 9025; //获取logo参数 + public static final int NET_DVR_SET_MATRIX_LOGO_CFG = 9026; //设置logo参数 + public static final int NET_DVR_GET_WIN_LOGO_CFG = 9027; //获取窗口logo参数 + public static final int NET_DVR_SET_WIN_LOGO_CFG = 9028; //设置窗口logo参数 + public static final int NET_DVR_DELETE_LOGO = 9029; //删除logo + public static final int NET_DVR_SET_DISPLAY_EFFECT_CFG = 9030; //设置显示输出效果参数v41 + public static final int NET_DVR_GET_DISPLAY_EFFECT_CFG = 9031; //获取显示输出效果参数v41 + public static final int NET_DVR_DEC_PLAY_REMOTE_FILE = 9032; //解码播放远程文件 + public static final int NET_DVR_DEC_PLAY_REMOTE_FILE_V50 = 9314; //解码播放远程文件V50 + public static final int NET_DVR_GET_WIN_ZOOM_STATUS = 9033; //获取窗口电子放大状态 + public static final int NET_DVR_GET_ALL_MATRIX_LOGOCFG = 9034; //获取所有logo参数 + +/*****************************电视墙 end******************************/ + + /******************* + * 查找文件和日志函数返回值 + *************************/ + public static final int NET_DVR_FILE_SUCCESS = 1000; //获得文件信息 + public static final int NET_DVR_FILE_NOFIND = 1001; //没有文件 + public static final int NET_DVR_ISFINDING = 1002;//正在查找文件 + public static final int NET_DVR_NOMOREFILE = 1003;//查找文件时没有更多的文件 + public static final int NET_DVR_FILE_EXCEPTION = 1004;//查找文件时异常 + /********************* + * 回调函数类型 begin + ************************/ + public static final int COMM_ALARM = 0x1100; //8000报警信息主动上传 + public static final int COMM_TRADEINFO = 0x1500; //ATMDVR主动上传交易信息 + public static final int COMM_ALARM_V30 = 0x4000;//9000报警信息主动上传 + public static final int COMM_ALARM_V40 = 0x4007; + public static final int COMM_ALARM_RULE = 0x1102;//异常行为检测信息上传 + public static final int COMM_ALARM_PDC = 0x1103;//客流量统计报警上传 + public static final int COMM_UPLOAD_PLATE_RESULT = 0x2800;//交通抓拍结果上传 + public static final int COMM_ITS_PLATE_RESULT = 0x3050;//交通抓拍的终端图片上传 + public static final int COMM_IPCCFG = 0x4001;//9000设备IPC接入配置改变报警信息主动上传 + public static final int COMM_ITS_PARK_VEHICLE = 0x3056;//停车场数据上传 + public static final int COMM_VEHICLE_CONTROL_ALARM = 0x3059;//车辆报警上传 + public static final int COMM_ALARM_TFS = 0x1113; //交通取证报警信息 + public static final int COMM_ALARM_TPS_V41 = 0x1114; //交通事件报警信息扩展 + public static final int COMM_ALARM_AID_V41 = 0x1115; //交通事件报警信息扩展 + public static final int COMM_UPLOAD_FACESNAP_RESULT = 0x1112; //特征识别结果上传 + public static final int COMM_SNAP_MATCH_ALARM = 0x2902; //人脸比对结果上传 + public static final int COMM_ALARM_ACS = 0x5002; //门禁主机报警信息 + public static final int COMM_ID_INFO_ALARM = 0x5200; //门禁身份证刷卡信息 + public static final int COMM_VCA_ALARM = 0x4993; //智能检测通用报警 + public static final int COMM_ISAPI_ALARM = 0x6009;//ISAPI协议报警信息 + public static final int COMM_ALARM_TPS_STATISTICS = 0x3082; //TPS统计过车数据上传 + public static final int COMM_ALARM_TPS_REAL_TIME = 0x3081; //TPS实时过车数据上传 + public static final int COMM_ALARMHOST_CID_ALARM = 0x1127; //报告报警上传 + public static final int COMM_SENSOR_VALUE_UPLOAD = 0x1120; //模拟量数据实时上传 + public static final int COMM_SENSOR_ALARM = 0x1121; //模拟量报警上传 + public static final int COMM_SWITCH_ALARM = 0x1122; //开关量报警 + public static final int COMM_ALARMHOST_EXCEPTION = 0x1123; //报警主机故障报警 + public static final int COMM_ALARMHOST_OPERATEEVENT_ALARM = 0x1124; //操作事件报警上传 + public static final int COMM_ALARMHOST_SAFETYCABINSTATE = 0x1125; //防护舱状态 + public static final int COMM_ALARMHOST_ALARMOUTSTATUS = 0x1126; //报警输出口/警号状态 + public static final int COMM_ALARMHOST_DATA_UPLOAD = 0x1129; //报警数据上传 + + public static final int COMM_UPLOAD_VIDEO_INTERCOM_EVENT = 0x1132; //可视对讲事件记录上传 + public static final int COMM_ALARM_VIDEO_INTERCOM = 0x1133; //可视对讲报警上传 + public static final int COMM_THERMOMETRY_ALARM = 0x5212; //温度报警上传 + public static final int COMM_FIREDETECTION_ALARM = 0x4991; //火点报警上传 + public static final int COMM_THERMOMETRY_DIFF_ALARM = 0x5111; //温差报警 + public static final int COMM_ALARM_SHIPSDETECTION = 0x4521; //船只检测报警 + public static final int COMM_UPLOAD_AIOP_VIDEO = 0x4021; //设备支持AI开放平台接入,上传视频检测数据 + public static final int COMM_UPLOAD_AIOP_PICTURE = 0x4022; //设备支持AI开放平台接入,上传图片检测数据 + public static final int COMM_UPLOAD_AIOP_POLLING_SNAP = 0x4023; //设备支持AI开放平台接入,上传轮巡抓图图片检测数据 对应的结构体(NET_AIOP_POLLING_PICTURE_HEAD) + public static final int COMM_UPLOAD_AIOP_POLLING_VIDEO = 0x4024; //设备支持AI开放平台接入,上传轮巡视频检测数据 对应的结构体(NET_AIOP_POLLING_VIDEO_HEAD) + public static final int COMM_IPC_AUXALARM_RESULT = 0x2820; //PIR报警、无线报警、呼救报警信息 + /************* + * 操作异常类型(消息方式, 回调方式(保留)) + ****************/ + public static final int EXCEPTION_EXCHANGE = 0x8000;//用户交互时异常 + public static final int EXCEPTION_AUDIOEXCHANGE = 0x8001;//语音对讲异常 + public static final int EXCEPTION_ALARM = 0x8002;//报警异常 + public static final int EXCEPTION_PREVIEW = 0x8003;//网络预览异常 + public static final int EXCEPTION_SERIAL = 0x8004;//透明通道异常 + public static final int EXCEPTION_RECONNECT = 0x8005; //预览时重连 + public static final int EXCEPTION_ALARMRECONNECT = 0x8006;//报警时重连 + public static final int EXCEPTION_SERIALRECONNECT = 0x8007;//透明通道重连 + public static final int EXCEPTION_PLAYBACK = 0x8010;//回放异常 + public static final int EXCEPTION_DISKFMT = 0x8011;//硬盘格式化 + /******************** + * 预览回调函数 + *********************/ + public static final int NET_DVR_SYSHEAD = 1;//系统头数据 + public static final int NET_DVR_STREAMDATA = 2;//视频流数据(包括复合流和音视频分开的视频流数据) + public static final int NET_DVR_AUDIOSTREAMDATA = 3;//音频流数据 + public static final int NET_DVR_STD_VIDEODATA = 4;//标准视频流数据 + public static final int NET_DVR_STD_AUDIODATA = 5;//标准音频流数据 + //回调预览中的状态和消息 + public static final int NET_DVR_REALPLAYEXCEPTION = 111;//预览异常 + public static final int NET_DVR_REALPLAYNETCLOSE = 112;//预览时连接断开 + public static final int NET_DVR_REALPLAY5SNODATA = 113;//预览5s没有收到数据 + public static final int NET_DVR_REALPLAYRECONNECT = 114;//预览重连 + /******************** + * 回放回调函数 + *********************/ + public static final int NET_DVR_PLAYBACKOVER = 101;//回放数据播放完毕 + public static final int NET_DVR_PLAYBACKEXCEPTION = 102;//回放异常 + public static final int NET_DVR_PLAYBACKNETCLOSE = 103;//回放时候连接断开 + public static final int NET_DVR_PLAYBACK5SNODATA = 104; //回放5s没有收到数据 + /********************* + * 回调函数类型 end + ************************/ +//设备型号(DVR类型) + /* 设备类型 */ + public static final int DVR = 1; /*对尚未定义的dvr类型返回NETRET_DVR*/ + public static final int ATMDVR = 2; /*atm dvr*/ + public static final int DVS = 3; /*DVS*/ + public static final int DEC = 4; /* 6001D */ + public static final int ENC_DEC = 5; /* 6001F */ + public static final int DVR_HC = 6; /*8000HC*/ + public static final int DVR_HT = 7; /*8000HT*/ + public static final int DVR_HF = 8; /*8000HF*/ + public static final int DVR_HS = 9; /* 8000HS DVR(no audio) */ + public static final int DVR_HTS = 10; /* 8016HTS DVR(no audio) */ + public static final int DVR_HB = 11; /* HB DVR(SATA HD) */ + public static final int DVR_HCS = 12; /* 8000HCS DVR */ + public static final int DVS_A = 13; /* 带ATA硬盘的DVS */ + public static final int DVR_HC_S = 14; /* 8000HC-S */ + public static final int DVR_HT_S = 15; /* 8000HT-S */ + public static final int DVR_HF_S = 16; /* 8000HF-S */ + public static final int DVR_HS_S = 17; /* 8000HS-S */ + public static final int ATMDVR_S = 18; /* ATM-S */ + public static final int LOWCOST_DVR = 19; /*7000H系列*/ + public static final int DEC_MAT = 20; /*多路解码器*/ + public static final int DVR_MOBILE = 21; /* mobile DVR */ + public static final int DVR_HD_S = 22; /* 8000HD-S */ + public static final int DVR_HD_SL = 23; /* 8000HD-SL */ + public static final int DVR_HC_SL = 24; /* 8000HC-SL */ + public static final int DVR_HS_ST = 25; /* 8000HS_ST */ + public static final int DVS_HW = 26; /* 6000HW */ + public static final int IPCAM = 30; /*IP 摄像机*/ + public static final int MEGA_IPCAM = 31; /*X52MF系列,752MF,852MF*/ + public static final int IPCAM_X62MF = 32; /*X62MF系列可接入9000设备,762MF,862MF*/ + public static final int IPDOME = 40; /*IP标清快球*/ + public static final int MEGA_IPDOME = 41; /*IP高清快球*/ + public static final int IPMOD = 50; /*IP 模块*/ + public static final int DS71XX_H = 71; /* DS71XXH_S */ + public static final int DS72XX_H_S = 72; /* DS72XXH_S */ + public static final int DS73XX_H_S = 73; /* DS73XXH_S */ + public static final int DS81XX_HS_S = 81; /* DS81XX_HS_S */ + public static final int DS81XX_HL_S = 82; /* DS81XX_HL_S */ + public static final int DS81XX_HC_S = 83; /* DS81XX_HC_S */ + public static final int DS81XX_HD_S = 84; /* DS81XX_HD_S */ + public static final int DS81XX_HE_S = 85; /* DS81XX_HE_S */ + public static final int DS81XX_HF_S = 86; /* DS81XX_HF_S */ + public static final int DS81XX_AH_S = 87; /* DS81XX_AH_S */ + public static final int DS81XX_AHF_S = 88; /* DS81XX_AHF_S */ + public static final int DS90XX_HF_S = 90; /*DS90XX_HF_S*/ + public static final int DS91XX_HF_S = 91; /*DS91XX_HF_S*/ + public static final int DS91XX_HD_S = 92; /*91XXHD-S(MD)*/ + + /* 操作 */ +//主类型 + public static final int MAJOR_OPERATION = 0x3; + //次类型 + public static final int MINOR_START_DVR = 0x41; /* 开机 */ + public static final int MINOR_STOP_DVR = 0x42;/* 关机 */ + public static final int MINOR_STOP_ABNORMAL = 0x43;/* 异常关机 */ + public static final int MINOR_REBOOT_DVR = 0x44; /*本地重启设备*/ + public static final int MINOR_LOCAL_LOGIN = 0x50; /* 本地登陆 */ + public static final int MINOR_LOCAL_LOGOUT = 0x51; /* 本地注销登陆 */ + public static final int MINOR_LOCAL_CFG_PARM = 0x52; /* 本地配置参数 */ + public static final int MINOR_LOCAL_PLAYBYFILE = 0x53; /* 本地按文件回放或下载 */ + public static final int MINOR_LOCAL_PLAYBYTIME = 0x54; /* 本地按时间回放或下载*/ + public static final int MINOR_LOCAL_START_REC = 0x55; /* 本地开始录像 */ + public static final int MINOR_LOCAL_STOP_REC = 0x56; /* 本地停止录像 */ + public static final int MINOR_LOCAL_PTZCTRL = 0x57; /* 本地云台控制 */ + public static final int MINOR_LOCAL_PREVIEW = 0x58;/* 本地预览 (保留不使用)*/ + public static final int MINOR_LOCAL_MODIFY_TIME = 0x59;/* 本地修改时间(保留不使用) */ + public static final int MINOR_LOCAL_UPGRADE = 0x5a;/* 本地升级 */ + public static final int MINOR_LOCAL_RECFILE_OUTPUT = 0x5b; /* 本地备份录象文件 */ + public static final int MINOR_LOCAL_FORMAT_HDD = 0x5c; /* 本地初始化硬盘 */ + public static final int MINOR_LOCAL_CFGFILE_OUTPUT = 0x5d; /* 导出本地配置文件 */ + public static final int MINOR_LOCAL_CFGFILE_INPUT = 0x5e; /* 导入本地配置文件 */ + public static final int MINOR_LOCAL_COPYFILE = 0x5f; /* 本地备份文件 */ + public static final int MINOR_LOCAL_LOCKFILE = 0x60; /* 本地锁定录像文件 */ + public static final int MINOR_LOCAL_UNLOCKFILE = 0x61; /* 本地解锁录像文件 */ + public static final int MINOR_LOCAL_DVR_ALARM = 0x62; /* 本地手动清除和触发报警*/ + public static final int MINOR_IPC_ADD = 0x63; /* 本地添加IPC */ + public static final int MINOR_IPC_DEL = 0x64; /* 本地删除IPC */ + public static final int MINOR_IPC_SET = 0x65; /* 本地设置IPC */ + public static final int MINOR_LOCAL_START_BACKUP = 0x66; /* 本地开始备份 */ + public static final int MINOR_LOCAL_STOP_BACKUP = 0x67;/* 本地停止备份*/ + public static final int MINOR_LOCAL_COPYFILE_START_TIME = 0x68;/* 本地备份开始时间*/ + public static final int MINOR_LOCAL_COPYFILE_END_TIME = 0x69; /* 本地备份结束时间*/ + public static final int MINOR_REMOTE_LOGIN = 0x70;/* 远程登录 */ + public static final int MINOR_REMOTE_LOGOUT = 0x71;/* 远程注销登陆 */ + public static final int MINOR_REMOTE_START_REC = 0x72;/* 远程开始录像 */ + public static final int MINOR_REMOTE_STOP_REC = 0x73;/* 远程停止录像 */ + public static final int MINOR_START_TRANS_CHAN = 0x74;/* 开始透明传输 */ + public static final int MINOR_STOP_TRANS_CHAN = 0x75; /* 停止透明传输 */ + public static final int MINOR_REMOTE_GET_PARM = 0x76;/* 远程获取参数 */ + public static final int MINOR_REMOTE_CFG_PARM = 0x77;/* 远程配置参数 */ + public static final int MINOR_REMOTE_GET_STATUS = 0x78;/* 远程获取状态 */ + public static final int MINOR_REMOTE_ARM = 0x79; /* 远程布防 */ + public static final int MINOR_REMOTE_DISARM = 0x7a;/* 远程撤防 */ + public static final int MINOR_REMOTE_REBOOT = 0x7b; /* 远程重启 */ + public static final int MINOR_START_VT = 0x7c;/* 开始语音对讲 */ + public static final int MINOR_STOP_VT = 0x7d;/* 停止语音对讲 */ + public static final int MINOR_REMOTE_UPGRADE = 0x7e; /* 远程升级 */ + public static final int MINOR_REMOTE_PLAYBYFILE = 0x7f; /* 远程按文件回放 */ + public static final int MINOR_REMOTE_PLAYBYTIME = 0x80; /* 远程按时间回放 */ + public static final int MINOR_REMOTE_PTZCTRL = 0x81; /* 远程云台控制 */ + public static final int MINOR_REMOTE_FORMAT_HDD = 0x82; /* 远程格式化硬盘 */ + public static final int MINOR_REMOTE_STOP = 0x83; /* 远程关机 */ + public static final int MINOR_REMOTE_LOCKFILE = 0x84;/* 远程锁定文件 */ + public static final int MINOR_REMOTE_UNLOCKFILE = 0x85;/* 远程解锁文件 */ + public static final int MINOR_REMOTE_CFGFILE_OUTPUT = 0x86; /* 远程导出配置文件 */ + public static final int MINOR_REMOTE_CFGFILE_INTPUT = 0x87; /* 远程导入配置文件 */ + public static final int MINOR_REMOTE_RECFILE_OUTPUT = 0x88; /* 远程导出录象文件 */ + public static final int MINOR_REMOTE_DVR_ALARM = 0x89; /* 远程手动清除和触发报警*/ + public static final int MINOR_REMOTE_IPC_ADD = 0x8a; /* 远程添加IPC */ + public static final int MINOR_REMOTE_IPC_DEL = 0x8b;/* 远程删除IPC */ + public static final int MINOR_REMOTE_IPC_SET = 0x8c; /* 远程设置IPC */ + public static final int MINOR_REBOOT_VCA_LIB = 0x8d; /*重启智能库*/ + + /*日志附加信息*/ +//主类型 + public static final int MAJOR_INFORMATION = 0x4; /*附加信息*/ + //次类型 + public static final int MINOR_HDD_INFO = 0xa1;/*硬盘信息*/ + public static final int MINOR_SMART_INFO = 0xa2; /*SMART信息*/ + public static final int MINOR_REC_START = 0xa3; /*开始录像*/ + public static final int MINOR_REC_STOP = 0xa4;/*停止录像*/ + public static final int MINOR_REC_OVERDUE = 0xa5;/*过期录像删除*/ + public static final int MINOR_LINK_START = 0xa6; // ivms多路解码器等连接前端设备 + public static final int MINOR_LINK_STOP = 0xa7;// ivms多路解码器等断开前端设备  + //当日志的主类型为MAJOR_OPERATION=03,次类型为MINOR_LOCAL_CFG_PARM=0x52或者MINOR_REMOTE_GET_PARM=0x76或者MINOR_REMOTE_CFG_PARM=0x77时,dwParaType:参数类型有效,其含义如下: + public static final int PARA_VIDEOOUT = 0x1; + public static final int PARA_IMAGE = 0x2; + public static final int PARA_ENCODE = 0x4; + public static final int PARA_NETWORK = 0x8; + public static final int PARA_ALARM = 0x10; + public static final int PARA_EXCEPTION = 0x20; + public static final int PARA_DECODER = 0x40; /*解码器*/ + public static final int PARA_RS232 = 0x80; + public static final int PARA_PREVIEW = 0x100; + public static final int PARA_SECURITY = 0x200; + public static final int PARA_DATETIME = 0x400; + public static final int PARA_FRAMETYPE = 0x800; /*帧格式*/ + public static final int PARA_VCA_RULE = 0x1000; //行为规则 + //SDK_V222 +//智能设备类型 + public static final int DS6001_HF_B = 60;//异常行为检测:DS6001-HF/B + public static final int DS6001_HF_P = 61;//车牌识别:DS6001-HF/P + public static final int DS6002_HF_B = 62;//双机:DS6002-HF/B + public static final int DS6101_HF_B = 63;//异常行为检测:DS6101-HF/B + public static final int IVMS_2000 = 64;//智能分析仪 + public static final int DS9000_IVS = 65;//9000系列智能DVR + public static final int DS8004_AHL_A = 66;//智能ATM, DS8004AHL-S/A + public static final int DS6101_HF_P = 67;//车牌识别:DS6101-HF/P + //能力获取命令 + public static final int VCA_DEV_ABILITY = 0x100;//设备智能分析的总能力 + public static final int VCA_CHAN_ABILITY = 0x110;//异常行为检测能力 + public static final int DEVICE_ABILITY_INFO = 0x011; //设备通用能力类型,具体能力根据发送的能力节点来区分 + public static final int NET_DVR_CHECK_USER_STATUS = 20005; //检测设备是否在线 + /**********************设备类型 end***********************/ + + /************************************************* + * 参数配置结构、参数(其中_V30为9000新增) + **************************************************/ + + ///////////////////////////////////////////////////////////////////////// + //校时结构参数 + public static class NET_DVR_TIME extends HIKSDKStructure {//校时结构参数 + public int dwYear; //年 + public int dwMonth; //月 + public int dwDay; //日 + public int dwHour; //时 + public int dwMinute; //分 + public int dwSecond; //秒 + + public String toString() { + return "NET_DVR_TIME.dwYear: " + dwYear + "\n" + "NET_DVR_TIME.dwMonth: \n" + dwMonth + "\n" + "NET_DVR_TIME.dwDay: \n" + dwDay + "\n" + "NET_DVR_TIME.dwHour: \n" + dwHour + "\n" + "NET_DVR_TIME.dwMinute: \n" + dwMinute + "\n" + "NET_DVR_TIME.dwSecond: \n" + dwSecond; + } + + //用于列表中显示 + public String toStringTime() { + return String.format("%02d/%02d/%02d%02d:%02d:%02d", dwYear, dwMonth, dwDay, dwHour, dwMinute, dwSecond); + } + + //存储文件名使用 + public String toStringTitle() { + return String.format("Time%02d%02d%02d%02d%02d%02d", dwYear, dwMonth, dwDay, dwHour, dwMinute, dwSecond); + } + } + + public static class NET_DVR_SCHEDTIME extends HIKSDKStructure { + public byte byStartHour; //开始时间 + public byte byStartMin; + public byte byStopHour; //结束时间 + public byte byStopMin; + + + } + + public static class NET_DVR_HANDLEEXCEPTION_V30 extends HIKSDKStructure { + public int dwHandleType; /*处理方式,处理方式的"或"结果*//*0x00: 无响应*//*0x01: 布防器上警告*//*0x02: 声音警告*//*0x04: 上传中心*/ /*0x08: 触发报警输出*//*0x20: 触发抓图*/ //(JPEG定制) + public byte[] byRelAlarmOut = new byte[MAX_ALARMOUT_V30]; //报警触发的输出通道,报警触发的输出,为1表示触发该输出 + + } + + //报警和异常处理结构(子结构)(多处使用) + public static class NET_DVR_HANDLEEXCEPTION extends HIKSDKStructure { + public int dwHandleType; /*处理方式,处理方式的"或"结果*//*0x00: 无响应*//*0x01: 布防器上警告*//*0x02: 声音警告*//*0x04: 上传中心*/ /*0x08: 触发报警输出*//*0x20: 触发抓图*/ //(JPEG定制) + public byte[] byRelAlarmOut = new byte[MAX_ALARMOUT]; //报警触发的输出通道,报警触发的输出,为1表示触发该输出 + + } + + //DVR设备参数 + public static class NET_DVR_DEVICECFG extends HIKSDKStructure { + public int dwSize; + public byte[] sDVRName = new byte[NAME_LEN]; //DVR名称 + public int dwDVRID; //DVR ID,用于遥控器 //V1.4(0-99), V1.5(0-255) + public int dwRecycleRecord; //是否循环录像,0:不是; 1:是 + //以下不可更改 + public byte[] sSerialNumber = new byte[SERIALNO_LEN]; //序列号 + public int dwSoftwareVersion; //软件版本号,高16位是主版本,低16位是次版本 + public int dwSoftwareBuildDate; //软件生成日期,0xYYYYMMDD + public int dwDSPSoftwareVersion; //DSP软件版本,高16位是主版本,低16位是次版本 + public int dwDSPSoftwareBuildDate; // DSP软件生成日期,0xYYYYMMDD + public int dwPanelVersion; // 前面板版本,高16位是主版本,低16位是次版本 + public int dwHardwareVersion; // 硬件版本,高16位是主版本,低16位是次版本 + public byte byAlarmInPortNum; //DVR报警输入个数 + public byte byAlarmOutPortNum; //DVR报警输出个数 + public byte byRS232Num; //DVR 232串口个数 + public byte byRS485Num; //DVR 485串口个数 + public byte byNetworkPortNum; //网络口个数 + public byte byDiskCtrlNum; //DVR 硬盘控制器个数 + public byte byDiskNum; //DVR 硬盘个数 + public byte byDVRType; //DVR类型, 1:DVR 2:ATM DVR 3:DVS ...... + public byte byChanNum; //DVR 通道个数 + public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1 + public byte byDecordChans; //DVR 解码路数 + public byte byVGANum; //VGA口的个数 + public byte byUSBNum; //USB口的个数 + public byte byAuxoutNum; //辅口的个数 + public byte byAudioNum; //语音口的个数 + public byte byIPChanNum; //最大数字通道数 + + + } + + //DVR设备参数 + public static class NET_DVR_DEVICECFG_V40 extends HIKSDKStructure { + public int dwSize; + public byte[] sDVRName = new byte[NAME_LEN]; //DVR名称 + public int dwDVRID; //DVR ID,用于遥控器 //V1.4(0-99), V1.5(0-255) + public int dwRecycleRecord; //是否循环录像,0:不是; 1:是 + //以下不可更改 + public byte[] sSerialNumber = new byte[SERIALNO_LEN]; //序列号 + public int dwSoftwareVersion; //软件版本号,高16位是主版本,低16位是次版本 + public int dwSoftwareBuildDate; //软件生成日期,0xYYYYMMDD + public int dwDSPSoftwareVersion; //DSP软件版本,高16位是主版本,低16位是次版本 + public int dwDSPSoftwareBuildDate; // DSP软件生成日期,0xYYYYMMDD + public int dwPanelVersion; // 前面板版本,高16位是主版本,低16位是次版本 + public int dwHardwareVersion; // 硬件版本,高16位是主版本,低16位是次版本 + public byte byAlarmInPortNum; //DVR报警输入个数 + public byte byAlarmOutPortNum; //DVR报警输出个数 + public byte byRS232Num; //DVR 232串口个数 + public byte byRS485Num; //DVR 485串口个数 + public byte byNetworkPortNum; //网络口个数 + public byte byDiskCtrlNum; //DVR 硬盘控制器个数 + public byte byDiskNum; //DVR 硬盘个数 + public byte byDVRType; //DVR类型, 1:DVR 2:ATM DVR 3:DVS ...... + public byte byChanNum; //DVR 通道个数 + public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1 + public byte byDecordChans; //DVR 解码路数 + public byte byVGANum; //VGA口的个数 + public byte byUSBNum; //USB口的个数 + public byte byAuxoutNum; //辅口的个数 + public byte byAudioNum; //语音口的个数 + public byte byIPChanNum; //最大数字通道数 低8位,高8位见byHighIPChanNum + public byte byZeroChanNum; //零通道编码个数 + public byte bySupport; //能力,位与结果为0表示不支持,1表示支持, + public byte byEsataUseage; //Esata的默认用途,0-默认备份,1-默认录像 + public byte byIPCPlug; //0-关闭即插即用,1-打开即插即用 + public byte byStorageMode; //0-盘组模式,1-磁盘配额, 2抽帧模式, 3-自动 + public byte bySupport1; //能力,位与结果为0表示不支持,1表示支持 + public short wDevType;//设备型号 + public byte[] byDevTypeName = new byte[DEV_TYPE_NAME_LEN];//设备型号名称 + public byte bySupport2; //能力集扩展,位与结果为0表示不支持,1表示支持 + //bySupport2 & 0x1, 表示是否支持扩展的OSD字符叠加(终端和抓拍机扩展区分) + public byte byAnalogAlarmInPortNum; //模拟报警输入个数 + public byte byStartAlarmInNo; //模拟报警输入起始号 + public byte byStartAlarmOutNo; //模拟报警输出起始号 + public byte byStartIPAlarmInNo; //IP报警输入起始号 + public byte byStartIPAlarmOutNo; //IP报警输出起始号 + public byte byHighIPChanNum; //数字通道个数,高8位 + public byte byEnableRemotePowerOn;//是否启用在设备休眠的状态下远程开机功能,0-不启用,1-启用 + public short wDevClass; //设备大类备是属于哪个产品线,0 保留,1-50 DVR,51-100 DVS,101-150 NVR,151-200 IPC,65534 其他,具体分类方法见《设备类型对应序列号和类型值.docx》 + public byte[] byRes2 = new byte[6]; //保留 + + + } + + public static class NET_DVR_IPADDR extends HIKSDKStructure { + public byte[] sIpV4 = new byte[16]; + public byte[] byRes = new byte[128]; + + public String toString() { + return "NET_DVR_IPADDR.sIpV4: " + new String(sIpV4) + "\n" + "NET_DVR_IPADDR.byRes: " + new String(byRes) + "\n"; + } + + + } + + + //网络数据结构(子结构)(9000扩展) + public static class NET_DVR_ETHERNET_V30 extends HIKSDKStructure { + public NET_DVR_IPADDR struDVRIP; + public NET_DVR_IPADDR struDVRIPMask; + public int dwNetInterface; + public short wDVRPort; + public short wMTU; + public byte[] byMACAddr = new byte[6]; + + public String toString() { + return "NET_DVR_ETHERNET_V30.struDVRIP: \n" + struDVRIP + "\n" + "NET_DVR_ETHERNET_V30.struDVRIPMask: \n" + struDVRIPMask + "\n" + "NET_DVR_ETHERNET_V30.dwNetInterface: " + dwNetInterface + "\n" + "NET_DVR_ETHERNET_V30.wDVRPort: " + wDVRPort + "\n" + "NET_DVR_ETHERNET_V30.wMTU: " + wMTU + "\n" + "NET_DVR_ETHERNET_V30.byMACAddr: " + new String(byMACAddr) + "\n"; + } + + + } + + public static class NET_DVR_ETHERNET extends HIKSDKStructure {//网络数据结构(子结构) + public byte[] sDVRIP = new byte[16]; //DVR IP地址 + public byte[] sDVRIPMask = new byte[16]; //DVR IP地址掩码 + public int dwNetInterface; //网络接口 1-10MBase-T 2-10MBase-T全双工 3-100MBase-TX 4-100M全双工 5-10M/100M自适应 + public short wDVRPort; //端口号 + public byte[] byMACAddr = new byte[MACADDR_LEN]; //服务器的物理地址 + + + } + + public static class NET_DVR_PPPOECFG extends HIKSDKStructure {//PPPoe + public int dwPPPoE; + public byte[] sPPPoEUser = new byte[32]; + public byte[] sPPPoEPassword = new byte[16]; + public NET_DVR_IPADDR struPPPoEIP; + + + } + + public static class NET_DVR_NETCFG_V30 extends HIKSDKStructure { + public int dwSize; + public NET_DVR_ETHERNET_V30[] struEtherNet = new NET_DVR_ETHERNET_V30[2]; + public NET_DVR_IPADDR[] struRes1 = new NET_DVR_IPADDR[2]; + public NET_DVR_IPADDR struAlarmHostIpAddr; + public short[] wRes2 = new short[2]; + public short wAlarmHostIpPort; + public byte byUseDhcp; + public byte byRes3; + public NET_DVR_IPADDR struDnsServer1IpAddr; + public NET_DVR_IPADDR struDnsServer2IpAddr; + public byte[] byIpResolver = new byte[64]; + public short wIpResolverPort; + public short wHttpPortNo; + public NET_DVR_IPADDR struMulticastIpAddr; + public NET_DVR_IPADDR struGatewayIpAddr; + public NET_DVR_PPPOECFG struPPPoE; + public byte[] byRes = new byte[64]; + + public String toString() { + return "NET_DVR_NETCFG_V30.dwSize: " + dwSize + "\n" + "NET_DVR_NETCFG_V30.struEtherNet[0]: \n" + struEtherNet[0] + "\n" + "NET_DVR_NETCFG_V30.struAlarmHostIpAddr: \n" + struAlarmHostIpAddr + "\n" + "NET_DVR_NETCFG_V30.wAlarmHostIpPort: " + wAlarmHostIpPort + "\n" + "NET_DVR_NETCFG_V30.wHttpPortNo: " + wHttpPortNo + "\n" + "NET_DVR_NETCFG_V30.struGatewayIpAddr: \n" + struGatewayIpAddr + "\n"; + } + + + } + + + public static class NET_DVR_NETCFG extends HIKSDKStructure {//网络配置结构 + public int dwSize; + public NET_DVR_ETHERNET[] struEtherNet = new NET_DVR_ETHERNET[MAX_ETHERNET]; /* 以太网口 */ + public byte[] sManageHostIP = new byte[16]; //远程管理主机地址 + public short wManageHostPort; //远程管理主机端口号 + public byte[] sIPServerIP = new byte[16]; //IPServer服务器地址 + public byte[] sMultiCastIP = new byte[16]; //多播组地址 + public byte[] sGatewayIP = new byte[16]; //网关地址 + public byte[] sNFSIP = new byte[16]; //NFS主机IP地址 + public byte[] sNFSDirectory = new byte[PATHNAME_LEN];//NFS目录 + public int dwPPPOE; //0-不启用,1-启用 + public byte[] sPPPoEUser = new byte[NAME_LEN]; //PPPoE用户名 + public byte[] sPPPoEPassword = new byte[PASSWD_LEN];// PPPoE密码 + public byte[] sPPPoEIP = new byte[16]; //PPPoE IP地址(只读) + + + } + + //通道图象结构 + public static class NET_DVR_SCHEDTIMEWEEK extends HIKSDKStructure { + public NET_DVR_SCHEDTIME[] struAlarmTime = new NET_DVR_SCHEDTIME[8]; + + + } + + public static class byte96 extends HIKSDKStructure { + public byte[] byMotionScope = new byte[96]; + + + } + // 云台守望 / 停车动作 + public static final int NET_DVR_GET_PTZ_PARKACTION_CFG = 3314; + public static final int NET_DVR_SET_PTZ_PARKACTION_CFG = 3315; + + //云台守望结构体 + public static class NET_DVR_PTZ_PARKACTION_CFG extends HIKSDKStructure { + public int dwSize; + public byte byEnable; // 需要 + public byte byOneTouchSwitch; + public byte[] byRes1 = new byte[2]; + public int dwParkTime; // 等待时间 单位秒 需要 + public short wActionType; + public short wID; + public byte[] byRes = new byte[128]; + @Override + protected List getFieldOrder() { + return Arrays.asList( + "dwSize", + "byEnable", + "byOneTouchSwitch", + "byRes1", + "dwParkTime", + "wActionType", + "wID", + "byRes" + ); + } + } + public static class NET_DVR_MOTION_V30 extends HIKSDKStructure {//移动侦测(子结构)(9000扩展) + public byte96[] byMotionScope = new byte96[64]; /*侦测区域,0-96位,表示64行,共有96*64个小宏块,为1表示是移动侦测区域,0-表示不是*/ + public byte byMotionSensitive; /*移动侦测灵敏度, 0 - 5,越高越灵敏,oxff关闭*/ + public byte byEnableHandleMotion; /* 是否处理移动侦测 0-否 1-是*/ + public byte byPrecision; /* 移动侦测算法的进度: 0--16*16, 1--32*32, 2--64*64 ... */ + public byte reservedData; + public NET_DVR_HANDLEEXCEPTION_V30 struMotionHandleType; /* 处理方式 */ + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS]; /*布防时间*/ + public byte[] byRelRecordChan = new byte[64]; /* 报警触发的录象通道*/ + + + } + + public static class NET_DVR_MOTION extends HIKSDKStructure {//移动侦测(子结构) + public byte[] byMotionScope = new byte[18 * 22]; /*侦测区域,共有22*18个小宏块,为1表示改宏块是移动侦测区域,0-表示不是*/ + public byte byMotionSensitive; /*移动侦测灵敏度, 0 - 5,越高越灵敏,0xff关闭*/ + public byte byEnableHandleMotion; /* 是否处理移动侦测 */ + public byte[] reservedData = new byte[2]; + public NET_DVR_HANDLEEXCEPTION strMotionHandleType; /* 处理方式 */ + public byte[] byRelRecordChan = new byte[MAX_CHANNUM]; //报警触发的录象通道,为1表示触发该通道 + + + } + + public static class NET_DVR_HIDEALARM_V30 extends HIKSDKStructure {//遮挡报警 + public int dwEnableHideAlarm; /* 是否启动遮挡报警 ,0-否,1-低灵敏度 2-中灵敏度 3-高灵敏度*/ + public short wHideAlarmAreaTopLeftX; /* 遮挡区域的x坐标 */ + public short wHideAlarmAreaTopLeftY; /* 遮挡区域的y坐标 */ + public short wHideAlarmAreaWidth; /* 遮挡区域的宽 */ + public short wHideAlarmAreaHeight; /*遮挡区域的高*/ + public NET_DVR_HANDLEEXCEPTION_V30 strHideAlarmHandleType; /* 处理方式 */ + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS];//布防时间 + + + } + + public static class NET_DVR_HIDEALARM extends HIKSDKStructure {//遮挡报警(子结构) 区域大小704*576 + public int dwEnableHideAlarm; /* 是否启动遮挡报警 ,0-否,1-低灵敏度 2-中灵敏度 3-高灵敏度*/ + public short wHideAlarmAreaTopLeftX; /* 遮挡区域的x坐标 */ + public short wHideAlarmAreaTopLeftY; /* 遮挡区域的y坐标 */ + public short wHideAlarmAreaWidth; /* 遮挡区域的宽 */ + public short wHideAlarmAreaHeight; /*遮挡区域的高*/ + public NET_DVR_HANDLEEXCEPTION strHideAlarmHandleType; /* 处理方式 */ + + + } + + public static class NET_DVR_VILOST_V30 extends HIKSDKStructure { //信号丢失报警(子结构)(9000扩展) + public byte byEnableHandleVILost; /* 是否处理信号丢失报警 */ + public NET_DVR_HANDLEEXCEPTION_V30 strVILostHandleType; /* 处理方式 */ + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS];//布防时间 + + } + + public static class NET_DVR_VILOST extends HIKSDKStructure { //信号丢失报警(子结构) + public byte byEnableHandleVILost; /* 是否处理信号丢失报警 */ + public NET_DVR_HANDLEEXCEPTION strVILostHandleType; /* 处理方式 */ + + } + + public static class NET_DVR_SHELTER extends HIKSDKStructure { //遮挡区域(子结构) + public short wHideAreaTopLeftX; /* 遮挡区域的x坐标 */ + public short wHideAreaTopLeftY; /* 遮挡区域的y坐标 */ + public short wHideAreaWidth; /* 遮挡区域的宽 */ + public short wHideAreaHeight; /* 遮挡区域的高*/ + + + } + + public static class NET_DVR_COLOR extends HIKSDKStructure { + public byte byBrightness; /*亮度,0-255*/ + public byte byContrast; /*对比度,0-255*/ + public byte bySaturation; /*饱和度,0-255*/ + public byte byHue; /*色调,0-255*/ + + + } + + public static class NET_DVR_VICOLOR extends HIKSDKStructure { + public NET_DVR_COLOR[] struColor = new NET_DVR_COLOR[MAX_TIMESEGMENT_V30];/*图象参数(第一个有效,其他三个保留)*/ + public NET_DVR_SCHEDTIME[] struHandleTime = new NET_DVR_SCHEDTIME[MAX_TIMESEGMENT_V30];/*处理时间段(保留)*/ + + + } + + //信号丢失 + public static class NET_DVR_VILOST_V40 extends HIKSDKStructure { + public int dwEnableVILostAlarm; /* 是否启动信号丢失报警 ,0-否,1-是*/ + /* 信号丢失触发报警输出 */ + public int dwHandleType; //异常处理,异常处理方式的"或"结果 + /*0x00: 无响应*/ + /*0x01: 布防器上警告*/ + /*0x02: 声音警告*/ + /*0x04: 上传中心*/ + /*0x08: 触发报警输出*/ + /*0x10: 触发JPRG抓图并上传Email*/ + /*0x20: 无线声光报警器联动*/ + /*0x40: 联动电子地图(目前只有PCNVR支持)*/ + /*0x200: 抓图并上传FTP*/ + /*0x1000:抓图上传到云*/ + public int dwMaxRelAlarmOutChanNum; //触发的报警输出通道数(只读)最大支持数量 + public int[] dwRelAlarmOut = new int[MAX_ALARMOUT_V40]; /*触发报警输出号,按值表示,采用紧凑型排列,从下标0 - dwRelAlarmOut -1有效,如果中间遇到0xffffffff,则后续无效*/ + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS]; /*布防时间*/ + public byte byVILostAlarmThreshold; /*信号丢失报警阈值,当值低于阈值,认为信号丢失,取值0-99*/ + public byte[] byRes = new byte[63]; //保留 + + + } + + public static class NET_DVR_DNMODE extends HIKSDKStructure { + public byte byObjectSize;//占比参数(0~100) + public byte byMotionSensitive; /*移动侦测灵敏度, 0 - 5,越高越灵敏,0xff关闭*/ + public byte[] byRes = new byte[6]; + + + } + + public static class NET_DVR_MOTION_MULTI_AREAPARAM extends HIKSDKStructure { + public byte byAreaNo;//区域编号(IPC- 1~8) + public byte[] byRes = new byte[3]; + public NET_VCA_RECT struRect = new NET_VCA_RECT();//单个区域的坐标信息(矩形) size = 16; + public NET_DVR_DNMODE struDayNightDisable = new NET_DVR_DNMODE();//关闭模式 + public NET_DVR_DNMODE struDayModeParam = new NET_DVR_DNMODE();//白天模式 + public NET_DVR_DNMODE struNightModeParam = new NET_DVR_DNMODE();//夜晚模式 + public byte[] byRes1 = new byte[8]; + + + } + + public static final int MAX_MULTI_AREA_NUM = 24; + + public static class NET_DVR_MOTION_MULTI_AREA extends HIKSDKStructure { + public byte byDayNightCtrl;//日夜控制 0~关闭,1~自动切换,2~定时切换(默认关闭) + public byte byAllMotionSensitive; /*移动侦测灵敏度, 0 - 5,越高越灵敏,0xff关闭,全部区域的灵敏度范围*/ + public byte[] byRes = new byte[2];// + public NET_DVR_SCHEDULE_DAYTIME struScheduleTime = new NET_DVR_SCHEDULE_DAYTIME();//切换时间 16 + public NET_DVR_MOTION_MULTI_AREAPARAM[] struMotionMultiAreaParam = new NET_DVR_MOTION_MULTI_AREAPARAM[MAX_MULTI_AREA_NUM];//最大支持24个区域 + public byte[] byRes1 = new byte[60]; + + + } + + public static class NET_DVR_MOTION_SINGLE_AREA extends HIKSDKStructure { + public byte[] byMotionScope = new byte[64 * 96]; /*侦测区域,0-96位,表示64行,共有96*64个小宏块,目前有效的是22*18,为1表示是移动侦测区域,0-表示不是*/ + public byte byMotionSensitive; /*移动侦测灵敏度, 0 - 5,越高越灵敏,0xff关闭*/ + public byte[] byRes = new byte[3]; + + + } + + public static class NET_DVR_MOTION_MODE_PARAM extends HIKSDKStructure { + public NET_DVR_MOTION_SINGLE_AREA struMotionSingleArea = new NET_DVR_MOTION_SINGLE_AREA(); //普通模式下的单区域设 + public NET_DVR_MOTION_MULTI_AREA struMotionMultiArea = new NET_DVR_MOTION_MULTI_AREA(); //专家模式下的多区域设置 + + + } + + public static class NET_DVR_MOTION_V40 extends HIKSDKStructure { + public NET_DVR_MOTION_MODE_PARAM struMotionMode = new NET_DVR_MOTION_MODE_PARAM(); //(5.1.0新增) + public byte byEnableHandleMotion; /* 是否处理移动侦测 0-否 1-是*/ + public byte byEnableDisplay; /*启用移动侦测高亮显示,0-否,1-是*/ + public byte byConfigurationMode; //0~普通,1~专家(5.1.0新增) + public byte byKeyingEnable; //启用键控移动侦测 0-不启用,1-启用 + /* 异常处理方式 */ + public int dwHandleType; //异常处理,异常处理方式的"或"结果 + /*0x00: 无响应*/ + /*0x01: 布防器上警告*/ + /*0x02: 声音警告*/ + /*0x04: 上传中心*/ + /*0x08: 触发报警输出*/ + /*0x10: 触发JPRG抓图并上传Email*/ + /*0x20: 无线声光报警器联动*/ + /*0x40: 联动电子地图(目前只有PCNVR支持)*/ + /*0x200: 抓图并上传FTP*/ + /*0x1000: 抓图上传到云*/ + public int dwMaxRelAlarmOutChanNum; //触发的报警输出通道数(只读)最大支持数量 + public int[] dwRelAlarmOut = new int[MAX_ALARMOUT_V40]; //实际触发的报警输出号,按值表示,采用紧凑型排列,从下标0 - dwRelAlarmOut -1有效,如果中间遇到0xffffffff,则后续无效 + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS]; /*布防时间*/ + /*触发的录像通道*/ + public int dwMaxRecordChanNum; //设备支持的最大关联录像通道数-只读 + public int[] dwRelRecordChan = new int[MAX_CHANNUM_V40]; /* 实际触发录像通道,按值表示,采用紧凑型排列,从下标0 - dwRelRecordChan -1有效,如果中间遇到0xffffffff,则后续无效*/ + public byte byDiscardFalseAlarm; //启用去误报 0-无效,1-不启用,2-启用 + public byte[] byRes = new byte[127]; //保留字节 + + + } + + public static class NET_DVR_RGB_COLOR extends HIKSDKStructure { + public byte byRed; //RGB颜色三分量中的红色 + public byte byGreen; //RGB颜色三分量中的绿色 + public byte byBlue; //RGB颜色三分量中的蓝色 + public byte byRes; //保留 + + + } + + public static class NET_DVR_HIDEALARM_V40 extends HIKSDKStructure { + public int dwEnableHideAlarm; /* 是否启动遮挡报警,0-否,1-低灵敏度,2-中灵敏度,3-高灵敏度*/ + public short wHideAlarmAreaTopLeftX; /* 遮挡区域的x坐标 */ + public short wHideAlarmAreaTopLeftY; /* 遮挡区域的y坐标 */ + public short wHideAlarmAreaWidth; /* 遮挡区域的宽 */ + public short wHideAlarmAreaHeight; /*遮挡区域的高*/ + /* 信号丢失触发报警输出 */ + public int dwHandleType; //异常处理,异常处理方式的"或"结果 + /*0x00: 无响应*/ + /*0x01: 布防器上警告*/ + /*0x02: 声音警告*/ + /*0x04: 上传中心*/ + /*0x08: 触发报警输出*/ + /*0x10: 触发JPRG抓图并上传Email*/ + /*0x20: 无线声光报警器联动*/ + /*0x40: 联动电子地图(目前只有PCNVR支持)*/ + /*0x200: 抓图并上传FTP*/ + /*0x1000:抓图上传到云*/ + public int dwMaxRelAlarmOutChanNum; //触发的报警输出通道数(只读)最大支持数量 + public int[] dwRelAlarmOut = new int[MAX_ALARMOUT_V40]; /*触发报警输出号,按值表示,采用紧凑型排列,从下标0 - dwRelAlarmOut -1有效,如果中间遇到0xffffffff,则后续无效*/ + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS]; /*布防时间*/ + public byte[] byRes = new byte[64]; //保留 + + + }//遮挡报警 + + public static class NET_DVR_PICCFG_V40 extends HIKSDKStructure { + public int dwSize; + public byte[] sChanName = new byte[NAME_LEN]; + public int dwVideoFormat; /* 只读 视频制式 1-NTSC 2-PAL */ + public NET_DVR_VICOLOR struViColor = new NET_DVR_VICOLOR();// 图像参数按时间段设置 + //显示通道名 + public int dwShowChanName; // 预览的图象上是否显示通道名称,0-不显示,1-显示 + public short wShowNameTopLeftX; /* 通道名称显示位置的x坐标 */ + public short wShowNameTopLeftY; /* 通道名称显示位置的y坐标 */ + //隐私遮挡 + public int dwEnableHide; /* 是否启动遮挡 ,0-否,1-是*/ + public NET_DVR_SHELTER[] struShelter = new NET_DVR_SHELTER[MAX_SHELTERNUM]; + //OSD + public int dwShowOsd;// 预览的图象上是否显示OSD,0-不显示,1-显示 + public short wOSDTopLeftX; /* OSD的x坐标 */ + public short wOSDTopLeftY; /* OSD的y坐标 */ + public byte byOSDType; /* OSD类型(主要是年月日格式) */ + /* 0: XXXX-XX-XX 年月日 */ + /* 1: XX-XX-XXXX 月日年 */ + /* 2: XXXX年XX月XX日 */ + /* 3: XX月XX日XXXX年 */ + /* 4: XX-XX-XXXX 日月年*/ + /* 5: XX日XX月XXXX年 */ + /*6: xx/xx/xxxx(月/日/年) */ + /*7: xxxx/xx/xx(年/月/日) */ + /*8: xx/xx/xxxx(日/月/年)*/ + public byte byDispWeek; /* 是否显示星期 */ + public byte byOSDAttrib; /* OSD属性:透明,闪烁 */ + /* 0: 不显示OSD */ + /* 1: 透明,闪烁 */ + /* 2: 透明,不闪烁 */ + /* 3: 不透明,闪烁 */ + /* 4: 不透明,不闪烁 */ + public byte byHourOSDType; /* OSD小时制:0-24小时制,1-12小时制 */ + public byte byFontSize; //16*16(中)/8*16(英),1-32*32(中)/16*32(英),2-64*64(中)/32*64(英) 3-48*48(中)/24*48(英) 4-24*24(中)/12*24(英) 5-96*96(中)/48*96(英) 6-128*128(中)/64*128(英) 7-80*80(中)/40*80(英) 8-112*112(中)/56*112(英) 0xff-自适应(adaptive) + public byte byOSDColorType; //0-默认(黑白);1-自定义 + public byte byAlignment;//对齐方式 0-自适应,1-右对齐, 2-左对齐,3-国标模式,4-全部右对齐(包含叠加字符、时间以及标题等所有OSD字符),5-全部左对齐(包含叠加字符、时间以及标题等所有OSD字符) + public byte byOSDMilliSecondEnable;//视频叠加时间支持毫秒;0~不叠加, 1-叠加 + public NET_DVR_VILOST_V40 struVILost = new NET_DVR_VILOST_V40(); //视频信号丢失报警(支持组) + public NET_DVR_VILOST_V40 struAULost = new NET_DVR_VILOST_V40(); /*音频信号丢失报警(支持组)*/ + public NET_DVR_MOTION_V40 struMotion = new NET_DVR_MOTION_V40(); //移动侦测报警(支持组) + public NET_DVR_HIDEALARM_V40 struHideAlarm = new NET_DVR_HIDEALARM_V40(); //遮挡报警(支持组) + public NET_DVR_RGB_COLOR struOsdColor = new NET_DVR_RGB_COLOR();//OSD颜色 + public int dwBoundary; //边界值,左对齐,右对齐以及国标模式的边界值,0-表示默认值,单位:像素;在国标模式下,单位修改为字符个数(范围是,0,1,2) + public NET_DVR_RGB_COLOR struOsdBkColor = new NET_DVR_RGB_COLOR(); //自定义OSD背景色 + public byte byOSDBkColorMode; //OSD背景色模式,0-默认,1-自定义OSD背景色 + public byte byUpDownBoundary; //上下最小边界值选项,单位为字符个数(范围是,0,1,2),国标模式下无效。byAlignment=3该字段无效,通过dwBoundary进行边界配置,.byAlignment不等于3的情况下, byUpDownBoundary/byLeftRightBoundary配置成功后,dwBoundary值将不生效 + public byte byLeftRightBoundary; //左右最小边界值选项,单位为字符个数(范围是,0,1,2), 国标模式下无效。byAlignment=3该字段无效,通过dwBoundary进行边界配置,.byAlignment不等于3的情况下, byUpDownBoundary/byLeftRightBoundary配置成功后,dwBoundary值将不生效 + public byte[] byRes = new byte[113]; + + + } + + public static class NET_DVR_PICCFG_V30 extends HIKSDKStructure { + public int dwSize; + public byte[] sChanName = new byte[NAME_LEN]; + public int dwVideoFormat; /* 只读 视频制式 1-NTSC 2-PAL*/ + public NET_DVR_VICOLOR struViColor; // 图像参数按时间段设置 + public int dwShowChanName; // 预览的图象上是否显示通道名称,0-不显示,1-显示 区域大小704*576 + public short wShowNameTopLeftX; /* 通道名称显示位置的x坐标 */ + public short wShowNameTopLeftY; /* 通道名称显示位置的y坐标 */ + public NET_DVR_VILOST_V30 struVILost; //视频信号丢失报警 + public NET_DVR_VILOST_V30 struAULost; /*音频信号丢失报警(保留)*/ + public NET_DVR_MOTION_V30 struMotion; //移动侦测 + public NET_DVR_HIDEALARM_V30 struHideAlarm;//遮挡报警 + public int dwEnableHide; /* 是否启动遮盖(区域大小704*576) ,0-否,1-是*/ + public NET_DVR_SHELTER[] struShelter = new NET_DVR_SHELTER[4]; + public int dwShowOsd; //预览的图象上是否显示OSD,0-不显示,1-显示 区域大小704*576 + public short wOSDTopLeftX; /* OSD的x坐标 */ + public short wOSDTopLeftY; /* OSD的y坐标 */ + public byte byOSDType; /* OSD类型(主要是年月日格式) */ + public byte byDispWeek; /* 是否显示星期 */ + public byte byOSDAttrib; /* OSD属性:透明,闪烁 */ + public byte byHourOSDType; /* OSD小时制:0-24小时制,1-12小时制 */ + public byte[] byRes = new byte[64]; + + + } + + public static class NET_DVR_PICCFG_EX extends HIKSDKStructure {//通道图象结构SDK_V14扩展 + public int dwSize; + public byte[] sChanName = new byte[NAME_LEN]; + public int dwVideoFormat; /* 只读 视频制式 1-NTSC 2-PAL*/ + public byte byBrightness; /*亮度,0-255*/ + public byte byContrast; /*对比度,0-255*/ + public byte bySaturation; /*饱和度,0-255 */ + public byte byHue; /*色调,0-255*/ + //显示通道名 + public int dwShowChanName; // 预览的图象上是否显示通道名称,0-不显示,1-显示 区域大小704*576 + public short wShowNameTopLeftX; /* 通道名称显示位置的x坐标 */ + public short wShowNameTopLeftY; /* 通道名称显示位置的y坐标 */ + //信号丢失报警 + public NET_DVR_VILOST struVILost; + //移动侦测 + public NET_DVR_MOTION struMotion; + //遮挡报警 + public NET_DVR_HIDEALARM struHideAlarm; + //遮挡 区域大小704*576 + public int dwEnableHide; /* 是否启动遮挡 ,0-否,1-是*/ + public NET_DVR_SHELTER[] struShelter = new NET_DVR_SHELTER[MAX_SHELTERNUM]; + //OSD + public int dwShowOsd;// 预览的图象上是否显示OSD,0-不显示,1-显示 区域大小704*576 + public short wOSDTopLeftX; /* OSD的x坐标 */ + public short wOSDTopLeftY; /* OSD的y坐标 */ + public byte byOSDType; /* OSD类型(主要是年月日格式) */ + /* 0: XXXX-XX-XX 年月日 */ + /* 1: XX-XX-XXXX 月日年 */ + /* 2: XXXX年XX月XX日 */ + /* 3: XX月XX日XXXX年 */ + /* 4: XX-XX-XXXX 日月年*/ + /* 5: XX日XX月XXXX年 */ + public byte byDispWeek; /* 是否显示星期 */ + public byte byOSDAttrib; /* OSD属性:透明,闪烁 */ + /* 0: 不显示OSD */ + /* 1: 透明,闪烁 */ + /* 2: 透明,不闪烁 */ + /* 3: 闪烁,不透明 */ + /* 4: 不透明,不闪烁 */ + public byte byHourOsdType; //小时制:0表示24小时制,1-12小时制或am/pm + + + } + + + public static class NET_DVR_PICCFG extends HIKSDKStructure { //通道图象结构(SDK_V13及之前版本) + public int dwSize; + public byte[] sChanName = new byte[NAME_LEN]; + public int dwVideoFormat; /* 只读 视频制式 1-NTSC 2-PAL*/ + public byte byBrightness; /*亮度,0-255*/ + public byte byContrast; /*对比度,0-255*/ + public byte bySaturation; /*饱和度,0-255 */ + public byte byHue; /*色调,0-255*/ + //显示通道名 + public int dwShowChanName; // 预览的图象上是否显示通道名称,0-不显示,1-显示 区域大小704*576 + public short wShowNameTopLeftX; /* 通道名称显示位置的x坐标 */ + public short wShowNameTopLeftY; /* 通道名称显示位置的y坐标 */ + //信号丢失报警 + public NET_DVR_VILOST struVILost; + //移动侦测 + public NET_DVR_MOTION struMotion; + //遮挡报警 + public NET_DVR_HIDEALARM struHideAlarm; + //遮挡 区域大小704*576 + public int dwEnableHide; /* 是否启动遮挡 ,0-否,1-是*/ + public short wHideAreaTopLeftX; /* 遮挡区域的x坐标 */ + public short wHideAreaTopLeftY; /* 遮挡区域的y坐标 */ + public short wHideAreaWidth; /* 遮挡区域的宽 */ + public short wHideAreaHeight; /*遮挡区域的高*/ + //OSD + public int dwShowOsd;// 预览的图象上是否显示OSD,0-不显示,1-显示 区域大小704*576 + public short wOSDTopLeftX; /* OSD的x坐标 */ + public short wOSDTopLeftY; /* OSD的y坐标 */ + public byte byOSDType; /* OSD类型(主要是年月日格式) */ + /* 0: XXXX-XX-XX 年月日 */ + /* 1: XX-XX-XXXX 月日年 */ + /* 2: XXXX年XX月XX日 */ + /* 3: XX月XX日XXXX年 */ + /* 4: XX-XX-XXXX 日月年*/ + /* 5: XX日XX月XXXX年 */ + byte byDispWeek; /* 是否显示星期 */ + byte byOSDAttrib; /* OSD属性:透明,闪烁 */ + /* 0: 不显示OSD */ + /* 1: 透明,闪烁 */ + /* 2: 透明,不闪烁 */ + /* 3: 闪烁,不透明 */ + /* 4: 不透明,不闪烁 */ + public byte reservedData2; + + + } + + public static class NET_DVR_MULTI_STREAM_COMPRESSIONCFG_COND extends HIKSDKStructure { + public int dwSize; + public NET_DVR_STREAM_INFO struStreamInfo = new NET_DVR_STREAM_INFO(); + public int dwStreamType; + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_MULTI_STREAM_COMPRESSIONCFG extends HIKSDKStructure { + public int dwSize; + public int dwStreamType; + public NET_DVR_COMPRESSION_INFO_V30 struStreamPara = new NET_DVR_COMPRESSION_INFO_V30(); + public byte[] byRes = new byte[80]; + } + + //码流压缩参数(子结构)(9000扩展) + public static class NET_DVR_COMPRESSION_INFO_V30 extends HIKSDKStructure { + public byte byStreamType; //码流类型 0-视频流, 1-复合流 + public byte byResolution; //分辨率0-DCIF 1-CIF, 2-QCIF, 3-4CIF, 4-2CIF 5(保留)16-VGA(640*480) 17-UXGA(1600*1200) 18-SVGA (800*600)19-HD720p(1280*720)20-XVGA 21-HD900p + public byte byBitrateType; //码率类型 0:定码率,1:变码率 + public byte byPicQuality; //图象质量 0-最好 1-次好 2-较好 3-一般 4-较差 5-差 + public int dwVideoBitrate; //视频码率 0-保留 1-16K 2-32K 3-48k 4-64K 5-80K 6-96K 7-128K 8-160k 9-192K 10-224K 11-256K 12-320K 13-384K 14-448K 15-512K 16-640K 17-768K 18-896K 19-1024K 20-1280K 21-1536K 22-1792K 23-2048最高位(31位)置成1表示是自定义码流, 0-30位表示码流值。 + public int dwVideoFrameRate; //帧率 0-全部; 1-1/16; 2-1/8; 3-1/4; 4-1/2; 5-1; 6-2; 7-4; 8-6; 9-8; 10-10; 11-12; 12-16; 13-20; V2.0版本中新加14-15; 15-18; 16-22; + public short wIntervalFrameI; //I帧间隔 + public byte byIntervalBPFrame;//0-BBP帧; 1-BP帧; 2-单P帧 + public byte byENumber; //E帧数量(保留) + public byte byVideoEncType;//视频编码类型 0 hik264;1标准h264; 2标准mpeg4; + public byte byAudioEncType;//音频编码类型 0 G722 + public byte[] byres = new byte[10]; + + + } + + //通道压缩参数(9000扩展) + public static class NET_DVR_COMPRESSIONCFG_V30 extends HIKSDKStructure { + public int dwSize; + public NET_DVR_COMPRESSION_INFO_V30 struNormHighRecordPara; //录像 对应8000的普通 + public NET_DVR_COMPRESSION_INFO_V30 struRes; //保留 String[28]; + public NET_DVR_COMPRESSION_INFO_V30 struEventRecordPara; //事件触发压缩参数 + public NET_DVR_COMPRESSION_INFO_V30 struNetPara; //网传(子码流) + + + } + + + public static class NET_DVR_COMPRESSION_INFO extends HIKSDKStructure {//码流压缩参数(子结构) + public byte byStreamType; //码流类型0-视频流,1-复合流,表示压缩参数时最高位表示是否启用压缩参数 + public byte byResolution; //分辨率0-DCIF 1-CIF, 2-QCIF, 3-4CIF, 4-2CIF, 5-2QCIF(352X144)(车载专用) + public byte byBitrateType; //码率类型0:变码率,1:定码率 + public byte byPicQuality; //图象质量 0-最好 1-次好 2-较好 3-一般 4-较差 5-差 + public int dwVideoBitrate; //视频码率 0-保留 1-16K(保留) 2-32K 3-48k 4-64K 5-80K 6-96K 7-128K 8-160k 9-192K 10-224K 11-256K 12-320K + // 13-384K 14-448K 15-512K 16-640K 17-768K 18-896K 19-1024K 20-1280K 21-1536K 22-1792K 23-2048K + //最高位(31位)置成1表示是自定义码流, 0-30位表示码流值(MIN-32K MAX-8192K)。 + public int dwVideoFrameRate; //帧率 0-全部; 1-1/16; 2-1/8; 3-1/4; 4-1/2; 5-1; 6-2; 7-4; 8-6; 9-8; 10-10; 11-12; 12-16; 13-20; + + + } + + public static class NET_DVR_COMPRESSIONCFG extends HIKSDKStructure {//通道压缩参数 + public int dwSize; + public NET_DVR_COMPRESSION_INFO struRecordPara; //录像/事件触发录像 + public NET_DVR_COMPRESSION_INFO struNetPara; //网传/保留 + + + } + + + public static class NET_DVR_COMPRESSION_INFO_EX extends HIKSDKStructure {//码流压缩参数(子结构)(扩展) 增加I帧间隔 + public byte byStreamType; //码流类型0-视频流, 1-复合流 + public byte byResolution; //分辨率0-DCIF 1-CIF, 2-QCIF, 3-4CIF, 4-2CIF, 5-2QCIF(352X144)(车载专用) + public byte byBitrateType; //码率类型0:变码率,1:定码率 + public byte byPicQuality; //图象质量 0-最好 1-次好 2-较好 3-一般 4-较差 5-差 + public int dwVideoBitrate; //视频码率 0-保留 1-16K(保留) 2-32K 3-48k 4-64K 5-80K 6-96K 7-128K 8-160k 9-192K 10-224K 11-256K 12-320K + // 13-384K 14-448K 15-512K 16-640K 17-768K 18-896K 19-1024K 20-1280K 21-1536K 22-1792K 23-2048K + //最高位(31位)置成1表示是自定义码流, 0-30位表示码流值(MIN-32K MAX-8192K)。 + public int dwVideoFrameRate; //帧率 0-全部; 1-1/16; 2-1/8; 3-1/4; 4-1/2; 5-1; 6-2; 7-4; 8-6; 9-8; 10-10; 11-12; 12-16; 13-20, //V2.0增加14-15, 15-18, 16-22; + public short wIntervalFrameI; //I帧间隔 + //2006-08-11 增加单P帧的配置接口,可以改善实时流延时问题 + public byte byIntervalBPFrame;//0-BBP帧; 1-BP帧; 2-单P帧 + public byte byENumber;//E帧数量 + + + } + + public static class NET_DVR_RECORDSCHED extends HIKSDKStructure //时间段录像参数配置(子结构) + { + public NET_DVR_SCHEDTIME struRecordTime = new NET_DVR_SCHEDTIME(); + public byte byRecordType; //0:定时录像,1:移动侦测,2:报警录像,3:动测|报警,4:动测&报警, 5:命令触发, 6: 智能录像 + public byte[] reservedData = new byte[3]; + + + } + + public static class NET_DVR_RECORDDAY extends HIKSDKStructure //全天录像参数配置(子结构) + { + public short wAllDayRecord; /* 是否全天录像 0-否 1-是*/ + public byte byRecordType; /* 录象类型 0:定时录像,1:移动侦测,2:报警录像,3:动测|报警,4:动测&报警 5:命令触发, 6: 智能录像*/ + public byte reservedData; + + + } + + public static class NET_DVR_RECORDSCHEDWEEK extends HIKSDKStructure { + public NET_DVR_RECORDSCHED[] struRecordSched = new NET_DVR_RECORDSCHED[MAX_TIMESEGMENT_V30]; + + + } + + public static class NET_DVR_RECORD_V30 extends HIKSDKStructure { //通道录像参数配置(9000扩展) + public int dwSize; + public int dwRecord; /*是否录像 0-否 1-是*/ + public NET_DVR_RECORDDAY[] struRecAllDay = new NET_DVR_RECORDDAY[MAX_DAYS]; + public NET_DVR_RECORDSCHEDWEEK[] struRecordSched = new NET_DVR_RECORDSCHEDWEEK[MAX_DAYS]; + public int dwRecordTime; /* 录象延时长度 0-5秒, 1-20秒, 2-30秒, 3-1分钟, 4-2分钟, 5-5分钟, 6-10分钟*/ + public int dwPreRecordTime; /* 预录时间 0-不预录 1-5秒 2-10秒 3-15秒 4-20秒 5-25秒 6-30秒 7-0xffffffff(尽可能预录) */ + public int dwRecorderDuration; /* 录像保存的最长时间 */ + public byte byRedundancyRec; /*是否冗余录像,重要数据双备份:0/1*/ + public byte byAudioRec; /*录像时复合流编码时是否记录音频数据:国外有此法规*/ + public byte[] byReserve = new byte[10]; + + + } + + public static class NET_DVR_RECORD extends HIKSDKStructure { //通道录像参数配置 + public int dwSize; + public int dwRecord; /*是否录像 0-否 1-是*/ + public NET_DVR_RECORDDAY[] struRecAllDay = new NET_DVR_RECORDDAY[MAX_DAYS]; + public NET_DVR_RECORDSCHEDWEEK[] struRecordSched = new NET_DVR_RECORDSCHEDWEEK[MAX_DAYS]; + public int dwRecordTime; /* 录象时间长度 0-5秒, 1-20秒, 2-30秒, 3-1分钟, 4-2分钟, 5-5分钟, 6-10分钟*/ + public int dwPreRecordTime; /* 预录时间 0-不预录 1-5秒 2-10秒 3-15秒 4-20秒 5-25秒 6-30秒 7-0xffffffff(尽可能预录) */ + + + } + + public static class NET_DVR_STATFRAME extends HIKSDKStructure { //单帧统计参数 + public int dwRelativeTime; + public int dwAbsTime; /*统计绝对时标*/ + public byte[] byRes = new byte[92]; + + + } + + public static class NET_DVR_STATTIME extends HIKSDKStructure { //单帧统计参数 + public NET_DVR_TIME tmStart; //统计开始时间 + public NET_DVR_TIME tmEnd; //统计结束时间 + public byte[] byRes = new byte[92]; + + + } + + public static class UNION_PDC_STATPARAM extends Union { + // public byte[] byLen = new byte[140]; + public NET_DVR_STATFRAME struStatFrame; + public NET_DVR_STATTIME struStatTime; + + + } + + public static class NET_DVR_PDC_ALRAM_INFO extends HIKSDKStructure { //通道录像参数配置 + public int dwSize; + public byte byMode; /*0-单帧统计结果,1-最小时间段统计结果*/ + public byte byChannel; + public byte bySmart; //专业智能返回0,Smart 返回 1 + public byte byRes1; // 保留字节 + public NET_VCA_DEV_INFO struDevInfo = new NET_VCA_DEV_INFO(); //前端设备信息 + public UNION_PDC_STATPARAM uStatModeParam = new UNION_PDC_STATPARAM(); + public int dwLeaveNum; /* 离开人数 */ + public int dwEnterNum; /* 进入人数 */ + public byte byBrokenNetHttp; //断网续传标志位,0-不是重传数据,1-重传数据 + public byte byRes3; + public short wDevInfoIvmsChannelEx; //与NET_VCA_DEV_INFO里的byIvmsChannel含义相同,能表示更大的值。老客户端用byIvmsChannel能继续兼容,但是最大到255。新客户端版本请使用wDevInfoIvmsChannelEx + public int dwPassingNum; // 经过人数(进入区域后徘徊没有触发进入、离开的人数) + public int dwChildLeaveNum; // 小孩离开人数 + public int dwChildEnterNum; // 小孩进入人数 + public int dwDuplicatePeople; // 重复人数 + public int dwXmlLen;//XML透传数据长度, 即EventNotificationAlert XML Block的数据长度 + public Pointer pXmlBuf; // XML报警信息指针,其XML对应到EventNotificationAlert XML Block + public byte[] byRes2 = new byte[8]; + public void read() { + super.read(); + switch (byMode) { + case 0: + uStatModeParam.setType(NET_DVR_STATFRAME.class); + break; + case 1: + uStatModeParam.setType(NET_DVR_STATTIME.class); + break; + default: + break; + } + uStatModeParam.read(); + } + + public void write() { + super.write(); + uStatModeParam.write(); + } + + + } + + //云台协议表结构配置 + public static class NET_DVR_PTZ_PROTOCOL extends HIKSDKStructure { + public int dwType; /*解码器类型值,从1开始连续递增*/ + public byte[] byDescribe = new byte[DESC_LEN]; /*解码器的描述符,和8000中的一致*/ + + + } + + public static class NET_DVR_PTZCFG extends HIKSDKStructure { + public int dwSize; + public NET_DVR_PTZ_PROTOCOL[] struPtz = new NET_DVR_PTZ_PROTOCOL[PTZ_PROTOCOL_NUM];/*最大200中PTZ协议*/ + public int dwPtzNum; /*有效的ptz协议数目,从0开始(即计算时加1)*/ + public byte[] byRes = new byte[8]; + + + } + + /*************************** + * 云台类型(end) + ******************************/ + public static class NET_DVR_DECODERCFG_V30 extends HIKSDKStructure {//通道解码器(云台)参数配置(9000扩展) + public int dwSize; + public int dwBaudRate; //波特率(bps),0-50,1-75,2-110,3-150,4-300,5-600,6-1200,7-2400,8-4800,9-9600,10-19200, 11-38400,12-57600,13-76800,14-115.2k; + public byte byDataBit; // 数据有几位 0-5位,1-6位,2-7位,3-8位; + public byte byStopBit; // 停止位 0-1位,1-2位; + public byte byParity; // 校验 0-无校验,1-奇校验,2-偶校验; + public byte byFlowcontrol; // 0-无,1-软流控,2-硬流控 + public short wDecoderType; //解码器类型, 0-YouLi,1-LiLin-1016,2-LiLin-820,3-Pelco-p,4-DM DynaColor,5-HD600,6-JC-4116,7-Pelco-d WX,8-Pelco-d PICO + public short wDecoderAddress; /*解码器地址:0 - 255*/ + public byte[] bySetPreset = new byte[MAX_PRESET_V30]; /* 预置点是否设置,0-没有设置,1-设置*/ + public byte[] bySetCruise = new byte[MAX_CRUISE_V30]; /* 巡航是否设置: 0-没有设置,1-设置 */ + public byte[] bySetTrack = new byte[MAX_TRACK_V30]; /* 是否设置,0-没有设置,1-设置*/ + + + } + + public static class NET_DVR_DECODERCFG extends HIKSDKStructure {//通道解码器(云台)参数配置 + public int dwSize; + public int dwBaudRate; //波特率(bps),0-50,1-75,2-110,3-150,4-300,5-600,6-1200,7-2400,8-4800,9-9600,10-19200, 11-38400,12-57600,13-76800,14-115.2k; + public byte byDataBit; // 数据有几位 0-5位,1-6位,2-7位,3-8位; + public byte byStopBit; // 停止位 0-1位,1-2位; + public byte byParity; // 校验 0-无校验,1-奇校验,2-偶校验; + public byte byFlowcontrol; // 0-无,1-软流控,2-硬流控 + public short wDecoderType; //解码器类型, 0-YouLi,1-LiLin-1016,2-LiLin-820,3-Pelco-p,4-DM DynaColor,5-HD600,6-JC-4116,7-Pelco-d WX,8-Pelco-d PICO + public short wDecoderAddress; /*解码器地址:0 - 255*/ + public byte[] bySetPreset = new byte[MAX_PRESET]; /* 预置点是否设置,0-没有设置,1-设置*/ + public byte[] bySetCruise = new byte[MAX_CRUISE]; /* 巡航是否设置: 0-没有设置,1-设置 */ + public byte[] bySetTrack = new byte[MAX_TRACK]; /* 是否设置,0-没有设置,1-设置*/ + + + } + + public static class NET_DVR_PPPCFG_V30 extends HIKSDKStructure {//ppp参数配置(子结构) + public NET_DVR_IPADDR struRemoteIP; //远端IP地址 + public NET_DVR_IPADDR struLocalIP; //本地IP地址 + public byte[] sLocalIPMask = new byte[16]; //本地IP地址掩码 + public byte[] sUsername = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public byte byPPPMode; //PPP模式, 0-主动,1-被动 + public byte byRedial; //是否回拨 :0-否,1-是 + public byte byRedialMode; //回拨模式,0-由拨入者指定,1-预置回拨号码 + public byte byDataEncrypt; //数据加密,0-否,1-是 + public int dwMTU; //MTU + public byte[] sTelephoneNumber = new byte[PHONENUMBER_LEN]; //电话号码 + + + } + + public static class NET_DVR_PPPCFG extends HIKSDKStructure {//ppp参数配置(子结构) + public byte[] sRemoteIP = new byte[16]; //远端IP地址 + public byte[] sLocalIP = new byte[16]; //本地IP地址 + public byte[] sLocalIPMask = new byte[16]; //本地IP地址掩码 + public byte[] sUsername = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public byte byPPPMode; //PPP模式, 0-主动,1-被动 + public byte byRedial; //是否回拨 :0-否,1-是 + public byte byRedialMode; //回拨模式,0-由拨入者指定,1-预置回拨号码 + public byte byDataEncrypt; //数据加密,0-否,1-是 + public int dwMTU; //MTU + public byte[] sTelephoneNumber = new byte[PHONENUMBER_LEN]; //电话号码 + + + } + + + public static class NET_DVR_SINGLE_RS232 extends HIKSDKStructure {//RS232串口参数配置(9000扩展) + public int dwBaudRate; /*波特率(bps),0-50,1-75,2-110,3-150,4-300,5-600,6-1200,7-2400,8-4800,9-9600,10-19200, 11-38400,12-57600,13-76800,14-115.2k;*/ + public byte byDataBit; /* 数据有几位 0-5位,1-6位,2-7位,3-8位 */ + public byte byStopBit; /* 停止位 0-1位,1-2位 */ + public byte byParity; /* 校验 0-无校验,1-奇校验,2-偶校验 */ + public byte byFlowcontrol; /* 0-无,1-软流控,2-硬流控 */ + public int dwWorkMode; /* 工作模式,0-232串口用于PPP拨号,1-232串口用于参数控制,2-透明通道 */ + + + } + + public static class NET_DVR_RS232CFG_V30 extends HIKSDKStructure {//RS232串口参数配置(9000扩展) + public int dwSize; + public NET_DVR_SINGLE_RS232 struRs232;/*目前只有第一个串口设置有效,所有设备都只支持一个串口,其他七个保留*/ + public byte[] byRes = new byte[84]; + public NET_DVR_PPPCFG_V30 struPPPConfig;/*ppp参数*/ + + + } + + public static class NET_DVR_RS232CFG extends HIKSDKStructure {//RS232串口参数配置 + public int dwSize; + public int dwBaudRate;//波特率(bps),0-50,1-75,2-110,3-150,4-300,5-600,6-1200,7-2400,8-4800,9-9600,10-19200, 11-38400,12-57600,13-76800,14-115.2k; + public byte byDataBit;// 数据有几位 0-5位,1-6位,2-7位,3-8位; + public byte byStopBit;// 停止位 0-1位,1-2位; + public byte byParity;// 校验 0-无校验,1-奇校验,2-偶校验; + public byte byFlowcontrol;// 0-无,1-软流控,2-硬流控 + public int dwWorkMode;// 工作模式,0-窄带传输(232串口用于PPP拨号),1-控制台(232串口用于参数控制),2-透明通道 + public NET_DVR_PPPCFG struPPPConfig; + + + } + + public static class NET_DVR_ALARMINCFG_V30 extends HIKSDKStructure {//报警输入参数配置(9000扩展) + public int dwSize; + public byte[] sAlarmInName = new byte[NAME_LEN]; /* 名称 */ + public byte byAlarmType; //报警器类型,0:常开,1:常闭 + public byte byAlarmInHandle; /* 是否处理 0-不处理 1-处理*/ + public byte[] reservedData = new byte[2]; + public NET_DVR_HANDLEEXCEPTION_V30 struAlarmHandleType; /* 处理方式 */ + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS];//布防时间 + public byte[] byRelRecordChan = new byte[MAX_CHANNUM_V30]; //报警触发的录象通道,为1表示触发该通道 + public byte[] byEnablePreset = new byte[MAX_CHANNUM_V30]; /* 是否调用预置点 0-否,1-是*/ + public byte[] byPresetNo = new byte[MAX_CHANNUM_V30]; /* 调用的云台预置点序号,一个报警输入可以调用多个通道的云台预置点, 0xff表示不调用预置点。*/ + public byte[] byEnablePresetRevert = new byte[MAX_CHANNUM_V30]; /* 是否恢复到调用预置点前的位置(保留) */ + public short[] wPresetRevertDelay = new short[MAX_CHANNUM_V30]; /* 恢复预置点延时(保留) */ + public byte[] byEnableCruise = new byte[MAX_CHANNUM_V30]; /* 是否调用巡航 0-否,1-是*/ + public byte[] byCruiseNo = new byte[MAX_CHANNUM_V30]; /* 巡航 */ + public byte[] byEnablePtzTrack = new byte[MAX_CHANNUM_V30]; /* 是否调用 0-否,1-是*/ + public byte[] byPTZTrack = new byte[MAX_CHANNUM_V30]; /* 调用的云台的序号 */ + public byte[] byRes = new byte[16]; + + + } + + public static class NET_DVR_ALARMINCFG extends HIKSDKStructure {//报警输入参数配置 + public int dwSize; + public byte[] sAlarmInName = new byte[NAME_LEN]; /* 名称 */ + public byte byAlarmType; //报警器类型,0:常开,1:常闭 + public byte byAlarmInHandle; /* 是否处理 0-不处理 1-处理*/ + public NET_DVR_HANDLEEXCEPTION struAlarmHandleType; /* 处理方式 */ + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS];//布防时间 + public byte[] byRelRecordChan = new byte[MAX_CHANNUM]; //报警触发的录象通道,为1表示触发该通道 + public byte[] byEnablePreset = new byte[MAX_CHANNUM]; /* 是否调用预置点 0-否,1-是*/ + public byte[] byPresetNo = new byte[MAX_CHANNUM]; /* 调用的云台预置点序号,一个报警输入可以调用多个通道的云台预置点, 0xff表示不调用预置点。*/ + public byte[] byEnableCruise = new byte[MAX_CHANNUM]; /* 是否调用巡航 0-否,1-是*/ + public byte[] byCruiseNo = new byte[MAX_CHANNUM]; /* 巡航 */ + public byte[] byEnablePtzTrack = new byte[MAX_CHANNUM]; /* 是否调用 0-否,1-是*/ + public byte[] byPTZTrack = new byte[MAX_CHANNUM]; /* 调用的云台的序号 */ + + + } + + public static class NET_DVR_ADDIT_POSITION extends HIKSDKStructure {//车载GPS信息结构(2007-12-27) + public byte[] sDevName = new byte[32]; /* 设备名称 */ + public int dwSpeed; /*速度*/ + public int dwLongitude; /* 经度*/ + public int dwLatitude; /* 纬度*/ + public byte[] direction = new byte[2]; /* direction[0]:'E'or'W'(东经/西经), direction[1]:'N'or'S'(北纬/南纬) */ + public byte[] res = new byte[2]; /* 保留位 */ + + + } + + public static class struRecordingHost extends HIKSDKStructure { + public byte bySubAlarmType; + public byte[] byRes1 = new byte[3]; + public NET_DVR_TIME_EX struRecordEndTime = new NET_DVR_TIME_EX(); + } + + public static class struAlarmHardDisk extends HIKSDKStructure { + public int dwAlarmHardDiskNum; + + + } + + public static class struAlarmChannel extends HIKSDKStructure { + public int dwAlarmChanNum; + public int dwPicLen;//Jpeg图片长度 + public byte byPicURL; //图片数据采用URL方式 0-二进制图片数据,1-图片数据走URL方式 + public byte byTarget; /*0-不区分识别目标,1-识别目标为人,2-识别目标为车*/ + public byte[] byRes1 = new byte[2]; //保留 + public Pointer pDataBuff; //报警图片或者图片URL + } + + public static class struIOAlarm extends HIKSDKStructure { + public int dwAlarmInputNo; + public int dwTrigerAlarmOutNum; + public int dwTrigerRecordChanNum; + + + } + + public static class NET_DVR_TIME_EX extends HIKSDKStructure { + public short wYear; + public byte byMonth; + public byte byDay; + public byte byHour; + public byte byMinute; + public byte bySecond; + public byte byRes; + } + + public static class uStruAlarm extends Union { + public byte[] byUnionLen = new byte[116]; + public struIOAlarm struioAlarm = new struIOAlarm(); + public struAlarmHardDisk strualarmHardDisk = new struAlarmHardDisk(); + public struAlarmChannel strualarmChannel = new struAlarmChannel(); + public struRecordingHost strurecordingHost = new struRecordingHost(); + + + } + + public static class NET_DVR_ALRAM_FIXED_HEADER extends HIKSDKStructure { + public int dwAlarmType; + public NET_DVR_TIME_EX struAlarmTime = new NET_DVR_TIME_EX(); + public uStruAlarm ustruAlarm = new uStruAlarm(); + public Pointer pRes; + public byte byTimeDiffFlag; /*时差字段是否有效 0-时差无效, 1-时差有效 */ + public byte cTimeDifferenceH; /*与UTC的时差(小时),-12 ... +14, +表示东区,,byTimeDiffFlag为1时有效*/ + public byte cTimeDifferenceM; /*与UTC的时差(分钟),-30, 30, 45, +表示东区,byTimeDiffFlag为1时有效*/ + public byte byRes; //保留 + public short wDevInfoIvmsChannel; //增加后端透传前端时的通道号 + public byte[] byRes2 = new byte[2]; //保留 + } + + public static class NET_DVR_ALARMINFO_V40 extends HIKSDKStructure { + public NET_DVR_ALRAM_FIXED_HEADER struAlarmFixedHeader = new NET_DVR_ALRAM_FIXED_HEADER(); + public Pointer pAlarmData; + + + } + + public static class NET_DVR_ALARMINFO_V30 extends HIKSDKStructure {//上传报警信息(9000扩展) + public int dwAlarmType;/*0-信号量报警,1-硬盘满,2-信号丢失,3-移动侦测,4-硬盘未格式化,5-读写硬盘出错,6-遮挡报警,7-制式不匹配, 8-非法访问, 0xa-GPS定位信息(车载定制)*/ + public int dwAlarmInputNumber;/*报警输入端口*/ + public byte[] byAlarmOutputNumber = new byte[MAX_ALARMOUT_V30];/*触发的输出端口,为1表示对应输出*/ + public byte[] byAlarmRelateChannel = new byte[MAX_CHANNUM_V30];/*触发的录像通道,为1表示对应录像, dwAlarmRelateChannel[0]对应第1个通道*/ + public byte[] byChannel = new byte[MAX_CHANNUM_V30];/*dwAlarmType为2或3,6时,表示哪个通道,dwChannel[0]对应第1个通道*/ + public byte[] byDiskNumber = new byte[MAX_DISKNUM_V30];/*dwAlarmType为1,4,5时,表示哪个硬盘, dwDiskNumber[0]对应第1个硬盘*/ + + + } + + public static class NET_DVR_ALARMINFO extends HIKSDKStructure { + public int dwAlarmType;/*0-信号量报警,1-硬盘满,2-信号丢失,3-移动侦测,4-硬盘未格式化,5-读写硬盘出错,6-遮挡报警,7-制式不匹配, 8-非法访问, 9-串口状态, 0xa-GPS定位信息(车载定制)*/ + public int dwAlarmInputNumber;/*报警输入端口, 当报警类型为9时该变量表示串口状态0表示正常, -1表示错误*/ + public int[] dwAlarmOutputNumber = new int[MAX_ALARMOUT];/*触发的输出端口,为1表示对应哪一个输出*/ + public int[] dwAlarmRelateChannel = new int[MAX_CHANNUM];/*触发的录像通道,dwAlarmRelateChannel[0]为1表示第1个通道录像*/ + public int[] dwChannel = new int[MAX_CHANNUM];/*dwAlarmType为2或3,6时,表示哪个通道,dwChannel[0]位对应第1个通道*/ + public int[] dwDiskNumber = new int[MAX_DISKNUM];/*dwAlarmType为1,4,5时,表示哪个硬盘, dwDiskNumber[0]位对应第1个硬盘*/ + + + } + + public static class NET_DVR_ALARMINFO_EX extends HIKSDKStructure {//上传报警信息(杭州竞天定制 2006-07-28) + public int dwAlarmType;/*0-信号量报警,1-硬盘满,2-信号丢失,3-移动侦测,4-硬盘未格式化,5-读写硬盘出错,6-遮挡报警,7-制式不匹配, 8-非法访问*/ + public int dwAlarmInputNumber;/*报警输入端口*/ + public int[] dwAlarmOutputNumber = new int[MAX_ALARMOUT];/*报警输入端口对应的输出端口,哪一位为1表示对应哪一个输出*/ + public int[] dwAlarmRelateChannel = new int[MAX_CHANNUM];/*报警输入端口对应的录像通道,哪一位为1表示对应哪一路录像,dwAlarmRelateChannel[0]对应第1个通道*/ + public int[] dwChannel = new int[MAX_CHANNUM];/*dwAlarmType为2或3,6时,表示哪个通道,dwChannel[0]位对应第0个通道*/ + public int[] dwDiskNumber = new int[MAX_DISKNUM];/*dwAlarmType为1,4,5时,表示哪个硬盘*/ + public byte[] sSerialNumber = new byte[SERIALNO_LEN]; //序列号 + public byte[] sRemoteAlarmIP = new byte[16]; //远程报警IP地址; + + + } + + ////////////////////////////////////////////////////////////////////////////////////// +//IPC接入参数配置 + public static class NET_DVR_IPDEVINFO extends HIKSDKStructure {/* IP设备结构 */ + public int dwEnable; /* 该IP设备是否启用 */ + public byte[] sUserName = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public NET_DVR_IPADDR struIP = new NET_DVR_IPADDR(); /* IP地址 */ + public short wDVRPort; /* 端口号 */ + public byte[] byres = new byte[34]; /* 保留 */ + + + } + /* IP通道匹配参数 */ + public static class NET_DVR_IPCHANINFO extends HIKSDKStructure {/* IP通道匹配参数 */ + + public byte byEnable; /* 该通道是否在线 */ + public byte byIPID; //IP设备ID低8位,当设备ID为0时表示通道不可用 + public byte byChannel; /* 通道号 */ + public byte byIPIDHigh; // IP设备ID的高8位 + public byte byTransProtocol; //传输协议类型0-TCP/auto(具体有设备决定),1-UDP 2-多播 3-仅TCP 4-auto + public byte byGetStream; /* 是否对该通道取流,0-是,1-否*/ + public byte[] byres=new byte[30]; /* 保留 */ + + + } + + public static class NET_DVR_IPPARACFG extends HIKSDKStructure {/* IP接入配置结构 */ + public int dwSize; /* 结构大小 */ + public NET_DVR_IPDEVINFO[] struIPDevInfo = new NET_DVR_IPDEVINFO[MAX_IP_DEVICE]; /* IP设备 */ + public byte[] byAnalogChanEnable = new byte[MAX_ANALOG_CHANNUM]; /* 模拟通道是否启用,从低到高表示1-32通道,0表示无效 1有效 */ + public NET_DVR_IPCHANINFO[] struIPChanInfo = new NET_DVR_IPCHANINFO[MAX_IP_CHANNEL]; /* IP通道 */ + + + } + + public class NET_DVR_IPDEVINFO_V31 extends HIKSDKStructure { + public byte byEnable;/* 该通道是否启用 */ + public byte byProType;//协议类型(默认为私有协议),0- 私有协议,1- 松下协议,2- 索尼,更多协议通过NET_DVR_GetIPCProtoList获取。 + public byte byEnableQuickAdd;//0-不支持快速添加;1-使用快速添加 + public byte byRes1;//保留,置为0 + public byte[] sUserName = new byte[HCNetSDK.NAME_LEN];//用户名 + public byte[] sPassword = new byte[HCNetSDK.PASSWD_LEN];//密码 + public byte[] byDomain = new byte[HCNetSDK.MAX_DOMAIN_NAME];//设备域名 + public NET_DVR_IPADDR struIP = new NET_DVR_IPADDR();//IP地址 + public short wDVRPort;//端口号 + public byte[] szDeviceID = new byte[32]; + public byte[] byRes2 = new byte[2];//保留,置为0 + + + } + + public class NET_DVR_STREAM_MODE extends HIKSDKStructure { + + public byte byGetStreamType;//取流方式:0- 直接从设备取流;1- 从流媒体取流;2- 通过IPServer获得IP地址后取流; + //3- 通过IPServer找到设备,再通过流媒体取设备的流; 4- 通过流媒体由URL去取流;5- 通过hiDDNS域名连接设备然后从设备取流 + public byte[] byRes = new byte[3];//保留,置为0 + public NET_DVR_GET_STREAM_UNION uGetStream = new NET_DVR_GET_STREAM_UNION();//不同取流方式联合体 + + public void read() { + super.read(); + switch (byGetStreamType) { + case 0: + uGetStream.setType(NET_DVR_IPCHANINFO.class); + break; + case 6: + uGetStream.setType(NET_DVR_IPCHANINFO_V40.class); + break; + default: + break; + } + } + + + } + + public class NET_DVR_IPSERVER_STREAM extends HIKSDKStructure { + public byte byEnable; + public byte[] byRes = new byte[3]; + public NET_DVR_IPADDR struIPServer = new NET_DVR_IPADDR(); + public short wPort; + public short wDvrNameLen; + public byte[] byDVRName = new byte[HCNetSDK.NAME_LEN]; + public short wDVRSerialLen; + public short[] byRes1 = new short[2]; + public byte[] byDVRSerialNumber = new byte[HCNetSDK.SERIALNO_LEN]; + public byte[] byUserName = new byte[HCNetSDK.NAME_LEN]; + public byte[] byPassWord = new byte[HCNetSDK.PASSWD_LEN]; + public byte byChannel; + public byte[] byRes2 = new byte[11]; + + + } + + public class NET_DVR_STREAM_MEDIA_SERVER_CFG extends HIKSDKStructure { + + public byte byValid;//是否启用流媒体服务器取流:0-不启用,非0-启用 + public byte[] byRes1 = new byte[3];//保留,置为0 + public NET_DVR_IPADDR struDevIP = new NET_DVR_IPADDR();//流媒体服务器的IP地址 + public short wDevPort;//流媒体服务器端口 + public byte byTransmitType;//传输协议类型:0-TCP,1-UDP + public byte[] byRes2 = new byte[69]; + + + } + + public class NET_DVR_DEV_CHAN_INFO extends HIKSDKStructure { + public NET_DVR_IPADDR struIP = new NET_DVR_IPADDR();//设备IP地址 + public short wDVRPort;//设备端口号 + public byte byChannel;//通道号,目前设备的模拟通道号是从1开始的,对于9000等设备的IPC接入,数字通道号从33开始 + public byte byTransProtocol;//传输协议类型:0-TCP,1-UDP,2-多播方式,3-RTP + public byte byTransMode;//传输码流模式:0-主码流,1-子码流 + public byte byFactoryType;//前端设备厂家类型, 通过接口NET_DVR_GetIPCProtoList获取 + public byte byDeviceType;//设备类型(视频综合平台使用):1- IPC,2- ENCODER + public byte byDispChan;// 显示通道号(智能配置使用),根据能力集决定使用解码通道还是显示通道 + public byte bySubDispChan;//显示通道子通道号(智能配置时使用) + public byte byResolution;//分辨率:1- CIF,2- 4CIF,3- 720P,4- 1080P,5- 500W,用于多屏控制器,多屏控制器会根据该参数分配解码资源 + public byte[] byRes = new byte[2];//保留,置为0 + public byte[] byDomain = new byte[HCNetSDK.MAX_DOMAIN_NAME];//设备域名 + public byte[] sUserName = new byte[HCNetSDK.NAME_LEN];//设备登陆帐号 + public byte[] sPassword = new byte[HCNetSDK.PASSWD_LEN];//设备密码 + } + + public class NET_DVR_PU_STREAM_CFG extends HIKSDKStructure { + public int dwSize;//结构体大小 + public NET_DVR_STREAM_MEDIA_SERVER_CFG struStreamMediaSvrCfg = new NET_DVR_STREAM_MEDIA_SERVER_CFG(); + public NET_DVR_DEV_CHAN_INFO struDevChanInfo = new NET_DVR_DEV_CHAN_INFO(); + } + + public class NET_DVR_PU_STREAM_CFG_V41 extends HIKSDKStructure { + public int dwSize; + public byte byStreamMode;/*取流模式,0-无效,1-通过IP或域名取流,2-通过URL取流,3-通过动态域名解析向设备取流*/ + public byte byStreamEncrypt; //是否进行码流加密处理,0-不支持,1-支持 + public byte[] byRes1 = new byte[2]; + public NET_DVR_DEC_STREAM_MODE uDecStreamMode;//取流信息 + public int dwDecDelayTime;//解码延时时间,单位:毫秒 + public byte[] sStreamPassword = new byte[STREAM_PASSWD_LEN]; //码流加密密码,需敏感信息加密 + public byte[] byRes2 = new byte[48]; + } + + + public class NET_DVR_DDNS_STREAM_CFG extends HIKSDKStructure { + public byte byEnable; + public byte[] byRes1 = new byte[3]; + public NET_DVR_IPADDR struStreamServer = new NET_DVR_IPADDR(); + public short wStreamServerPort; + public byte byStreamServerTransmitType; + public byte byRes2; + public NET_DVR_IPADDR struIPServer = new NET_DVR_IPADDR(); + public short wIPServerPort; + public byte[] byRes3 = new byte[2]; + public byte[] sDVRName = new byte[HCNetSDK.NAME_LEN]; + public short wDVRNameLen; + public short wDVRSerialLen; + public byte[] sDVRSerialNumber = new byte[HCNetSDK.SERIALNO_LEN]; + public byte[] sUserName = new byte[HCNetSDK.NAME_LEN]; + public byte[] sPassWord = new byte[HCNetSDK.PASSWD_LEN]; + public short wDVRPort; + public byte[] byRes4 = new byte[2]; + public byte byChannel; + public byte byTransProtocol; + public byte byTransMode; + public byte byFactoryType; + + + } + + public class NET_DVR_PU_STREAM_URL extends HIKSDKStructure { + public byte byEnable;//是否启用:0- 禁用,1- 启用 + public byte[] strURL = new byte[240];//取流URL路径 + public byte byTransPortocol;//传输协议类型:0-TCP,1-UDP + public short wIPID;//设备ID号,wIPID = iDevInfoIndex + iGroupNO*64 +1 + public byte byChannel;//设备通道号 + public byte[] byRes = new byte[7];//保留,置为0 + + + } + + public class NET_DVR_HKDDNS_STREAM extends HIKSDKStructure { + public byte byEnable;//是否启用 + public byte[] byRes = new byte[3];//保留 + public byte[] byDDNSDomain = new byte[64];//hiDDNS服务器地址 + public short wPort;//hiDDNS端口,默认:80 + public short wAliasLen;//别名长度 + public byte[] byAlias = new byte[HCNetSDK.NAME_LEN];//别名 + public short wDVRSerialLen;//序列号长度 + public byte[] byRes1 = new byte[2];//保留 + public byte[] byDVRSerialNumber = new byte[HCNetSDK.SERIALNO_LEN];//设备序列号 + public byte[] byUserName = new byte[HCNetSDK.NAME_LEN];//设备登录用户名 + public byte[] byPassWord = new byte[HCNetSDK.PASSWD_LEN];//设备登录密码 + public byte byChannel;//设备通道号 + public byte[] byRes2 = new byte[11];//保留 + + + } + + public class NET_DVR_IPCHANINFO_V40 extends HIKSDKStructure { + + public byte byEnable;//IP通道在线状态,是一个只读的属性; + //0表示HDVR或者NVR设备的数字通道连接对应的IP设备失败,该通道不在线;1表示连接成功,该通道在线 + public byte byRes1;//保留,置为0 + public short wIPID;//IP设备ID + public int dwChannel;//IP设备的通道号,例如设备A(HDVR或者NVR设备)的IP通道01,对应的是设备B(DVS)里的通道04,则byChannel=4,如果前端接的是IPC则byChannel=1。 + public byte byTransProtocol;//传输协议类型:0- TCP,1- UDP,2- 多播,0xff- auto(自动) + public byte byTransMode;//传输码流模式:0- 主码流,1- 子码流 + public byte byFactoryType;//前端设备厂家类型 + public byte[] byRes = new byte[241];//保留,置为0 + + + } + + + public static class NET_DVR_GET_STREAM_UNION extends Union { + public NET_DVR_IPCHANINFO struChanInfo = new NET_DVR_IPCHANINFO(); /*IP通道信息*/ + public NET_DVR_IPCHANINFO_V40 struIPChan = new NET_DVR_IPCHANINFO_V40(); //直接从设备取流(扩展) + public byte[] byUnionLen = new byte[492]; //直接从设备取流(扩展) + + + } + + public static class NET_DVR_IPPARACFG_V40 extends HIKSDKStructure {/* IP接入配置结构V40 */ + public int dwSize; /* 结构大小 */ + public int dwGroupNum;//设备支持的总组数(只读)。 + public int dwAChanNum;//最大模拟通道个数(只读) + public int dwDChanNum;//数字通道个数(只读) + public int dwStartDChan;//起始数字通道(只读) + public byte[] byAnalogChanEnable = new byte[MAX_CHANNUM_V30]; //模拟通道资源是否启用,从低到高表示1-64通道:0-禁用,1-启用。 + public NET_DVR_IPDEVINFO_V31[] struIPDevInfo = new NET_DVR_IPDEVINFO_V31[MAX_IP_DEVICE_V40];//IP设备信息,下标0对应设备IP ID为1 + public NET_DVR_STREAM_MODE[] struStreamMode = new NET_DVR_STREAM_MODE[MAX_CHANNUM_V30];//取流模式 + public byte[] byRes2 = new byte[20];//保留,置为0 + + + } + + public static class NET_DVR_IPALARMOUTINFO extends HIKSDKStructure {/* 报警输出参数 */ + public byte byIPID; /* IP设备ID取值1- MAX_IP_DEVICE */ + public byte byAlarmOut; /* 报警输出号 */ + public byte[] byRes = new byte[18]; /* 保留 */ + + + } + + public static class NET_DVR_IPALARMOUTCFG extends HIKSDKStructure {/* IP报警输出配置结构 */ + public int dwSize; /* 结构大小 */ + public NET_DVR_IPALARMOUTINFO[] struIPAlarmOutInfo = new NET_DVR_IPALARMOUTINFO[MAX_IP_ALARMOUT];/* IP报警输出 */ + + + } + + public static class NET_DVR_IPALARMININFO extends HIKSDKStructure {/* 报警输入参数 */ + public byte byIPID; /* IP设备ID取值1- MAX_IP_DEVICE */ + public byte byAlarmIn; /* 报警输入号 */ + public byte[] byRes = new byte[18]; /* 保留 */ + + + } + + public static class NET_DVR_IPALARMINCFG extends HIKSDKStructure {/* IP报警输入配置结构 */ + public int dwSize; /* 结构大小 */ + public NET_DVR_IPALARMININFO[] struIPAlarmInInfo = new NET_DVR_IPALARMININFO[MAX_IP_ALARMIN];/* IP报警输入 */ + + + } + + public static class NET_DVR_IPALARMINFO extends HIKSDKStructure {//ipc alarm info + public NET_DVR_IPDEVINFO[] struIPDevInfo = new NET_DVR_IPDEVINFO[MAX_IP_DEVICE]; /* IP设备 */ + public byte[] byAnalogChanEnable = new byte[MAX_ANALOG_CHANNUM]; /* 模拟通道是否启用,0-未启用 1-启用 */ + public NET_DVR_IPCHANINFO[] struIPChanInfo = new NET_DVR_IPCHANINFO[MAX_IP_CHANNEL]; /* IP通道 */ + public NET_DVR_IPALARMININFO[] struIPAlarmInInfo = new NET_DVR_IPALARMININFO[MAX_IP_ALARMIN]; /* IP报警输入 */ + public NET_DVR_IPALARMOUTINFO[] struIPAlarmOutInfo = new NET_DVR_IPALARMOUTINFO[MAX_IP_ALARMOUT]; /* IP报警输出 */ + + + } + + public static class NET_DVR_SINGLE_HD extends HIKSDKStructure {//本地硬盘信息配置 + public int dwHDNo; /*硬盘号, 取值0~MAX_DISKNUM_V30-1*/ + public int dwCapacity; /*硬盘容量(不可设置)*/ + public int dwFreeSpace; /*硬盘剩余空间(不可设置)*/ + public int dwHdStatus; /*硬盘状态(不可设置) 0-正常, 1-未格式化, 2-错误, 3-SMART状态, 4-不匹配, 5-休眠*/ + public byte byHDAttr; /*0-默认, 1-冗余; 2-只读*/ + public byte[] byRes1 = new byte[3]; + public int dwHdGroup; /*属于哪个盘组 1-MAX_HD_GROUP*/ + public byte[] byRes2 = new byte[120]; + } + + public static class NET_DVR_HDCFG extends HIKSDKStructure { + public int dwSize; + public int dwHDCount; /*硬盘数(不可设置)*/ + public NET_DVR_SINGLE_HD[] struHDInfo = new NET_DVR_SINGLE_HD[MAX_DISKNUM_V30];//硬盘相关操作都需要重启才能生效; + } + + public static class NET_DVR_SINGLE_HDGROUP extends HIKSDKStructure {//本地盘组信息配置 + public int dwHDGroupNo; /*盘组号(不可设置) 1-MAX_HD_GROUP*/ + public byte[] byHDGroupChans = new byte[64]; /*盘组对应的录像通道, 0-表示该通道不录象到该盘组,1-表示录象到该盘组*/ + public byte[] byRes = new byte[8]; + } + + public static class NET_DVR_HDGROUP_CFG extends HIKSDKStructure { + public int dwSize; + public int dwHDGroupCount; /*盘组总数(不可设置)*/ + public NET_DVR_SINGLE_HDGROUP[] struHDGroupAttr = new NET_DVR_SINGLE_HDGROUP[MAX_HD_GROUP];//硬盘相关操作都需要重启才能生效; + } + + public static class NET_DVR_SCALECFG extends HIKSDKStructure {//配置缩放参数的结构 + public int dwSize; + public int dwMajorScale; /* 主显示 0-不缩放,1-缩放*/ + public int dwMinorScale; /* 辅显示 0-不缩放,1-缩放*/ + public int[] dwRes = new int[2]; + } + + public static class NET_DVR_ALARMOUTCFG_V30 extends HIKSDKStructure {//DVR报警输出(9000扩展) + public int dwSize; + public byte[] sAlarmOutName = new byte[NAME_LEN]; /* 名称 */ + public int dwAlarmOutDelay; /* 输出保持时间(-1为无限,手动关闭) */ + //0-5秒,1-10秒,2-30秒,3-1分钟,4-2分钟,5-5分钟,6-10分钟,7-手动 + public NET_DVR_SCHEDTIMEWEEK[] struAlarmOutTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS];/* 报警输出激活时间段 */ + public byte[] byRes = new byte[16]; + } + + public static class NET_DVR_ALARMOUTCFG extends HIKSDKStructure {//DVR报警输出 + public int dwSize; + public byte[] sAlarmOutName = new byte[NAME_LEN]; /* 名称 */ + public int dwAlarmOutDelay; /* 输出保持时间(-1为无限,手动关闭) */ + //0-5秒,1-10秒,2-30秒,3-1分钟,4-2分钟,5-5分钟,6-10分钟,7-手动 + public NET_DVR_SCHEDTIMEWEEK[] struAlarmOutTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS];/* 报警输出激活时间段 */ + } + + public static class NET_DVR_PREVIEWCFG_V30 extends HIKSDKStructure {//DVR本地预览参数(9000扩展) + public int dwSize; + public byte byPreviewNumber;//预览数目,0-1画面,1-4画面,2-9画面,3-16画面, 4-6画面, 5-8画面, 0xff:最大画面 + public byte byEnableAudio;//是否声音预览,0-不预览,1-预览 + public short wSwitchTime;//切换时间,0-不切换,1-5s,2-10s,3-20s,4-30s,5-60s,6-120s,7-300s + public byte[][] bySwitchSeq = new byte[MAX_PREVIEW_MODE][MAX_WINDOW_V30];//切换顺序,如果lSwitchSeq[i]为 0xff表示不用 + public byte[] byRes = new byte[24]; + } + + public static class NET_DVR_PREVIEWCFG extends HIKSDKStructure {//DVR本地预览参数 + public int dwSize; + public byte byPreviewNumber;//预览数目,0-1画面,1-4画面,2-9画面,3-16画面,0xff:最大画面 + public byte byEnableAudio;//是否声音预览,0-不预览,1-预览 + public short wSwitchTime;//切换时间,0-不切换,1-5s,2-10s,3-20s,4-30s,5-60s,6-120s,7-300s + public byte[] bySwitchSeq = new byte[MAX_WINDOW];//切换顺序,如果lSwitchSeq[i]为 0xff表示不用 + } + + public static class NET_DVR_VGAPARA extends HIKSDKStructure {//DVR视频输出 + public short wResolution; /* 分辨率 */ + public short wFreq; /* 刷新频率 */ + public int dwBrightness; /* 亮度 */ + } + + /* + * MATRIX输出参数结构 + */ + public static class NET_DVR_MATRIXPARA_V30 extends HIKSDKStructure { + public short[] wOrder = new short[MAX_ANALOG_CHANNUM]; /* 预览顺序, 0xff表示相应的窗口不预览 */ + public short wSwitchTime; /* 预览切换时间 */ + public byte[] res = new byte[14]; + } + + public static class NET_DVR_MATRIXPARA extends HIKSDKStructure { + public short wDisplayLogo; /* 显示视频通道号(保留) */ + public short wDisplayOsd; /* 显示时间(保留) */ + } + + public static class NET_DVR_VOOUT extends HIKSDKStructure { + public byte byVideoFormat; /* 输出制式,0-PAL,1-NTSC */ + public byte byMenuAlphaValue; /* 菜单与背景图象对比度 */ + public short wScreenSaveTime; /* 屏幕保护时间 0-从不,1-1分钟,2-2分钟,3-5分钟,4-10分钟,5-20分钟,6-30分钟 */ + public short wVOffset; /* 视频输出偏移 */ + public short wBrightness; /* 视频输出亮度 */ + public byte byStartMode; /* 启动后视频输出模式(0:菜单,1:预览)*/ + public byte byEnableScaler; /* 是否启动缩放 (0-不启动, 1-启动)*/ + } + + public static class NET_DVR_VIDEOOUT_V30 extends HIKSDKStructure {//DVR视频输出(9000扩展) + public int dwSize; + public NET_DVR_VOOUT[] struVOOut = new NET_DVR_VOOUT[MAX_VIDEOOUT_V30]; + public NET_DVR_VGAPARA[] struVGAPara = new NET_DVR_VGAPARA[MAX_VGA_V30]; /* VGA参数 */ + public NET_DVR_MATRIXPARA_V30[] struMatrixPara = new NET_DVR_MATRIXPARA_V30[MAX_MATRIXOUT]; /* MATRIX参数 */ + public byte[] byRes = new byte[16]; + } + + public static class NET_DVR_VIDEOOUT extends HIKSDKStructure {//DVR视频输出 + public int dwSize; + public NET_DVR_VOOUT[] struVOOut = new NET_DVR_VOOUT[MAX_VIDEOOUT]; + public NET_DVR_VGAPARA[] struVGAPara = new NET_DVR_VGAPARA[MAX_VGA]; /* VGA参数 */ + public NET_DVR_MATRIXPARA struMatrixPara; /* MATRIX参数 */ + } + + public static class NET_DVR_USER_INFO_V30 extends HIKSDKStructure {//单用户参数(子结构)(9000扩展) + public byte[] sUserName = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public byte[] byLocalRight = new byte[MAX_RIGHT]; /* 本地权限 */ + /*数组0: 本地控制云台*/ + /*数组1: 本地手动录象*/ + /*数组2: 本地回放*/ + /*数组3: 本地设置参数*/ + /*数组4: 本地查看状态、日志*/ + /*数组5: 本地高级操作(升级,格式化,重启,关机)*/ + /*数组6: 本地查看参数 */ + /*数组7: 本地管理模拟和IP camera */ + /*数组8: 本地备份 */ + /*数组9: 本地关机/重启 */ + public byte[] byRemoteRight = new byte[MAX_RIGHT];/* 远程权限 */ + /*数组0: 远程控制云台*/ + /*数组1: 远程手动录象*/ + /*数组2: 远程回放 */ + /*数组3: 远程设置参数*/ + /*数组4: 远程查看状态、日志*/ + /*数组5: 远程高级操作(升级,格式化,重启,关机)*/ + /*数组6: 远程发起语音对讲*/ + /*数组7: 远程预览*/ + /*数组8: 远程请求报警上传、报警输出*/ + /*数组9: 远程控制,本地输出*/ + /*数组10: 远程控制串口*/ + /*数组11: 远程查看参数 */ + /*数组12: 远程管理模拟和IP camera */ + /*数组13: 远程关机/重启 */ + public byte[] byNetPreviewRight = new byte[MAX_CHANNUM_V30]; /* 远程可以预览的通道 0-有权限,1-无权限*/ + public byte[] byLocalPlaybackRight = new byte[MAX_CHANNUM_V30]; /* 本地可以回放的通道 0-有权限,1-无权限*/ + public byte[] byNetPlaybackRight = new byte[MAX_CHANNUM_V30]; /* 远程可以回放的通道 0-有权限,1-无权限*/ + public byte[] byLocalRecordRight = new byte[MAX_CHANNUM_V30]; /* 本地可以录像的通道 0-有权限,1-无权限*/ + public byte[] byNetRecordRight = new byte[MAX_CHANNUM_V30]; /* 远程可以录像的通道 0-有权限,1-无权限*/ + public byte[] byLocalPTZRight = new byte[MAX_CHANNUM_V30]; /* 本地可以PTZ的通道 0-有权限,1-无权限*/ + public byte[] byNetPTZRight = new byte[MAX_CHANNUM_V30]; /* 远程可以PTZ的通道 0-有权限,1-无权限*/ + public byte[] byLocalBackupRight = new byte[MAX_CHANNUM_V30]; /* 本地备份权限通道 0-有权限,1-无权限*/ + public NET_DVR_IPADDR struUserIP; /* 用户IP地址(为0时表示允许任何地址) */ + public byte[] byMACAddr = new byte[MACADDR_LEN]; /* 物理地址 */ + public byte byPriority; /* 优先级,0xff-无,0--低,1--中,2--高 */ + /* + 无……表示不支持优先级的设置 + 低……默认权限:包括本地和远程回放,本地和远程查看日志和状态,本地和远程关机/重启 + 中……包括本地和远程控制云台,本地和远程手动录像,本地和远程回放,语音对讲和远程预览 + 本地备份,本地/远程关机/重启 + 高……管理员 + */ + public byte[] byRes = new byte[17]; + } + + public static class NET_DVR_USER_INFO_EX extends HIKSDKStructure {//单用户参数(SDK_V15扩展)(子结构) + public byte[] sUserName = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public int[] dwLocalRight = new int[MAX_RIGHT]; /* 权限 */ + /*数组0: 本地控制云台*/ + /*数组1: 本地手动录象*/ + /*数组2: 本地回放*/ + /*数组3: 本地设置参数*/ + /*数组4: 本地查看状态、日志*/ + /*数组5: 本地高级操作(升级,格式化,重启,关机)*/ + public int dwLocalPlaybackRight; /* 本地可以回放的通道 bit0 -- channel 1*/ + public int[] dwRemoteRight = new int[MAX_RIGHT]; /* 权限 */ + /*数组0: 远程控制云台*/ + /*数组1: 远程手动录象*/ + /*数组2: 远程回放 */ + /*数组3: 远程设置参数*/ + /*数组4: 远程查看状态、日志*/ + /*数组5: 远程高级操作(升级,格式化,重启,关机)*/ + /*数组6: 远程发起语音对讲*/ + /*数组7: 远程预览*/ + /*数组8: 远程请求报警上传、报警输出*/ + /*数组9: 远程控制,本地输出*/ + /*数组10: 远程控制串口*/ + public int dwNetPreviewRight; /* 远程可以预览的通道 bit0 -- channel 1*/ + public int dwNetPlaybackRight; /* 远程可以回放的通道 bit0 -- channel 1*/ + public byte[] sUserIP = new byte[16]; /* 用户IP地址(为0时表示允许任何地址) */ + public byte[] byMACAddr = new byte[MACADDR_LEN]; /* 物理地址 */ + } + + public static class NET_DVR_USER_INFO extends HIKSDKStructure {//单用户参数(子结构) + public byte[] sUserName = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public int[] dwLocalRight = new int[MAX_RIGHT]; /* 权限 */ + /*数组0: 本地控制云台*/ + /*数组1: 本地手动录象*/ + /*数组2: 本地回放*/ + /*数组3: 本地设置参数*/ + /*数组4: 本地查看状态、日志*/ + /*数组5: 本地高级操作(升级,格式化,重启,关机)*/ + public int[] dwRemoteRight = new int[MAX_RIGHT]; /* 权限 */ + /*数组0: 远程控制云台*/ + /*数组1: 远程手动录象*/ + /*数组2: 远程回放 */ + /*数组3: 远程设置参数*/ + /*数组4: 远程查看状态、日志*/ + /*数组5: 远程高级操作(升级,格式化,重启,关机)*/ + /*数组6: 远程发起语音对讲*/ + /*数组7: 远程预览*/ + /*数组8: 远程请求报警上传、报警输出*/ + /*数组9: 远程控制,本地输出*/ + /*数组10: 远程控制串口*/ + public byte[] sUserIP = new byte[16]; /* 用户IP地址(为0时表示允许任何地址) */ + public byte[] byMACAddr = new byte[MACADDR_LEN]; /* 物理地址 */ + } + + public static class NET_DVR_USER_V30 extends HIKSDKStructure {//DVR用户参数(9000扩展) + public int dwSize; + public NET_DVR_USER_INFO_V30[] struUser = new NET_DVR_USER_INFO_V30[MAX_USERNUM_V30]; + } + + public static class NET_DVR_USER_EX extends HIKSDKStructure {//DVR用户参数(SDK_V15扩展) + public int dwSize; + public NET_DVR_USER_INFO_EX[] struUser = new NET_DVR_USER_INFO_EX[MAX_USERNUM]; + } + + public static class NET_DVR_USER extends HIKSDKStructure {//DVR用户参数 + public int dwSize; + public NET_DVR_USER_INFO[] struUser = new NET_DVR_USER_INFO[MAX_USERNUM]; + } + + public static class NET_DVR_EXCEPTION_V30 extends HIKSDKStructure {//DVR异常参数(9000扩展) + public int dwSize; + public NET_DVR_HANDLEEXCEPTION_V30[] struExceptionHandleType = new NET_DVR_HANDLEEXCEPTION_V30[MAX_EXCEPTIONNUM_V30]; + /*数组0-盘满,1- 硬盘出错,2-网线断,3-局域网内IP 地址冲突,4-非法访问, 5-输入/输出视频制式不匹配, 6-行车超速(车载专用), 7-视频信号异常(9000)*/ + } + + public static class NET_DVR_EXCEPTION extends HIKSDKStructure {//DVR异常参数 + public int dwSize; + public NET_DVR_HANDLEEXCEPTION[] struExceptionHandleType = new NET_DVR_HANDLEEXCEPTION[MAX_EXCEPTIONNUM]; + /*数组0-盘满,1- 硬盘出错,2-网线断,3-局域网内IP 地址冲突,4-非法访问, 5-输入/输出视频制式不匹配, 6-行车超速(车载专用)*/ + } + + public static class NET_DVR_CHANNELSTATE_V30 extends HIKSDKStructure {//通道状态(9000扩展) + public byte byRecordStatic; //通道是否在录像,0-不录像,1-录像 + public byte bySignalStatic; //连接的信号状态,0-正常,1-信号丢失 + public byte byHardwareStatic;//通道硬件状态,0-正常,1-异常,例如DSP死掉 + public byte byRes1; //保留 + public int dwBitRate;//实际码率 + public int dwLinkNum;//客户端连接的个数 + public NET_DVR_IPADDR[] struClientIP = new NET_DVR_IPADDR[MAX_LINK];//客户端的IP地址 + public int dwIPLinkNum;//如果该通道为IP接入,那么表示IP接入当前的连接数 + public byte byExceedMaxLink; // 是否超出了单路6路连接数 0 - 未超出, 1-超出 + public byte[] byRes = new byte[3]; // 保留字节 + public int dwAllBitRate; //所有实际码率之和 + public int dwChannelNo; //当前的通道号,0xffffffff表示无效 + } + + public static class NET_DVR_CHANNELSTATE extends HIKSDKStructure {//通道状态 + public byte byRecordStatic; //通道是否在录像,0-不录像,1-录像 + public byte bySignalStatic; //连接的信号状态,0-正常,1-信号丢失 + public byte byHardwareStatic;//通道硬件状态,0-正常,1-异常,例如DSP死掉 + public byte reservedData; //保留 + public int dwBitRate;//实际码率 + public int dwLinkNum;//客户端连接的个数 + public int[] dwClientIP = new int[MAX_LINK];//客户端的IP地址 + } + + public static class NET_DVR_DISKSTATE extends HIKSDKStructure {//硬盘状态 + public int dwVolume;//硬盘的容量 + public int dwFreeSpace;//硬盘的剩余空间 + public int dwHardDiskStatic; //硬盘的状态,按位:1-休眠,2-不正常,3-休眠硬盘出错 + } + + public static class NET_DVR_WORKSTATE_V30 extends HIKSDKStructure {//DVR工作状态(9000扩展) + public int dwDeviceStatic; //设备的状态,0-正常,1-CPU占用率太高,超过85%,2-硬件错误,例如串口死掉 + public NET_DVR_DISKSTATE[] struHardDiskStatic = new NET_DVR_DISKSTATE[MAX_DISKNUM_V30]; + public NET_DVR_CHANNELSTATE_V30[] struChanStatic = new NET_DVR_CHANNELSTATE_V30[MAX_CHANNUM_V30];//通道的状态 + public byte[] byAlarmInStatic = new byte[MAX_ALARMIN_V30]; //报警端口的状态,0-没有报警,1-有报警 + public byte[] byAlarmOutStatic = new byte[MAX_ALARMOUT_V30]; //报警输出端口的状态,0-没有输出,1-有报警输出 + public int dwLocalDisplay;//本地显示状态,0-正常,1-不正常 + public byte[] byAudioChanStatus = new byte[MAX_AUDIO_V30];//表示语音通道的状态 0-未使用,1-使用中, 0xff无效 + public byte[] byRes = new byte[10]; + } + + public static class NET_DVR_WORKSTATE extends HIKSDKStructure {//DVR工作状态 + public int dwDeviceStatic; //设备的状态,0-正常,1-CPU占用率太高,超过85%,2-硬件错误,例如串口死掉 + public NET_DVR_DISKSTATE[] struHardDiskStatic = new NET_DVR_DISKSTATE[MAX_DISKNUM]; + public NET_DVR_CHANNELSTATE[] struChanStatic = new NET_DVR_CHANNELSTATE[MAX_CHANNUM];//通道的状态 + public byte[] byAlarmInStatic = new byte[MAX_ALARMIN]; //报警端口的状态,0-没有报警,1-有报警 + public byte[] byAlarmOutStatic = new byte[MAX_ALARMOUT]; //报警输出端口的状态,0-没有输出,1-有报警输出 + public int dwLocalDisplay;//本地显示状态,0-正常,1-不正常 + } + + public static class NET_DVR_LOG_V30 extends HIKSDKStructure {//日志信息(9000扩展) + public NET_DVR_TIME strLogTime; + public int dwMajorType; //主类型 1-报警; 2-异常; 3-操作; 0xff-全部 + public int dwMinorType;//次类型 0-全部; + public byte[] sPanelUser = new byte[MAX_NAMELEN]; //操作面板的用户名 + public byte[] sNetUser = new byte[MAX_NAMELEN];//网络操作的用户名 + public NET_DVR_IPADDR struRemoteHostAddr;//??程主机地址 + public int dwParaType;//参数类型 + public int dwChannel;//通道号 + public int dwDiskNumber;//硬盘号 + public int dwAlarmInPort;//报警输入端口 + public int dwAlarmOutPort;//报警输出端口 + public int dwInfoLen; + public byte[] sInfo = new byte[LOG_INFO_LEN]; + } + + //日志信息 + public static class NET_DVR_LOG extends HIKSDKStructure { + public NET_DVR_TIME strLogTime; + public int dwMajorType; //主类型 1-报警; 2-异常; 3-操作; 0xff-全部 + public int dwMinorType;//次类型 0-全部; + public byte[] sPanelUser = new byte[MAX_NAMELEN]; //操作面板的用户名 + public byte[] sNetUser = new byte[MAX_NAMELEN];//网络操作的用户名 + public byte[] sRemoteHostAddr = new byte[16];//远程主机地址 + public int dwParaType;//参数类型 + public int dwChannel;//通道号 + public int dwDiskNumber;//硬盘号 + public int dwAlarmInPort;//报警输入端口 + public int dwAlarmOutPort;//报警输出端口 + } + + /************************ + * DVR日志 end + ***************************/ + public static class NET_DVR_ALARMOUTSTATUS_V30 extends HIKSDKStructure {//报警输出状态(9000扩展) + public byte[] Output = new byte[MAX_ALARMOUT_V30]; + } + + public static class NET_DVR_ALARMOUTSTATUS extends HIKSDKStructure {//报警输出状态 + public byte[] Output = new byte[MAX_ALARMOUT]; + } + + public static class NET_DVR_TRADEINFO extends HIKSDKStructure {//交易信息 + public short m_Year; + public short m_Month; + public short m_Day; + public short m_Hour; + public short m_Minute; + public short m_Second; + public byte[] DeviceName = new byte[24]; //设备名称 + public int dwChannelNumer; //通道号 + public byte[] CardNumber = new byte[32]; //卡号 + public byte[] cTradeType = new byte[12]; //交易类型 + public int dwCash; //交易金额 + } + + public static class NET_DVR_FRAMETYPECODE extends HIKSDKStructure {/*帧格式*/ + public byte[] code = new byte[12]; /* 代码 */ + } + + public static class NET_DVR_FRAMEFORMAT_V30 extends HIKSDKStructure {//ATM参数(9000扩展) + public int dwSize; + public NET_DVR_IPADDR struATMIP; /* ATM IP地址 */ + public int dwATMType; /* ATM类型 */ + public int dwInputMode; /* 输入方式 0-网络侦听 1-网络接收 2-串口直接输入 3-串口ATM命令输入*/ + public int dwFrameSignBeginPos; /* 报文标志位的起始位置*/ + public int dwFrameSignLength; /* 报文标志位的长度 */ + public byte[] byFrameSignContent = new byte[12]; /* 报文标志位的内容 */ + public int dwCardLengthInfoBeginPos; /* 卡号长度信息的起始位置 */ + public int dwCardLengthInfoLength; /* 卡号长度信息的长度 */ + public int dwCardNumberInfoBeginPos; /* 卡号信息的起始位置 */ + public int dwCardNumberInfoLength; /* 卡号信息的长度 */ + public int dwBusinessTypeBeginPos; /* 交易类型的起始位置 */ + public int dwBusinessTypeLength; /* 交易类型的长度 */ + public NET_DVR_FRAMETYPECODE[] frameTypeCode = new NET_DVR_FRAMETYPECODE[10]; /* 类型 */ + public short wATMPort; /* 卡号捕捉端口号(网络协议方式) (保留)0xffff表示该值无效*/ + public short wProtocolType; /* 网络协议类型(保留) 0xffff表示该值无效*/ + public byte[] byRes = new byte[24]; + } + + public static class NET_DVR_FRAMEFORMAT extends HIKSDKStructure {//ATM参数 + public int dwSize; + public byte[] sATMIP = new byte[16]; /* ATM IP地址 */ + public int dwATMType; /* ATM类型 */ + public int dwInputMode; /* 输入方式 0-网络侦听 1-网络接收 2-串口直接输入 3-串口ATM命令输入*/ + public int dwFrameSignBeginPos; /* 报文标志位的起始位置*/ + public int dwFrameSignLength; /* 报文标志位的长度 */ + public byte[] byFrameSignContent = new byte[12]; /* 报文标志位的内容 */ + public int dwCardLengthInfoBeginPos; /* 卡号长度信息的起始位置 */ + public int dwCardLengthInfoLength; /* 卡号长度信息的长度 */ + public int dwCardNumberInfoBeginPos; /* 卡号信息的起始位置 */ + public int dwCardNumberInfoLength; /* 卡号信息的长度 */ + public int dwBusinessTypeBeginPos; /* 交易类型的起始位置 */ + public int dwBusinessTypeLength; /* 交易类型的长度 */ + public NET_DVR_FRAMETYPECODE[] frameTypeCode = new NET_DVR_FRAMETYPECODE[10];/* 类型 */ + } + + public static class NET_DVR_FTPTYPECODE extends HIKSDKStructure { + public byte[] sFtpType = new byte[32]; /*客户定义的操作类型*/ + public byte[] sFtpCode = new byte[8]; /*客户定义的操作类型的对应的码*/ + } + + public static class NET_DVR_FRAMEFORMAT_EX extends HIKSDKStructure {//ATM参数添加FTP上传参数, 银行定制, 2006-11-17 + public int dwSize; + public byte[] sATMIP = new byte[16]; /* ATM IP地址 */ + public int dwATMType; /* ATM类型 */ + public int dwInputMode; /* 输入方式 0-网络侦听 1-网络接收 2-串口直接输入 3-串口ATM命令输入*/ + public int dwFrameSignBeginPos; /* 报文标志位的起始位置*/ + public int dwFrameSignLength; /* 报文标志位的长度 */ + public byte[] byFrameSignContent = new byte[12]; /* 报文标志位的内容 */ + public int dwCardLengthInfoBeginPos; /* 卡号长度信息的起始位置 */ + public int dwCardLengthInfoLength; /* 卡号长度信息的长度 */ + public int dwCardNumberInfoBeginPos; /* 卡号信息的起始位置 */ + public int dwCardNumberInfoLength; /* 卡号信息的长度 */ + public int dwBusinessTypeBeginPos; /* 交易类型的起始位置 */ + public int dwBusinessTypeLength; /* 交易类型的长度 */ + public NET_DVR_FRAMETYPECODE[] frameTypeCode = new NET_DVR_FRAMETYPECODE[10];/* 类型 */ + public byte[] sFTPIP = new byte[16]; /* FTP IP */ + public byte[] byFtpUsername = new byte[NAME_LEN]; /* 用户名 */ + public byte[] byFtpPasswd = new byte[PASSWD_LEN]; /* 密码 */ + public byte[] sDirName = new byte[NAME_LEN]; /*服务器目录名*/ + public int dwATMSrvType; /*ATM服务器类型,0--wincor ,1--diebold*/ + public int dwTimeSpace; /*取值为1.2.3.4.5.10*/ + public NET_DVR_FTPTYPECODE[] sFtpTypeCodeOp = new NET_DVR_FTPTYPECODE[300]; /*新加的*/ + public int dwADPlay; /* 1 表示在播放广告,0 表示没有播放广告*/ + public int dwNewPort; //端口 + } +/****************************ATM(end)***************************/ + + /***************************** + * DS-6001D/F(begin) + ***************************/ +//DS-6001D Decoder + public static class NET_DVR_DECODERINFO extends HIKSDKStructure { + public byte[] byEncoderIP = new byte[16]; //解码设备连接的服务器IP + public byte[] byEncoderUser = new byte[16]; //解码设备连接的服务器的用户名 + public byte[] byEncoderPasswd = new byte[16]; //解码设备连接的服务器的密码 + public byte bySendMode; //解码设备连接服务器的连接模式 + public byte byEncoderChannel; //解码设备连接的服务器的通道号 + public short wEncoderPort; //解码设备连接的服务器的端口号 + public byte[] reservedData = new byte[4]; //保留 + } + + public static class NET_DVR_DECODERSTATE extends HIKSDKStructure { + public byte[] byEncoderIP = new byte[16]; //解码设备连接的服务器IP + public byte[] byEncoderUser = new byte[16]; //解码设备连接的服务器的用户名 + public byte[] byEncoderPasswd = new byte[16]; //解码设备连接的服务器的密码 + public byte byEncoderChannel; //解码设备连接的服务器的通道号 + public byte bySendMode; //解码设备连接的服务器的连接模式 + public short wEncoderPort; //解码设备连接的服务器的端口号 + public int dwConnectState; //解码设备连接服务器的状态 + public byte[] reservedData = new byte[4]; //保留 + } + + public static class NET_DVR_DECCHANINFO extends HIKSDKStructure { + public byte[] sDVRIP = new byte[16]; /* DVR IP地址 */ + public short wDVRPort; /* 端口号 */ + public byte[] sUserName = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public byte byChannel; /* 通道号 */ + public byte byLinkMode; /* 连接模式 */ + public byte byLinkType; /* 连接类型 0-主码流 1-子码流 */ + } + + public static class NET_DVR_DECINFO extends HIKSDKStructure {/*每个解码通道的配置*/ + public byte byPoolChans; /*每路解码通道上的循环通道数量, 最多4通道 0表示没有解码*/ + public NET_DVR_DECCHANINFO[] struchanConInfo = new NET_DVR_DECCHANINFO[MAX_DECPOOLNUM]; + public byte byEnablePoll; /*是否轮巡 0-否 1-是*/ + public byte byPoolTime; /*轮巡时间 0-保留 1-10秒 2-15秒 3-20秒 4-30秒 5-45秒 6-1分钟 7-2分钟 8-5分钟 */ + } + + public static class NET_DVR_DECCFG extends HIKSDKStructure {/*整个设备解码配置*/ + public int dwSize; + public int dwDecChanNum; /*解码通道的数量*/ + public NET_DVR_DECINFO[] struDecInfo = new NET_DVR_DECINFO[MAX_DECNUM]; + } + + //2005-08-01 + public static class NET_DVR_PORTINFO extends HIKSDKStructure {/* 解码设备透明通道设置 */ + public int dwEnableTransPort; /* 是否启动透明通道 0-不启用 1-启用*/ + public byte[] sDecoderIP = new byte[16]; /* DVR IP地址 */ + public short wDecoderPort; /* 端口号 */ + public short wDVRTransPort; /* 配置前端DVR是从485/232输出,1表示232串口,2表示485串口 */ + public byte[] cReserve = new byte[4]; + } + + public static class NET_DVR_PORTCFG extends HIKSDKStructure { + public int dwSize; + public NET_DVR_PORTINFO[] struTransPortInfo = new NET_DVR_PORTINFO[MAX_TRANSPARENTNUM]; /* 数组0表示232 数组1表示485 */ + } + + /*https://jna.dev.java.net/javadoc/com/sun/jna/Union.html#setType(java.lang.Class) see how to use the JNA Union*/ + public static class NET_DVR_PLAYREMOTEFILE extends HIKSDKStructure {/* 控制网络文件回放 */ + public int dwSize; + public byte[] sDecoderIP = new byte[16]; /* DVR IP地址 */ + public short wDecoderPort; /* 端口号 */ + public short wLoadMode; /* 回放下载模式 1-按名字 2-按时间 */ + public byte[] byFile = new byte[100]; + + public static class mode_size extends Union { + public byte[] byFile = new byte[100]; // 回放的文件名 + + public static class bytime extends HIKSDKStructure { + public int dwChannel; + public byte[] sUserName = new byte[NAME_LEN]; //请求视频用户名 + public byte[] sPassword = new byte[PASSWD_LEN]; // 密码 + public NET_DVR_TIME struStartTime; //按时间回放的开始时间 + public NET_DVR_TIME struStopTime; // 按时间回放的结束时间 + } + } + } + + public static class NET_DVR_DECCHANSTATUS extends HIKSDKStructure {/*当前设备解码连接状态*/ + public int dwWorkType; /*工作方式:1:轮巡、2:动态连接解码、3:文件回放下载 4:按时间回放下载*/ + public byte[] sDVRIP = new byte[16]; /*连接的设备ip*/ + public short wDVRPort; /*连接端口号*/ + public byte byChannel; /* 通道号 */ + public byte byLinkMode; /* 连接模式 */ + public int dwLinkType; /*连接类型 0-主码流 1-子码流*/ + public byte[] sUserName = new byte[NAME_LEN]; /*请求视频用户名*/ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public byte[] cReserve = new byte[52]; + + public static class objectInfo extends Union { + public static class userInfo extends HIKSDKStructure { + public byte[] sUserName = new byte[NAME_LEN]; //请求视频用户名 + public byte[] sPassword = new byte[PASSWD_LEN]; // 密码 + public byte[] cReserve = new byte[52]; + } + + public static class fileInfo extends HIKSDKStructure { + public byte[] fileName = new byte[100]; + } + + public static class timeInfo extends HIKSDKStructure { + public int dwChannel; + public byte[] sUserName = new byte[NAME_LEN]; //请求视频用户名 + public byte[] sPassword = new byte[PASSWD_LEN]; // 密码 + public NET_DVR_TIME struStartTime; // 按时间回放的开始时间 + public NET_DVR_TIME struStopTime; //按时间回放的结束时间 + } + } + } + + public static class NET_DVR_DECSTATUS extends HIKSDKStructure { + public int dwSize; + public NET_DVR_DECCHANSTATUS[] struDecState = new NET_DVR_DECCHANSTATUS[MAX_DECNUM]; + } + + /***************************** + * DS-6001D/F(end) + ***************************/ + + public static class NET_DVR_SHOWSTRINGINFO extends HIKSDKStructure {//单字符参数(子结构) + public short wShowString; // 预览的图象上是否显示字符,0-不显示,1-显示 区域大小704*576,单个字符的大小为32*32 + public short wStringSize; /* 该行字符的长度,不能大于44个字符 */ + public short wShowStringTopLeftX; /* 字符显示位置的x坐标 */ + public short wShowStringTopLeftY; /* 字符名称显示位置的y坐标 */ + public byte[] sString = new byte[44]; /* 要显示的字符内容 */ + } + + //叠加字符(9000扩展) + public static class NET_DVR_SHOWSTRING_V30 extends HIKSDKStructure { + public int dwSize; + public NET_DVR_SHOWSTRINGINFO[] struStringInfo = new NET_DVR_SHOWSTRINGINFO[MAX_STRINGNUM_V30]; /* 要显示的字符内容 */ + } + + //叠加字符扩展(8条字符) + public static class NET_DVR_SHOWSTRING_EX extends HIKSDKStructure { + public int dwSize; + public NET_DVR_SHOWSTRINGINFO[] struStringInfo = new NET_DVR_SHOWSTRINGINFO[MAX_STRINGNUM_EX]; /* 要显示的字符内容 */ + } + + //叠加字符 + public static class NET_DVR_SHOWSTRING extends HIKSDKStructure { + public int dwSize; + public NET_DVR_SHOWSTRINGINFO[] struStringInfo = new NET_DVR_SHOWSTRINGINFO[MAX_STRINGNUM]; /* 要显示的字符内容 */ + } + + /**************************** + * DS9000新增结构(begin) + ******************************/ + +/* +EMAIL参数结构 +*/ + public static class NET_DVR_SENDER extends HIKSDKStructure { + public byte[] sName = new byte[NAME_LEN]; /* 发件人姓名 */ + public byte[] sAddress = new byte[MAX_EMAIL_ADDR_LEN]; /* 发件人地址 */ + } + + public static class NET_DVRRECEIVER extends HIKSDKStructure { + public byte[] sName = new byte[NAME_LEN]; /* 收件人姓名 */ + public byte[] sAddress = new byte[MAX_EMAIL_ADDR_LEN]; /* 收件人地址 */ + } + + public static class NET_DVR_EMAILCFG_V30 extends HIKSDKStructure { + public int dwSize; + public byte[] sAccount = new byte[NAME_LEN]; /* 账号*/ + public byte[] sPassword = new byte[MAX_EMAIL_PWD_LEN]; /*密码 */ + public NET_DVR_SENDER struSender; + public byte[] sSmtpServer = new byte[MAX_EMAIL_ADDR_LEN]; /* smtp服务器 */ + public byte[] sPop3Server = new byte[MAX_EMAIL_ADDR_LEN]; /* pop3服务器 */ + public NET_DVRRECEIVER[] struReceiver = new NET_DVRRECEIVER[3]; /* 最多可以设置3个收件人 */ + public byte byAttachment; /* 是否带附件 */ + public byte bySmtpServerVerify; /* 发送服务器要求身份验证 */ + public byte byMailInterval; /* mail interval */ + public byte[] res = new byte[77]; + } + + /* +DVR实现巡航数据结构 +*/ + public static class NET_DVR_CRUISE_PARA extends HIKSDKStructure { + public int dwSize; + public byte[] byPresetNo = new byte[CRUISE_MAX_PRESET_NUMS]; /* 预置点号 */ + public byte[] byCruiseSpeed = new byte[CRUISE_MAX_PRESET_NUMS]; /* 巡航速度 */ + public short[] wDwellTime = new short[CRUISE_MAX_PRESET_NUMS]; /* 停留时间 */ + public byte[] byEnableThisCruise; /* 是否启用 */ + public byte[] res = new byte[15]; + } + + /**************************** + * DS9000新增结构(end) + ******************************/ + +//时间点 + public static class NET_DVR_TIMEPOINT extends HIKSDKStructure { + public int dwMonth; //月 0-11表示1-12个月 + public int dwWeekNo; //第几周 0-第1周 1-第2周 2-第3周 3-第4周 4-最后一周 + public int dwWeekDate; //星期几 0-星期日 1-星期一 2-星期二 3-星期三 4-星期四 5-星期五 6-星期六 + public int dwHour; //小时 开始时间0-23 结束时间1-23 + public int dwMin; //分 0-59 + } + + //夏令时参数 + public static class NET_DVR_ZONEANDDST extends HIKSDKStructure { + public int dwSize; + public byte[] byRes1 = new byte[16]; //保留 + public int dwEnableDST; //是否启用夏时制 0-不启用 1-启用 + public byte byDSTBias; //夏令时偏移值,30min, 60min, 90min, 120min, 以分钟计,传递原始数值 + public byte[] byRes2 = new byte[3]; + public NET_DVR_TIMEPOINT struBeginPoint; //夏时制开始时间 + public NET_DVR_TIMEPOINT struEndPoint; //夏时制停止时间 + } + + //图片质量 + public static class NET_DVR_JPEGPARA extends HIKSDKStructure { + /*注意:当图像压缩分辨率为VGA时,支持0=CIF, 1=QCIF, 2=D1抓图, + 当分辨率为3=UXGA(1600x1200), 4=SVGA(800x600), 5=HD720p(1280x720),6=VGA,7=XVGA, 8=HD900p + 仅支持当前分辨率的抓图*/ + public short wPicSize; /* 0=CIF, 1=QCIF, 2=D1 3=UXGA(1600x1200), 4=SVGA(800x600), 5=HD720p(1280x720),6=VGA*/ + public short wPicQuality; /* 图片质量系数 0-最好 1-较好 2-一般 */ + @Override + protected List getFieldOrder() { + return Arrays.asList( + "wPicSize", + "wPicQuality" + ); + } + } + + /* aux video out parameter */ +//辅助输出参数配置 + public static class NET_DVR_AUXOUTCFG extends HIKSDKStructure { + public int dwSize; + public int dwAlarmOutChan; /* 选择报警弹出大报警通道切换时间:1画面的输出通道: 0:主输出/1:辅1/2:辅2/3:辅3/4:辅4 */ + public int dwAlarmChanSwitchTime; /* :1秒 - 10:10秒 */ + public int[] dwAuxSwitchTime = new int[MAX_AUXOUT]; /* 辅助输出切换时间: 0-不切换,1-5s,2-10s,3-20s,4-30s,5-60s,6-120s,7-300s */ + public byte[][] byAuxOrder = new byte[MAX_AUXOUT][MAX_WINDOW]; /* 辅助输出预览顺序, 0xff表示相应的窗口不预览 */ + } + + //ntp + public static class NET_DVR_NTPPARA extends HIKSDKStructure { + public byte[] sNTPServer = new byte[64]; /* Domain Name or IP addr of NTP server */ + public short wInterval; /* adjust time interval(hours) */ + public byte byEnableNTP; /* enable NPT client 0-no,1-yes*/ + public byte cTimeDifferenceH; /* 与国际标准时间的 小时偏移-12 ... +13 */ + public byte cTimeDifferenceM;/* 与国际标准时间的 分钟偏移0, 30, 45*/ + public byte res1; + public short wNtpPort; /* ntp server port 9000新增 设备默认为123*/ + public byte[] res2 = new byte[8]; + } + + //ddns + public static class NET_DVR_DDNSPARA extends HIKSDKStructure { + public byte[] sUsername = new byte[NAME_LEN]; /* DDNS账号用户名/密码 */ + public byte[] sPassword = new byte[PASSWD_LEN]; + public byte[] sDomainName = new byte[64]; /* 域名 */ + public byte byEnableDDNS; /*是否应用 0-否,1-是*/ + public byte[] res = new byte[15]; + } + + public static class NET_DVR_DDNSPARA_EX extends HIKSDKStructure { + public byte byHostIndex; /* 0-Hikvision DNS 1-Dyndns 2-PeanutHull(花生壳), 3-希网3322*/ + public byte byEnableDDNS; /*是否应用DDNS 0-否,1-是*/ + public short wDDNSPort; /* DDNS端口号 */ + public byte[] sUsername = new byte[NAME_LEN]; /* DDNS用户名*/ + public byte[] sPassword = new byte[PASSWD_LEN]; /* DDNS密码 */ + public byte[] sDomainName = new byte[MAX_DOMAIN_NAME]; /* 设备配备的域名地址 */ + public byte[] sServerName = new byte[MAX_DOMAIN_NAME]; /* DDNS 对应的服务器地址,可以是IP地址或域名 */ + public byte[] byRes = new byte[16]; + } + + public static class NET_DVR_DDNS extends HIKSDKStructure { + public byte[] sUsername = new byte[NAME_LEN]; /* DDNS账号用户名*/ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public byte[] sDomainName = new byte[MAX_DOMAIN_NAME]; /* 设备配备的域名地址 */ + public byte[] sServerName = new byte[MAX_DOMAIN_NAME]; /* DDNS协议对应的服务器地址,可以是IP地址或域名 */ + public short wDDNSPort; /* 端口号 */ + public byte[] byRes = new byte[10]; + } + + //9000扩展 + public static class NET_DVR_DDNSPARA_V30 extends HIKSDKStructure { + public byte byEnableDDNS; + public byte byHostIndex;/* 0-Hikvision DNS(保留) 1-Dyndns 2-PeanutHull(花生壳) 3-希网3322 */ + public byte[] byRes1 = new byte[2]; + public NET_DVR_DDNS[] struDDNS = new NET_DVR_DDNS[MAX_DDNS_NUMS];//9000目前只支持前3个配置,其他配置保留 + public byte[] byRes2 = new byte[16]; + } + + //email + public static class NET_DVR_EMAILPARA extends HIKSDKStructure { + public byte[] sUsername = new byte[64]; /* 邮件账号/密码 */ + public byte[] sPassword = new byte[64]; + public byte[] sSmtpServer = new byte[64]; + public byte[] sPop3Server = new byte[64]; + public byte[] sMailAddr = new byte[64]; /* email */ + public byte[] sEventMailAddr1 = new byte[64]; /* 上传报警/异常等的email */ + public byte[] sEventMailAddr2 = new byte[64]; + public byte[] res = new byte[16]; + } + + public static class NET_DVR_NETAPPCFG extends HIKSDKStructure {//网络参数配置 + public int dwSize; + public byte[] sDNSIp = new byte[16]; /* DNS服务器地址 */ + public NET_DVR_NTPPARA struNtpClientParam; /* NTP参数 */ + public NET_DVR_DDNSPARA struDDNSClientParam; /* DDNS参数 */ + //NET_DVR_EMAILPARA struEmailParam; /* EMAIL参数 */ + public byte[] res = new byte[464]; /* 保留 */ + } + + public static class NET_DVR_SINGLE_NFS extends HIKSDKStructure {//nfs结构配置 + public byte[] sNfsHostIPAddr = new byte[16]; + public byte[] sNfsDirectory = new byte[PATHNAME_LEN]; // PATHNAME_LEN = 128 + } + + public static class NET_DVR_NFSCFG extends HIKSDKStructure { + public int dwSize; + public NET_DVR_SINGLE_NFS[] struNfsDiskParam = new NET_DVR_SINGLE_NFS[MAX_NFS_DISK]; + } + + //巡航点配置(HIK IP快球专用) + public static class NET_DVR_CRUISE_POINT extends HIKSDKStructure { + public byte PresetNum; //预置点 + public byte Dwell; //停留时间 + public byte Speed; //速度 + public byte Reserve; //保留 + } + + public static class NET_DVR_CRUISE_RET extends HIKSDKStructure { + public NET_DVR_CRUISE_POINT[] struCruisePoint = new NET_DVR_CRUISE_POINT[32]; //最大支持32个巡航点 + } + + /************************************ + * 多路解码器(begin) + ***************************************/ +//多路解码器扩展 added by zxy 2007-05-23 + public static class NET_DVR_NETCFG_OTHER extends HIKSDKStructure { + public int dwSize; + public byte[] sFirstDNSIP = new byte[16]; + public byte[] sSecondDNSIP = new byte[16]; + public byte[] sRes = new byte[32]; + } + + public static class NET_DVR_MATRIX_DECINFO extends HIKSDKStructure { + public byte[] sDVRIP = new byte[16]; /* DVR IP地址 */ + public short wDVRPort; /* 端口号 */ + public byte byChannel; /* 通道号 */ + public byte byTransProtocol; /* 传输协议类型 0-TCP 1-UDP */ + public byte byTransMode; /* 传输码流模式 0-主码流 1-子码流*/ + public byte[] byRes = new byte[3]; + public byte[] sUserName = new byte[NAME_LEN]; /* 布防主机登陆帐号 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 布防主机密码 */ + } + + public static class NET_DVR_MATRIX_DYNAMIC_DEC extends HIKSDKStructure {//启动/停止动态解码 + public int dwSize; + public NET_DVR_MATRIX_DECINFO struDecChanInfo; /* 动态解码通道信息 */ + } + + public static class NET_DVR_MATRIX_DEC_CHAN_STATUS extends HIKSDKStructure {//2007-12-13 modified by zxy 修改多路解码器的NET_DVR_MATRIX_DEC_CHAN_STATUS结构 + public int dwSize;//2008-1-16 modified by zxy dwIsLinked的状态由原来的0-未链接 1-连接修改成以下三种状态。 + public int dwIsLinked; /* 解码通道状态 0-休眠 1-正在连接 2-已连接 3-正在解码 */ + public int dwStreamCpRate; /* Stream copy rate, X kbits/second */ + public byte[] cRes = new byte[64]; /* 保留 */ + } +//end 2007-12-13 modified by zxy + + public static class NET_DVR_MATRIX_DEC_CHAN_INFO extends HIKSDKStructure { + public int dwSize; + public NET_DVR_MATRIX_DECINFO struDecChanInfo; /* 解码通道信息 */ + public int dwDecState; /* 0-动态解码 1-循环解码 2-按时间回放 3-按文件回放 */ + public NET_DVR_TIME StartTime; /* 按时间回放开始时间 */ + public NET_DVR_TIME StopTime; /* 按时间回放停止时间 */ + public byte[] sFileName = new byte[128]; /* 按文件回放文件名 */ + } + + //连接的通道配置 2007-11-05 + public static class NET_DVR_MATRIX_DECCHANINFO extends HIKSDKStructure { + public int dwEnable; /* 是否启用 0-否 1-启用*/ + public NET_DVR_MATRIX_DECINFO struDecChanInfo; /* 轮循解码通道信息 */ + } + + //2007-11-05 新增每个解码通道的配置 + public static class NET_DVR_MATRIX_LOOP_DECINFO extends HIKSDKStructure { + public int dwSize; + public int dwPoolTime; /*轮巡时间 */ + public NET_DVR_MATRIX_DECCHANINFO[] struchanConInfo = new NET_DVR_MATRIX_DECCHANINFO[MAX_CYCLE_CHAN]; + } + + //2007-05-25 多路解码器数字矩阵配置 +//矩阵行信息 2007-12-28 + public static class NET_DVR_MATRIX_ROW_ELEMENT extends HIKSDKStructure { + public byte[] sSurvChanName = new byte[128]; /* 布防通道名称,支持中文 */ + public int dwRowNum; /* 行号 */ + public NET_DVR_MATRIX_DECINFO struDecChanInfo; /* 矩阵行信息 */ + } + + public static class NET_DVR_MATRIX_ROW_INDEX extends HIKSDKStructure { + public byte[] sSurvChanName = new byte[128]; /* 布防通道名称,支持中文 */ + public int dwRowNum; /* 行号 */ + } + + //矩阵列信息 2007-12-28 + public static class NET_DVR_MATRIX_COLUMN_ELEMENT extends HIKSDKStructure { + public int dwLocalDispChanNum; /* 本地显示通道号 */ + public int dwGlobalDispChanNum; /* 全局显示通道号 */ + public int dwRes; /* 保留 */ + } + + public static class NET_DVR_MATRIX_GLOBAL_COLUMN_ELEMENT extends HIKSDKStructure { + public int dwConflictTag; /* 冲突标记,0:无冲突,1:冲突 */ + public int dwConflictGloDispChan; /* 与之冲突的全局通道号 */ + public NET_DVR_MATRIX_COLUMN_ELEMENT struColumnInfo;/* 矩阵列元素结构体 */ + } + + //手动查看 2007-12-28 + public static class NET_DVR_MATRIX_ROW_COLUMN_LINK extends HIKSDKStructure { + public int dwSize; + /* + * 以下三个参数只需要指定其中一个便可指定数字矩阵里的某一行 + * 所代表的远程布防通道。 + * 如果指定了多个域并有冲突,设备将按照域的先后顺序为准取最先定义者。 + */ + public int dwRowNum; /* -1代表无效域,大于0者方为有效的矩阵行号 */ + public byte[] sSurvChanName = new byte[128]; /* 布防通道名,是否无效按字符串的有效性判断 */ + public int dwSurvNum; /* 布防通道号,按矩阵行列表的顺序指定,一般情况下与行号一致 */ + /* + * 以下两项只需要指定其中一项便可,如果两项都有效默认选择第一项 + */ + public int dwGlobalDispChanNum; /* 电视墙上的电视机编号 */ + public int dwLocalDispChanNum; + /* + * 0代表播放即时码流, + * 1表示按时间回访远程布防设备的文件 + * 2表示按文件名回访 + */ + public int dwTimeSel; + public NET_DVR_TIME StartTime; + public NET_DVR_TIME StopTime; + public byte[] sFileName = new byte[128]; + } + + public static class NET_DVR_MATRIX_PREVIEW_DISP_CHAN extends HIKSDKStructure { + public int dwSize; + public int dwGlobalDispChanNum; /* 电视墙上的电视机编号 */ + public int dwLocalDispChanNum; /* 解码通道 */ + } + + public static class NET_DVR_MATRIX_LOOP_PLAY_SET extends HIKSDKStructure {//轮循功能 2007-12-28 + public int dwSize; + /* 任意指定一个,-1为无效,如果都指定则以LocalDispChanNum为准 */ + public int dwLocalDispChanNum; /* 解码通道 */ + public int dwGlobalDispChanNum; /* 电视墙上的电视机编号 */ + public int dwCycTimeInterval; /* 轮循时间间隔 */ + } + + public static class NET_DVR_MATRIX_LOCAL_HOST_INFO extends HIKSDKStructure {//矩阵中心配置 2007-12-28 + public int dwSize; + public int dwLocalHostProperty; /* 本地主机类型 0-服务器 1-客户端*/ + public int dwIsIsolated; /* 本地主机是否独立于系统,0:联网,1:独立 */ + public int dwLocalMatrixHostPort; /* 本地主机访问端口 */ + public byte[] byLocalMatrixHostUsrName = new byte[NAME_LEN]; /* 本地主机登录用户名 */ + public byte[] byLocalMatrixHostPasswd = new byte[PASSWD_LEN]; /* 本地主机登录密码 */ + public int dwLocalMatrixCtrlMedia; /* 控制方式 0x1串口键盘控制 0x2网络键盘控制 0x4矩阵中心控制 0x8PC客户端控制*/ + public byte[] sMatrixCenterIP = new byte[16]; /* 矩阵中心IP地址 */ + public int dwMatrixCenterPort; /* 矩阵中心端口号 */ + public byte[] byMatrixCenterUsrName = new byte[NAME_LEN]; /* 矩阵中心登录用户名 */ + public byte[] byMatrixCenterPasswd = new byte[PASSWD_LEN]; /* 矩阵中心登录密码 */ + } + + //2007-12-22 + public static class TTY_CONFIG extends HIKSDKStructure { + public byte baudrate; /* 波特率 */ + public byte databits; /* 数据位 */ + public byte stopbits; /* 停止位 */ + public byte parity; /* 奇偶校验位 */ + public byte flowcontrol; /* 流控 */ + public byte[] res = new byte[3]; + } + + public static class NET_DVR_MATRIX_TRAN_CHAN_INFO extends HIKSDKStructure { + public byte byTranChanEnable; /* 当前透明通道是否打开 0:关闭 1:打开 */ + /* + * 多路解码器本地有1个485串口,1个232串口都可以作为透明通道,设备号分配如下: + * 0 RS485 + * 1 RS232 Console + */ + public byte byLocalSerialDevice; /* Local serial device */ + /* + * 远程串口输出还是两个,一个RS232,一个RS485 + * 1表示232串口 + * 2表示485串口 + */ + public byte byRemoteSerialDevice; /* Remote output serial device */ + public byte res1; /* 保留 */ + public byte[] sRemoteDevIP = new byte[16]; /* Remote Device IP */ + public short wRemoteDevPort; /* Remote Net Communication Port */ + public byte[] res2 = new byte[2]; /* 保留 */ + public TTY_CONFIG RemoteSerialDevCfg; + } + + public static class NET_DVR_MATRIX_TRAN_CHAN_CONFIG extends HIKSDKStructure { + public int dwSize; + public byte by232IsDualChan; /* 设置哪路232透明通道是全双工的 取值1到MAX_SERIAL_NUM */ + public byte by485IsDualChan; /* 设置哪路485透明通道是全双工的 取值1到MAX_SERIAL_NUM */ + public byte[] res = new byte[2]; /* 保留 */ + public NET_DVR_MATRIX_TRAN_CHAN_INFO[] struTranInfo = new NET_DVR_MATRIX_TRAN_CHAN_INFO[MAX_SERIAL_NUM];/*同时支持建立MAX_SERIAL_NUM个透明通道*/ + } + + //2007-12-24 Merry Christmas Eve... + public static class NET_DVR_MATRIX_DEC_REMOTE_PLAY extends HIKSDKStructure { + public int dwSize; + public byte[] sDVRIP = new byte[16]; /* DVR IP地址 */ + public short wDVRPort; /* 端口号 */ + public byte byChannel; /* 通道号 */ + public byte byReserve; + public byte[] sUserName = new byte[NAME_LEN]; /* 用户名 */ + public byte[] sPassword = new byte[PASSWD_LEN]; /* 密码 */ + public int dwPlayMode; /* 0-按文件 1-按时间*/ + public NET_DVR_TIME StartTime; + public NET_DVR_TIME StopTime; + public byte[] sFileName = new byte[128]; + } + + + public static class NET_DVR_MATRIX_DEC_REMOTE_PLAY_CONTROL extends HIKSDKStructure { + public int dwSize; + public int dwPlayCmd; /* 播放命令 见文件播放命令*/ + public int dwCmdParam; /* 播放命令参数 */ + } + + public static class NET_DVR_MATRIX_DEC_REMOTE_PLAY_STATUS extends HIKSDKStructure { + public int dwSize; + public int dwCurMediaFileLen; /* 当前播放的媒体文件长度 */ + public int dwCurMediaFilePosition; /* 当前播放文件的播放位置 */ + public int dwCurMediaFileDuration; /* 当前播放文件的总时间 */ + public int dwCurPlayTime; /* ½“前已经播放的时间 */ + public int dwCurMediaFIleFrames; /* 当前播放文件的总帧数 */ + public int dwCurDataType; /* 当前传输的数据类型,19-文件头,20-流数据, 21-播放结束标志 */ + public byte[] res = new byte[72]; + } + + public static class NET_DVR_MATRIX_PASSIVEMODE extends HIKSDKStructure { + public short wTransProtol; //传输协议,0-TCP, 1-UDP, 2-MCAST + public short wPassivePort; //TCP,UDP时为TCP,UDP端口, MCAST时为MCAST端口 + public NET_DVR_IPADDR struMcastIP; //TCP,UDP时无效, MCAST时为多播地址 + public byte byStreamType; //数据播放模式:1- 实时流,2- 文件流 + public byte[] res = new byte[7]; + } +/************************************多路解码器(end)***************************************/ + + + /************************************ + * 拼控(Start) + ***************************************/ + + + public static final int NET_DVR_GET_SUBWND_DECODE_OSD = 9183; //获取子窗口解码OSD信息 + public static final int NET_DVR_GET_SUBWND_DECODE_OSD_ALL = 9184; //获取所有子窗口解码OSD信息 + public static final int NET_DVR_SET_SUBWND_DECODE_OSD = 9185; //设置子窗口解码OSD信息 + public static final int NET_DVR_GET_SUBWND_DECODE_OSD_CAP = 9186; //获取子窗口解码OSD信息能力集 + public static final int NET_DVR_GET_DECODE_CHANNEL_OSD = 9187; //获取解码通道OSD信息 + public static final int NET_DVR_SET_DECODE_CHANNEL_OSD = 9188; //设置解码通道OSD信息 + + public static final int MAX_PLAN_ACTION_NUM = 32; //预案动作个数 + public static final int DAYS_A_WEEK = 7; //一周7天 + public static final int MAX_PLAN_COUNT = 16; //预案个数 + public static final int MAX_LEN_OSD_CONTENT = 256; //OSD信息最大长度 + public static final int MAX_NUM_OSD_ONE_SUBWND = 8; //单个子窗口支持的最大OSD数量 + public static final int MAX_NUM_SPLIT_WND = 64; //单个窗口支持的最大分屏窗口数量(即子窗口数量) + public static final int MAX_NUM_OSD = 8; + public static final int MAX_CYCLE_CHAN_V30 = 64; //最大轮巡通道数(扩展) + public static final int STREAM_PASSWD_LEN = 12; //码流加密密钥最大长度 + + public static class NET_DVR_VIDEO_WALL_INFO extends HIKSDKStructure { + public int dwSize; + //窗口号:1字节墙号+1字节保留+2字节窗口号 + public int dwWindowNo; + public int dwSceneNo;//场景号 + public int dwDestWallNo; //目的墙号 + public int dwDestSceneNo;//目的场景号 + public byte[] byRes = new byte[12]; + } + + public static class NET_DVR_SCENE_CONTROL_INFO extends HIKSDKStructure { + public int dwSize; + public NET_DVR_VIDEO_WALL_INFO struVideoWallInfo; //电视墙信息 + public int dwCmd; //场景控制命令,1-场景模式切换(如果要切换的是当前场景,则不进行切换),2-初始化场景(将此场景的配置清空,如果是当前场景,则同时对当前场景进行清屏操作),3-强制切换(无论是否是当前场景,强制切换),4-保存当前模式到某场景 5-删除场景 ,6-场景复制 + public byte[] byRes = new byte[4]; + } + + public static class NET_DVR_BUF_INFO extends HIKSDKStructure { + public Pointer pBuf; + public int nLen; + } + + public static class NET_DVR_IN_PARAM extends HIKSDKStructure { + public NET_DVR_BUF_INFO struCondBuf; + public NET_DVR_BUF_INFO struInParamBuf; + public int dwRecvTimeout; //接收数据超时时间,单位:ms,置0采用接口默认超时 + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_OUT_PARAM extends HIKSDKStructure { + public NET_DVR_BUF_INFO struOutBuf; + public Pointer lpStatusList; + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_RECTCFG_EX extends HIKSDKStructure { + public int dwXCoordinate; /*矩形左上角起始点X坐标*/ + public int dwYCoordinate; /*矩形左上角Y坐标*/ + public int dwWidth; /*矩形宽度*/ + public int dwHeight; /*矩形高度*/ + public byte[] byRes = new byte[4]; + + } + + public static class NET_DVR_VIDEOWALLWINDOWPOSITION extends HIKSDKStructure { + public int dwSize; + public byte byEnable; //窗口使能,0-不使能,1-使能 + public byte byWndOperateMode; //窗口操作模式,0-统一坐标,1-分辨率坐标 + public byte[] byRes1 = new byte[6]; + public int dwWindowNo;//窗口号 + public int dwLayerIndex;//窗口相对应的图层号,图层号到最大即置顶,置顶操作 + public NET_DVR_RECTCFG_EX struRect; //目的窗口统一坐标(相对显示墙),获取或按统一坐标设置时有效 + public NET_DVR_RECTCFG_EX struResolution; //目的窗口分辨率坐标,获取或按分辨率坐标设置有效 + public int dwXCoordinate; //LED区域左上角X坐标(统一坐标),获取或按分辨率坐标设置有效 + public int dwYCoordinate; //LED区域左上角Y坐标(统一坐标),获取或按分辨率坐标设置有效 + public byte[] byRes2 = new byte[36]; + } + + public static class VIDEOWALLWINDOWPOSITION_ARRAY extends HIKSDKStructure { + public NET_DVR_VIDEOWALLWINDOWPOSITION[] strVideoWinPostion; + + public VIDEOWALLWINDOWPOSITION_ARRAY(int iLen) { + strVideoWinPostion = new NET_DVR_VIDEOWALLWINDOWPOSITION[iLen]; + } + + + } + + + public static class NET_DVR_WALLWINPARAM extends HIKSDKStructure { + public int dwSize; + public byte byTransparency; //使能透明度,0-关,非0-开 + public byte byWinMode;//窗口分屏模式,能力集获取 + public byte byEnableSpartan;//畅显使能,0-关,1-开 + public byte byDecResource; //为窗口分配的解码资源,1-D1,2-720P,3-1080P + public byte byWndShowMode; //窗口显示模式,0-此字段不用,1-子窗口模式,2-子窗口全屏模式 + public byte byEnabledFeature; //是否启用场景特写,0-不启用,!0-启用 + public byte byFeatureMode; //特写模式,启用场景特写时有效,0-无效,1-“1+5”模式 + public byte byRes1; + public int dwAmplifyingSubWndNo; //全屏子窗口号(1字节墙号+1字节子窗口号+2字节窗口号) + //当byWndShowMode为2时有效,表示当前全屏显示的子窗口 + public byte byWndTopKeep; //窗口置顶保持,0-不保持,1-保持 + public byte byWndOpenKeep; //窗口打开保持,0-不保持,1-保持 + public byte[] byRes = new byte[22]; + } + + public static class NET_DVR_PLAN_LIST extends HIKSDKStructure { + public int dwSize; + public int dwPlanNums; //设备输入信号源数量 + public Pointer pBuffer; //指向dwInputSignalNums个NET_DVR_PLAN_CFG结构大小的缓冲区 + public byte byWallNo; //墙号,从1开始 + public byte[] byRes1 = new byte[2]; + public int dwBufLen; //所分配缓冲区长度,输入参数(大于等于dwInputSignalNums个NET_DVR_PLAN_CFG结构大小) + public byte[] byRes2 = new byte[64]; + } + + /*预案项信息*/ + public static class NET_DVR_PLAN_INFO extends HIKSDKStructure { + public byte byValid; // 该项是否有效 + public byte byType; // 见定义NET_DVR_PLAN_OPERATE_TYPE + public short wLayoutNo; // 布局号 + public byte byScreenStyle; //屏幕型号,开关机所用,1是低亮,2是高亮 + public byte byBaseMapType; //底图类型,1-图片底图,2-超高清输入底图,底图切换时有效 + public byte[] byRes1 = new byte[2]; + public int dwDelayTime; // 一个项的运行时间, 单位秒 + public int dwSerialNo; //串口号,屏幕控制时使用 + public int dwBaseMapWndNo; //底图窗口号,底图切换时有效 + public int dwBaseMapNo; //底图号,底图切换时有效;底图类型为1时,此参数为图片序号,底图类型为2时此参数为超高清输入子系统输入号(1字节设备号+1字节子板号+2字节显示输入序号) + public byte[] byRes2 = new byte[20]; + } + + public static class NET_DVR_CYCLE_TIME extends HIKSDKStructure { + public byte byValid; + public byte[] byRes = new byte[3]; + public NET_DVR_TIME_EX struTime = new NET_DVR_TIME_EX(); + } + + /*预案管理*/ + public static class NET_DVR_PLAN_CFG extends HIKSDKStructure { + public int dwSize; + public byte byValid; // 该预案是否有效 + public byte byWorkMode; // 预案工作模式 1表示手动,2自动,3预案循环 + public byte byWallNo; //电视墙号,从1开始 + public byte byPlanNo; //预案号,获取预案列表时有效,0-无效或不支持 + public byte[] byPlanName = new byte[NAME_LEN/*32*/]; //预案名称 + public NET_DVR_TIME_EX struTime; // 工作模式为自动时使用 + public NET_DVR_CYCLE_TIME[] struTimeCycle = new NET_DVR_CYCLE_TIME[DAYS_A_WEEK/*7*/]; /*循环时间,周期为一个星期,年、月、日三个参数不使用。如:struTimeCycle[0]中的byValid的值是1,表示星期天执行该预案。星期取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推*/ + public int dwWorkCount; // 预案内容执行次数 + public NET_DVR_PLAN_INFO[] strPlanEntry = new NET_DVR_PLAN_INFO[MAX_PLAN_ACTION_NUM/*32*/]; // 预案执行的内容 + public int dwPlanNo; //4字节预案号,客户端统一使用4字节的预案号,单字节的预案号不再使用 + public byte[] byRes2 = new byte[60]; + } + + public static class NET_DVR_WALLSCENECFG extends HIKSDKStructure { + public int dwSize; + public byte[] sSceneName = new byte[NAME_LEN]; //场景名称 + public byte byEnable; //场景是否有效,0-无效,1-有效 + public byte bySceneIndex; //场景号,只能获取。获取所有场景时使用该参数 + public byte[] byRes = new byte[78]; + } + + public static class NET_DVR_SUBWND_DECODE_OSD extends HIKSDKStructure { + public int dwSize = 0; + public int dwSubWndNo = 0; //子窗口号(4字节组合方式) + public int dwOSDNums = 0; //该子窗口配置的OSD信息的个数 + public NET_DVR_OSD_INFO[] struOSDList = new NET_DVR_OSD_INFO[MAX_NUM_OSD_ONE_SUBWND]; //OSD信息列表 + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_OSD_INFO extends HIKSDKStructure { + public byte byEnabled = 1; //是否使能,零-不使能,非零-使能 + public byte byEnabledFlash = 0; //是否闪烁,零-不闪烁,非零-闪烁 + public byte byFontSize = 1; //字体大小,1-大,2-中,3-小 + public byte byTransparent = 0; //透明度,取值范围0-100 + public NET_DVR_RGB_COLOR struColor = new NET_DVR_RGB_COLOR(); //字体颜色 + public short wCoordinateX = 0; //OSD左上角X坐标 + public short wCoordinateY = 0; //OSD左上角Y坐标 + public byte[] byContent = new byte[MAX_LEN_OSD_CONTENT]; //OSD信息 + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_DEV_CHAN_INFO_EX extends HIKSDKStructure { + public byte byChanType; //通道类型,0-普通通道,1-零通道,2-流ID,3-本地输入源,4-虚拟屏服务器通道,5-拼接通道,6-屏幕服务器,7-分布式网络源,8-多相机融合通道,9-网络输入源 + public byte[] byStreamId = new byte[STREAM_ID_LEN]; //流ID,当byChanType=2、9时,该字段用于指定流或者网络ipc的ID号 + public byte[] byRes1 = new byte[3]; + public int dwChannel; //通道号,通道类型为普通通道,零通道,本地输入源,虚拟屏服务器通道,拼接通道,屏幕服务器,分布式网络源时填此字段 + public byte[] byRes2 = new byte[24]; + public byte[] byAddress = new byte[MAX_DOMAIN_NAME]; //设备域名 + public short wDVRPort; //端口号 + public byte byChannel; //通道号,dwChannel不为0时此字段无效 + public byte byTransProtocol; //传输协议类型0-TCP,1-UDP + public byte byTransMode; //传输码流模式 0-主码流 1-子码流 + public byte byFactoryType; /*前端设备厂家类型,通过接口获取*/ + public byte byDeviceType; //设备类型(视频综合平台智能板使用),1-解码器(此时根据视频综合平台能力集中byVcaSupportChanMode字段来决定是使用解码通道还是显示通道),2-编码器 + public byte byDispChan;//显示通道号,智能配置使用 + public byte bySubDispChan;//显示通道子通道号,智能配置时使用 + public byte byResolution; //; 1-CIF 2-4CIF 3-720P 4-1080P 5-500w大屏控制器使用,大屏控制器会根据该参数分配解码资源 + public byte[] byRes = new byte[2]; + public byte[] sUserName = new byte[NAME_LEN]; //布防主机登陆帐号 + public byte[] sPassword = new byte[PASSWD_LEN]; //布防主机密码 + } + + public static class NET_DVR_STREAM_MEDIA_SERVER extends HIKSDKStructure { + public byte byValid; //是否启用,0-否,1-是 + public byte[] byRes1 = new byte[3]; + public byte[] byAddress = new byte[MAX_DOMAIN_NAME]; //IP或者域名 + public short wDevPort; /*流媒体服务器端口*/ + public byte byTransmitType; /*传输协议类型 0-TCP,1-UDP*/ + public byte[] byRes2 = new byte[5]; + } + + public static class NET_DVR_DEV_DDNS_INFO extends HIKSDKStructure { + public byte[] byDevAddress = new byte[MAX_DOMAIN_NAME]; //域名(IPServer或hiDDNS时可填序列号或者别名) + public byte byTransProtocol; //传输协议类型0-TCP,1-UDP, 2-MCAST + public byte byTransMode; //传输码流模式 0-主码流 1-子码流 + public byte byDdnsType; //域名服务器类型,0-IPServer 1-Dyndns 2-PeanutHull(花生壳),3- NO-IP, 4- hiDDNS + public byte byRes1; + public byte[] byDdnsAddress = new byte[MAX_DOMAIN_NAME]; //DDNS服务器地址 + public short wDdnsPort; //DDNS服务器端口号 + public byte byChanType; //0-普通通道,1-零通道,2-流ID + public byte byFactoryType; //前端设备厂家类型,通过接口获取 + public int dwChannel; //通道号 + public byte[] byStreamId = new byte[STREAM_ID_LEN]; //流ID + public byte[] sUserName = new byte[NAME_LEN]; //布防主机登陆帐号 + public byte[] sPassword = new byte[PASSWD_LEN]; //布防主机密码 + public short wDevPort; //前端设备通信端口 + public byte[] byRes2 = new byte[2]; + } + + public static class NET_DVR_DEC_STREAM_DEV_EX extends HIKSDKStructure { + public NET_DVR_STREAM_MEDIA_SERVER struStreamMediaSvrCfg = new NET_DVR_STREAM_MEDIA_SERVER(); + public NET_DVR_DEV_CHAN_INFO_EX struDevChanInfo = new NET_DVR_DEV_CHAN_INFO_EX(); + } + + //DDNS方式取流 + public static class NET_DVR_DEC_DDNS_DEV extends HIKSDKStructure { + public NET_DVR_DEV_DDNS_INFO struDdnsInfo; + public NET_DVR_STREAM_MEDIA_SERVER struMediaServer; + } + + public static class NET_DVR_DEC_STREAM_MODE extends Union { + public NET_DVR_DEC_STREAM_DEV_EX struDecStreamDev = new NET_DVR_DEC_STREAM_DEV_EX(); + public NET_DVR_PU_STREAM_URL struUrlInfo = new NET_DVR_PU_STREAM_URL(); + public NET_DVR_DEC_DDNS_DEV struDdnsDecInfo = new NET_DVR_DEC_DDNS_DEV(); + public byte[] byRes = new byte[300]; + } + + public static class NET_DVR_MATRIX_CHAN_INFO_V41 extends HIKSDKStructure { + public byte byEnable; //是否启用,0-否,1-是 + public byte byStreamMode;/*取流模式,0-无效,1-通过IP或域名取流,2-通过URL取流,3-通过动态域名解析向设备取流*/ + public byte[] byRes = new byte[2]; + public NET_DVR_DEC_STREAM_MODE uDecStreamMode = new NET_DVR_DEC_STREAM_MODE();//取流信息 + } + + public static class NET_DVR_MATRIX_LOOP_DECINFO_V41 extends HIKSDKStructure { + public int dwSize; + public int dwPoolTime; /*轮巡间隔*/ + public NET_DVR_MATRIX_CHAN_INFO_V41[] struchanConInfo = new NET_DVR_MATRIX_CHAN_INFO_V41[MAX_CYCLE_CHAN_V30]; + public byte byStreamEncrypt; //是否进行码流加密处理,0-不支持,1-支持 + public byte[] byRes = new byte[3]; + public byte[] sStreamPassword = new byte[STREAM_PASSWD_LEN]; //码流加密密码,需敏感信息加密 + } + + /************************************ + * 拼控(End) + ***************************************/ + + public static class NET_DVR_EMAILCFG extends HIKSDKStructure { /* 12 bytes */ + public int dwSize; + public byte[] sUserName = new byte[32]; + public byte[] sPassWord = new byte[32]; + public byte[] sFromName = new byte[32]; /* Sender *///字符串中的第一个字符和最后一个字符不能是"@",并且字符串中要有"@"字符 + public byte[] sFromAddr = new byte[48]; /* Sender address */ + public byte[] sToName1 = new byte[32]; /* Receiver1 */ + public byte[] sToName2 = new byte[32]; /* Receiver2 */ + public byte[] sToAddr1 = new byte[48]; /* Receiver address1 */ + public byte[] sToAddr2 = new byte[48]; /* Receiver address2 */ + public byte[] sEmailServer = new byte[32]; /* Email server address */ + public byte byServerType; /* Email server type: 0-SMTP, 1-POP, 2-IMTP…*/ + public byte byUseAuthen; /* Email server authentication method: 1-enable, 0-disable */ + public byte byAttachment; /* enable attachment */ + public byte byMailinterval; /* mail interval 0-2s, 1-3s, 2-4s. 3-5s*/ + } + + public static class NET_DVR_COMPRESSIONCFG_NEW extends HIKSDKStructure { + public int dwSize; + public NET_DVR_COMPRESSION_INFO_EX struLowCompression; //定šš时录像 + public NET_DVR_COMPRESSION_INFO_EX struEventCompression; //事件触发录像 + } + + //球机位置信息 + public static class NET_DVR_PTZPOS extends HIKSDKStructure { + public short wAction;//获取时该字段无效 + public short wPanPos;//水平参数 + public short wTiltPos;//垂直参数 + public short wZoomPos;//变倍参数 + } + + //球机范围信息 + public static class NET_DVR_PTZSCOPE extends HIKSDKStructure { + public short wPanPosMin;//水平参数min + public short wPanPosMax;//水平参数max + public short wTiltPosMin;//垂直参数min + public short wTiltPosMax;//垂直参数max + public short wZoomPosMin;//变倍参数min + public short wZoomPosMax;//变倍参数max + } + + public static class NET_DVR_PTZABSOLUTEEX_CFG extends HIKSDKStructure { + public int dwSize;//结构体大小 + public NET_PTZ_INFO struPTZCtrl = new NET_PTZ_INFO();//设备PTZF信息 + public int dwFocalLen;//焦距范围:0-100000MM + public float fHorizontalSpeed;//水平转动速度:0.01-1000.00度/S + public float fVerticalSpeed;//垂直转动速度:0.01-1000.00度/S + /*镜头变倍配置类型;absoluteZoom:通过变倍参数进行配置,选择为该类型时struPTZCtrl中的fZoom参数生效。focalLen:通过焦距参数进行配置,选择为该类型时,dwFocalLen参数生效。*/ + public byte byZoomType;// 镜头变倍配置类型0~ absoluteZoom,1~ focalLen + public byte[] byRes = new byte[123]; + } + + //rtsp配置 ipcamera专用 + public static class NET_DVR_RTSPCFG extends HIKSDKStructure { + public int dwSize; //长度 + public short wPort; //rtsp服务器侦听端口 + public byte[] byReserve = new byte[54]; //预留 + } + + /******************************** + * 接口参数结构(begin) + *********************************/ + +//NET_DVR_Login()参数结构 + public static class NET_DVR_DEVICEINFO extends HIKSDKStructure { + public byte[] sSerialNumber = new byte[SERIALNO_LEN]; //序列号 + public byte byAlarmInPortNum; //DVR报警输入个数 + public byte byAlarmOutPortNum; //DVR报警输出个数 + public byte byDiskNum; //DVR硬盘个数 + public byte byDVRType; //DVR类型, 1:DVR 2:ATM DVR 3:DVS ...... + public byte byChanNum; //DVR 通道个数 + public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1 + } + + //NET_DVR_Login_V30()参数结构 + public static class NET_DVR_DEVICEINFO_V30 extends HIKSDKStructure { + public byte[] sSerialNumber = new byte[SERIALNO_LEN]; //序列号 + public byte byAlarmInPortNum; //报警输入个数 + public byte byAlarmOutPortNum; //报警输出个数 + public byte byDiskNum; //硬盘个数 + public byte byDVRType; //设备类型, 1:DVR 2:ATM DVR 3:DVS ...... + public byte byChanNum; //模拟通道个数 + public byte byStartChan; //起始通道号,例如DVS-1,DVR - 1 + public byte byAudioChanNum; //语音通道数 + public byte byIPChanNum; //最大数字通道个数,低位 + public byte byZeroChanNum; //零通道编码个数 //2010-01-16 + public byte byMainProto; //主码流传输协议类型 0-private, 1-rtsp,2-同时支持private和rtsp + public byte bySubProto; //子码流传输协议类型0-private, 1-rtsp,2-同时支持private和rtsp + public byte bySupport; //能力,位与结果为0表示不支持,1表示支持, + public byte bySupport1; // 能力集扩充,位与结果为0表示不支持,1表示支持 + public byte bySupport2; /*能力*/ + public short wDevType; //设备型号 + public byte bySupport3; //能力集扩展 + public byte byMultiStreamProto;//是否支持多码流,按位表示,0-不支持,1-支持,bit1-码流3,bit2-码流4,bit7-主码流,bit-8子码流 + public byte byStartDChan; //起始数字通道号,0表示无效 + public byte byStartDTalkChan; //起始数字对讲通道号,区别于模拟对讲通道号,0表示无效 + public byte byHighDChanNum; //数字通道个数,高位 + public byte bySupport4; //能力集扩展 + public byte byLanguageType;// 支持语种能力,按位表示,每一位0-不支持,1-支持 + // byLanguageType 等于0 表示 老设备 + // byLanguageType & 0x1表示支持中文 + // byLanguageType & 0x2表示支持英文 + public byte byVoiceInChanNum; //音频输入通道数 + public byte byStartVoiceInChanNo; //音频输入起始通道号 0表示无效 + public byte bySupport5; + public byte bySupport6; //能力 + public byte byMirrorChanNum; //镜像通道个数,<录播主机中用于表示导播通道> + public short wStartMirrorChanNo; //起始镜像通道号 + public byte bySupport7; //能力 + public byte byRes2; //保留 + } + + public static final int NET_DVR_DEV_ADDRESS_MAX_LEN = 129; + public static final int NET_DVR_LOGIN_USERNAME_MAX_LEN = 64; + public static final int NET_DVR_LOGIN_PASSWD_MAX_LEN = 64; + + public static interface FLoginResultCallBack extends Callback { + public int invoke(int lUserID, int dwResult, NET_DVR_DEVICEINFO_V30 lpDeviceinfo, Pointer pUser); + } + + //NET_DVR_Login_V40()参数 + public static class NET_DVR_USER_LOGIN_INFO extends HIKSDKStructure { + public byte[] sDeviceAddress = new byte[NET_DVR_DEV_ADDRESS_MAX_LEN]; + public byte byUseTransport; + public short wPort; + public byte[] sUserName = new byte[NET_DVR_LOGIN_USERNAME_MAX_LEN]; + public byte[] sPassword = new byte[NET_DVR_LOGIN_PASSWD_MAX_LEN]; + public FLoginResultCallBack cbLoginResult; + public Pointer pUser; + public boolean bUseAsynLogin; + public byte byProxyType; //0:不使用代理,1:使用标准代理,2:使用EHome代理 + public byte byUseUTCTime; //0-不进行转换,默认,1-接口上输入输出全部使用UTC时间,SDK完成UTC时间与设备时区的转换,2-接口上输入输出全部使用平台本地时间,SDK完成平台本地时间与设备时区的转换 + public byte byLoginMode; //0-Private 1-ISAPI 2-自适应 + public byte byHttps; //0-不适用tls,1-使用tls 2-自适应 + public int iProxyID; //代理服务器序号,添加代理服务器信息时,相对应的服务器数组下表值 + public byte byVerifyMode; //认证方式,0-不认证,1-双向认证,2-单向认证;认证仅在使用TLS的时候生效; + public byte[] byRes2 = new byte[119]; + @Override + protected List getFieldOrder() { + return Arrays.asList( + "sDeviceAddress", + "byUseTransport", + "wPort", + "sUserName", + "sPassword", + "cbLoginResult", + "pUser", + "bUseAsynLogin", + "byProxyType", + "byUseUTCTime", + "byLoginMode", + "byHttps", + "iProxyID", + "byVerifyMode", + "byRes2" + ); + } + } + + //NET_DVR_Login_V40()参数 + public static class NET_DVR_DEVICEINFO_V40 extends HIKSDKStructure { + public NET_DVR_DEVICEINFO_V30 struDeviceV30 = new NET_DVR_DEVICEINFO_V30(); + public byte bySupportLock; + public byte byRetryLoginTime; + public byte byPasswordLevel; + public byte byRes1; + public int dwSurplusLockTime; + public byte byCharEncodeType;//字符编码类型:0- 无字符编码信息(老设备),1- GB2312(简体中文),2- GBK,3- BIG5(繁体中文),4- Shift_JIS(日文),5- EUC-KR(韩文),6- UTF-8,7- ISO8859-1,8- ISO8859-2,9- ISO8859-3,…,依次类推,21- ISO8859-15(西欧) + public byte bySupportDev5; //支持v50版本的设备参数获取,设备名称和设备类型名称长度扩展为64字节 + public byte bySupport; //能力集扩展,位与结果:0- 不支持,1- 支持 + public byte byLoginMode; //登录模式 0-Private登录 1-ISAPI登录 + public int dwOEMCode; + public int iResidualValidity; //该用户密码剩余有效天数,单位:天,返回负值,表示密码已经超期使用,例如“-3表示密码已经超期使用3天” + public byte byResidualValidity; // iResidualValidity字段是否有效,0-无效,1-有效 + public byte bySingleStartDTalkChan; //独立音轨接入的设备,起始接入通道号,0-为保留字节,无实际含义,音轨通道号不能从0开始 + public byte bySingleDTalkChanNums; //独立音轨接入的设备的通道总数,0-表示不支持 + public byte byPassWordResetLevel; //0-无效,1-管理员创建一个非管理员用户为其设置密码,该非管理员用户正确登录设备后要提示“请修改初始登录密码”,未修改的情况下,用户每次登入都会进行提醒;2-当非管理员用户的密码被管理员修改,该非管理员用户再次正确登录设备后,需要提示“请重新设置登录密码”,未修改的情况下,用户每次登入都会进行提醒。 + public byte bySupportStreamEncrypt; //能力集扩展,位与结果:0- 不支持,1- 支持 bySupportStreamEncrypt & 0x1:表示是否支持RTP/TLS取流 bySupportStreamEncrypt & 0x2: 表示是否支持SRTP/UDP取流 bySupportStreamEncrypt & 0x4: 表示是否支持SRTP/MULTICAST取流 + public byte byMarketType;//0-无效(未知类型),1-经销型,2-行业型 + public byte[] byRes2 = new byte[238]; + @Override + protected List getFieldOrder() { + return Arrays.asList( + "struDeviceV30", + "bySupportLock", + "byRetryLoginTime", + "byPasswordLevel", + "byRes1", + "dwSurplusLockTime", + "byCharEncodeType", + "bySupportDev5", + "bySupport", + "byLoginMode", + "dwOEMCode", + "iResidualValidity", + "byResidualValidity", + "bySingleStartDTalkChan", + "bySingleDTalkChanNums", + "byPassWordResetLevel", + "bySupportStreamEncrypt", + "byMarketType", + "byRes2" + ); + } + } + + //sdk网络环境枚举变量,用于远程升级 + enum _SDK_NET_ENV { + LOCAL_AREA_NETWORK, + WIDE_AREA_NETWORK + } + + //显示模式 + enum DISPLAY_MODE { + NORMALMODE, + OVERLAYMODE + } + + //发送模式 + enum SEND_MODE { + PTOPTCPMODE, + PTOPUDPMODE, + MULTIMODE, + RTPMODE, + RESERVEDMODE + } + + ; + + //抓图模式 + enum CAPTURE_MODE { + BMP_MODE, //BMP模式 + JPEG_MODE //JPEG模式 + } + + ; + + //实时声音模式 + enum REALSOUND_MODE { + NONE, //SDK中无此模式,只是为了填补0这个位置 + MONOPOLIZE_MODE, //独占模式 1 + SHARE_MODE //共享模式 2 + } + + ; + + //软解码预览参数 + public static class NET_DVR_CLIENTINFO extends HIKSDKStructure { + public int lChannel; + public int lLinkMode; + public HWND hPlayWnd; + public String sMultiCastIP; + } + + //预览V40接口 + public static class NET_DVR_PREVIEWINFO extends HIKSDKStructure { + public int lChannel;//通道号 + public int dwStreamType; // 码流类型,0-主码流,1-子码流,2-码流3,3-码流4, 4-码流5,5-码流6,7-码流7,8-码流8,9-码流9,10-码流10 + public int dwLinkMode;// 0:TCP方式,1:UDP方式,2:多播方式,3 - RTP方式,4-RTP/RTSP,5-RSTP/HTTP ,6- HRUDP(可靠传输) ,7-RTSP/HTTPS + public int hPlayWnd;//播放窗口的句柄,为NULL表示不播放图象 + public int bBlocked; //0-非阻塞取流, 1-阻塞取流, 如果阻塞SDK内部connect失败将会有5s的超时才能够返回,不适合于轮询取流操作. + public int bPassbackRecord; //0-不启用录像回传,1启用录像回传 + public byte byPreviewMode;//预览模式,0-正常预览,1-延迟预览 + public byte[] byStreamID = new byte[32];//流ID,lChannel为0xffffffff时启用此参数 + public byte byProtoType; //应用层取流协议,0-私有协议,1-RTSP协议 + public byte byRes1; + public byte byVideoCodingType; //码流数据编解码类型 0-通用编码数据 1-热成像探测器产生的原始数据(温度数据的加密信息,通过去加密运算,将原始数据算出真实的温度值) + public int dwDisplayBufNum; //播放库播放缓冲区最大缓冲帧数,范围1-50,置0时默认为1 + public byte byNPQMode; //NPQ是直连模式,还是过流媒体 0-直连 1-过流媒体 + public byte[] byRes = new byte[215]; + } + + public static class NET_DVR_STREAM_INFO extends HIKSDKStructure { + public int dwSize; + public byte[] byID = new byte[32]; + public int dwChannel; + public byte[] byRes = new byte[32]; + } + + //配置条件 + public static class NET_DVR_CLOUDSTORAGE_COND extends HIKSDKStructure { + public int dwSize; + public int dwChannel; + public byte[] byRes1 = new byte[64]; + } + + public static class NET_DVR_STREAM_RECORD_STATUS extends HIKSDKStructure { + public int dwSize; + public byte byRecord; + public byte byOffLineRecord; + public byte[] byRes1 = new byte[2]; + public int dwRelatedHD; + public byte[] byRes2 = new byte[8]; + } + + //SDK状态信息(9000新增) + public static class NET_DVR_SDKSTATE extends HIKSDKStructure { + public int dwTotalLoginNum; //当前login用户数 + public int dwTotalRealPlayNum; //当前realplay路数 + public int dwTotalPlayBackNum; //当前回放或下载路数 + public int dwTotalAlarmChanNum; //当前建立报警通道路数 + public int dwTotalFormatNum; //当前硬盘格式化路数 + public int dwTotalFileSearchNum; //当前日志或文件搜索路数 + public int dwTotalLogSearchNum; //当前日志或文件搜索路数 + public int dwTotalSerialNum; //当前透明通道路数 + public int dwTotalUpgradeNum; //当前升级路数 + public int dwTotalVoiceComNum; //当前语音转发路数 + public int dwTotalBroadCastNum; //当前语音广播路数 + public int[] dwRes = new int[10]; + } + + //SDK功能支持信息(9000新增) + public static class NET_DVR_SDKABL extends HIKSDKStructure { + public int dwMaxLoginNum; //最大login用户数 MAX_LOGIN_USERS + public int dwMaxRealPlayNum; //最大realplay路数 WATCH_NUM + public int dwMaxPlayBackNum; //最大回放或下载路数 WATCH_NUM + public int dwMaxAlarmChanNum; //最大建立报警通道路数 ALARM_NUM + public int dwMaxFormatNum; //最大硬盘格式化路数 SERVER_NUM + public int dwMaxFileSearchNum; //最大文件搜索路数 SERVER_NUM + public int dwMaxLogSearchNum; //最大日志搜索路数 SERVER_NUM + public int dwMaxSerialNum; //最大透明通道路数 SERVER_NUM + public int dwMaxUpgradeNum; //最大升级路数 SERVER_NUM + public int dwMaxVoiceComNum; //最大语音转发路数 SERVER_NUM + public int dwMaxBroadCastNum; //最大语音广播路数 MAX_CASTNUM + public int[] dwRes = new int[10]; + } + + //报警设备信息 + public static class NET_DVR_ALARMER extends HIKSDKStructure { + public byte byUserIDValid; /* userid是否有效 0-无效,1-有效 */ + public byte bySerialValid; /* 序列号是否有效 0-无效,1-有效 */ + public byte byVersionValid; /* 版本号是否有效 0-无效,1-有效 */ + public byte byDeviceNameValid; /* 设备名字是否有效 0-无效,1-有效 */ + public byte byMacAddrValid; /* MAC地址是否有效 0-无效,1-有效 */ + public byte byLinkPortValid; /* login端口是否有效 0-无效,1-有效 */ + public byte byDeviceIPValid; /* 设备IP是否有效 0-无效,1-有效 */ + public byte bySocketIPValid; /* socket ip是否有效 0-无效,1-有效 */ + public int lUserID; /* NET_DVR_Login()返回值, 布防时有效 */ + public byte[] sSerialNumber = new byte[SERIALNO_LEN]; /* 序列号 */ + public int dwDeviceVersion; /* 版本信息 高16位表示主版本,低16位表示次版本*/ + public byte[] sDeviceName = new byte[NAME_LEN]; /* 设备名字 */ + public byte[] byMacAddr = new byte[MACADDR_LEN]; /* MAC地址 */ + public short wLinkPort; /* link port */ + public byte[] sDeviceIP = new byte[128]; /* IP地址 */ + public byte[] sSocketIP = new byte[128]; /* 报警主动上传时的socket IP地址 */ + public byte byIpProtocol; /* Ip协议 0-IPV4, 1-IPV6 */ + public byte[] byRes2 = new byte[11]; + + + } + + //硬解码显示区域参数(子结构) + public static class NET_DVR_DISPLAY_PARA extends HIKSDKStructure { + public int bToScreen; + public int bToVideoOut; + public int nLeft; + public int nTop; + public int nWidth; + public int nHeight; + public int nReserved; + } + + //硬解码预览参数 + public static class NET_DVR_CARDINFO extends HIKSDKStructure { + public int lChannel;//通道号 + public int lLinkMode; //最高位(31)为0表示主码流,为1表示子,0-30位表示码流连接方式:0:TCP方式,1:UDP方式,2:多播方式,3 - RTP方式,4-电话线,5-128k宽带,6-256k宽带,7-384k宽带,8-512k宽带; + public String sMultiCastIP; + public NET_DVR_DISPLAY_PARA struDisplayPara; + } + + //录象文件参数 + public static class NET_DVR_FIND_DATA extends HIKSDKStructure { + public byte[] sFileName = new byte[100];//文件名 + public NET_DVR_TIME struStartTime;//文件的开始时间 + public NET_DVR_TIME struStopTime;//文件的结束时间 + public int dwFileSize;//文件的大小 + } + + //录象文件参数(9000) + public static class NET_DVR_FINDDATA_V30 extends HIKSDKStructure { + public byte[] sFileName = new byte[100];//文件名 + public NET_DVR_TIME struStartTime;//文件的开始时间 + public NET_DVR_TIME struStopTime;//文件的结束时间 + public int dwFileSize;//文件的大小 + public byte[] sCardNum = new byte[32]; + public byte byLocked;//9000设备支持,1表示此文件已经被锁定,0表示正常的文件 + public byte[] byRes = new byte[3]; + } + + //录象文件参数(带卡号) + public static class NET_DVR_FINDDATA_CARD extends HIKSDKStructure { + public byte[] sFileName = new byte[100];//文件名 + public NET_DVR_TIME struStartTime;//文件的开始时间 + public NET_DVR_TIME struStopTime;//文件的结束时间 + public int dwFileSize;//文件的大小 + public byte[] sCardNum = new byte[32]; + } + + public static class NET_DVR_FILECOND_V40 extends HIKSDKStructure { + public int lChannel; + public int dwFileType; + public int dwIsLocked; + public int dwUseCardNo;//是否带ATM信息进行查询:0-不带ATM信息,1-按交易卡号查询,2-按交易类型查询,3-按交易金额查询,4-按卡号、交易类型及交易金额的组合查询 5-按课程名称查找,此时卡号表示课程名称 + public byte[] sCardNumber = new byte[CARDNUM_LEN_OUT]; + public NET_DVR_TIME struStartTime = new NET_DVR_TIME(); + public NET_DVR_TIME struStopTime = new NET_DVR_TIME(); + public byte byDrawFrame; //0:不抽帧,1:抽帧 + public byte byFindType; //0:查询普通卷,1:查询存档卷 + public byte byQuickSearch; //0:普通查询,1:快速(日历)查询 + public byte bySpecialFindInfoType; //专有查询条件类型 0-无效, 1-带ATM查询条件 + public int dwVolumeNum; //存档卷号 + public byte[] byWorkingDeviceGUID = new byte[GUID_LEN]; //工作机GUID,通过获取N+1得到 + public NET_DVR_SPECIAL_FINDINFO_UNION uSpecialFindInfo = new NET_DVR_SPECIAL_FINDINFO_UNION(); //专有查询条件 + public byte byStreamType; //0-同一个时间段只返回一种录像,优先级顺序为:主码流、子码流、三码流,1-子码流,2-三码流,3-主码流,254-双码流搜索(优先返回主码流录像,没有主码流录像时返回子码流录像) + public byte byAudioFile; //音频文件 0-非音频文件,1-音频文件 + public byte[] byRes2 = new byte[30]; //保留 + @Override + protected List getFieldOrder() { + return Arrays.asList( + "sFileName", + "struStartTime", + "struStopTime", + "dwFileSize", + "sCardNum", + "byLocked", + "byFileType", + "byQuickSearch", + "byRes", + "dwFileIndex", + "byStreamType", + "byRes1" + ); + } + } + + public static class NET_DVR_SPECIAL_FINDINFO_UNION extends Union { + public byte[] byLenth = new byte[8]; + public NET_DVR_ATMFINDINFO struATMFindInfo = new NET_DVR_ATMFINDINFO(); //ATM查询 + } + + public static class NET_DVR_ATMFINDINFO extends HIKSDKStructure { + public byte byTransactionType; //交易类型 0-全部,1-查询, 2-取款, 3-存款, 4-修改密码,5-转账, 6-无卡查询 7-无卡存款, 8-吞钞 9-吞卡 10-自定义 + public byte[] byRes = new byte[3]; //保留 + public int dwTransationAmount; //交易金额 ; + } + + //录像文件查找条件结构V50 + public static class NET_DVR_FILECOND_V50 extends HIKSDKStructure { + public NET_DVR_STREAM_INFO struStreamID; //流ID或通道号 + public NET_DVR_TIME_SEARCH_COND struStartTime = new NET_DVR_TIME_SEARCH_COND(); //开始时间 + public NET_DVR_TIME_SEARCH_COND struStopTime = new NET_DVR_TIME_SEARCH_COND(); //结束时间 + public byte byFindType; //0-查询普通卷,1-查询存档卷 2-查询N+1录像文件 + public byte byDrawFrame; //是否抽帧 0-不抽帧 1-抽帧 + public byte byQuickSearch; //0-普通查询,1-快速(日历)查询 + public byte byStreamType; //0-主码流,1-子码流,2-3码流,0xff-全部 + public int dwFileType; // 文件类型 + public int dwVolumeNum; //存档卷号,byFindType为1时有效 + public byte byIsLocked; //是否锁定 0-正常文件,1-锁定文件, 0xff表示所有文件 + public byte byNeedCard; //是否需要查询卡,0-不需要 1-需要 + public byte byOnlyAudioFile; //音频文件 0-视频文件 1-音频文件 + public byte bySpecialFindInfoType; //0-无效, 1-带ATM查询条件 + public byte[] szCardNum = new byte[32]; //卡号,byNeedCard为1时有效 + public byte[] szWorkingDeviceGUID = new byte[16]; //工作机GUID,通过获取N+1得到,byFindType为2时有效 + public NET_DVR_SPECIAL_FINDINFO_UNION uSpecialFindInfo = new NET_DVR_SPECIAL_FINDINFO_UNION(); //专有查询条件联合体 + public int dwTimeout; //查找超时时间(指定NET_DVR_FindNextFile_V30/NET_DVR_FindNextFile_V40/NET_DVR_FindNextFile_V50接口的超时时间返回);单位:毫秒,不填写(默认为0时),接口行为跟以前一样 ;有效值:0, [5000 – 15000] + public byte[] byRes = new byte[252]; + } + + public static class NET_DVR_FINDDATA_V40 extends HIKSDKStructure { + public byte[] sFileName = new byte[100];//文件名 + public NET_DVR_TIME struStartTime = new NET_DVR_TIME();//文件的开始时间 + public NET_DVR_TIME struStopTime = new NET_DVR_TIME();//文件的结束时间 + public int dwFileSize;//文件的大小 + public byte[] sCardNum = new byte[32]; + public byte byLocked;//9000设备支持,1表示此文件已经被锁定,0表示正常的文件 + public byte byFileType; //文件类型:0-定时录像,1-移动侦测 ,2-报警触发, + //3-报警|移动侦测 4-报警&移动侦测 5-命令触发 6-手动录像,7-震动报警,8-环境报警,9-智能报警,10-PIR报警,11-无线报警,12-呼救报警,14-智能交通事件 + public byte byQuickSearch; //0:普通查询结果,1:快速(日历)查询结果 + public byte byRes; + public int dwFileIndex; //文件索引号 + public byte byStreamType; + public byte[] byRes1 = new byte[127]; + @Override + protected List getFieldOrder() { + return Arrays.asList( + "sFileName", + "struStartTime", + "struStopTime", + "dwFileSize", + "sCardNum", + "byLocked", + "byFileType", + "byQuickSearch", + "byRes", + "dwFileIndex", + "byStreamType", + "byRes1" + ); + } + } + + public static class NET_DVR_TIME_SEARCH extends HIKSDKStructure { + public short wYear; //年,设备OSD时间 + public byte byMonth; //月,设备OSD时间 + public byte byDay; //日,设备OSD时间 + public byte byHour; //时,设备OSD时间 + public byte byMinute; //分,设备OSD时间 + public byte bySecond; //秒,设备OSD时间 + public byte cTimeDifferenceH; //与国际标准时间的时差(小时),-12 ... +14 + public byte cTimeDifferenceM; //与国际标准时间的时差(分钟),-30, 0, 30, 45 + public byte byLocalOrUTC; //0-时差无效,设备本地时间,即设备OSD时间 1-时差有效 + public short wMillisecond; //毫秒,精度不够,默认为0 + } + + public static class NET_DVR_ADDRESS extends HIKSDKStructure { + public NET_DVR_IPADDR struIP = new NET_DVR_IPADDR(); //IP地址 + public short wPort; //端口号 + public byte[] byRes = new byte[2]; + } + + public static class NET_DVR_FINDDATA_V50 extends HIKSDKStructure { + public byte[] sFileName = new byte[100]; + public NET_DVR_TIME_SEARCH struStartTime = new NET_DVR_TIME_SEARCH(); + public NET_DVR_TIME_SEARCH struStopTime = new NET_DVR_TIME_SEARCH(); + public NET_DVR_ADDRESS struAddr = new NET_DVR_ADDRESS(); //片段所在的地址信息,集群回放时用到 + public int dwFileSize; //文件大小 + public byte byLocked; //文件是否被锁定,1-文件已锁定;0-文件未锁定 + public byte byFileType; //文件类型,与V40相同 + public byte byQuickSearch; //0- 普通查询结果,1- 快速(日历)查询结果 + public byte byStreamType; //码流类型:0- 主码流,1- 子码流,2- 码流三 + public int dwFileIndex; //文件索引号 + public byte[] sCardNum = new byte[32]; //卡号 + public int dwTotalLenH; // 对于大文件搜索,时间段内数据总长度,高32字节 + public int dwTotalLenL; // 对于大文件搜索,时间段内数据总长度,低32字节 + public byte byBigFileType; // 0为普通片段搜索,1为大文件搜索 + public byte[] byRes = new byte[247]; + } + + public static class NET_DVR_FILECOND extends HIKSDKStructure //录象文件查找条件结构 + { + public int lChannel;//通道号 + public int dwFileType;//录象文件类型0xff-全部,0-定时录像,1-移动侦测 ,2-报警触发,3-报警|移动侦测 4-报警&移动侦测 5-命令触发 6-手动录像 + public int dwIsLocked;//是否锁定 0-正常文件,1-锁定文件, 0xff表示所有文件 + public int dwUseCardNo;//是否使用卡号 + public byte[] sCardNumber = new byte[32];//卡号 + public NET_DVR_TIME struStartTime;//开始时间 + public NET_DVR_TIME struStopTime;//结束时间 + } + + public static class NET_DVR_PLAYCOND extends HIKSDKStructure //回放或者下载信息结构体 + { + public int dwChannel;//通道号 + public NET_DVR_TIME struStartTime; + public NET_DVR_TIME struStopTime; + public byte byDrawFrame; //0:不抽帧,1:抽帧 + public byte byStreamType; //码流类型,0-主码流 1-子码流 2-码流三 + public byte[] byStreamID = new byte[STREAM_ID_LEN]; + public byte[] byRes = new byte[30];//保留 + } + + public static class NET_DVR_VOD_PARA extends HIKSDKStructure //回放或者下载信息结构体 + { + public int dwSize; + public NET_DVR_STREAM_INFO struIDInfo; + public NET_DVR_TIME struBeginTime; + public NET_DVR_TIME struEndTime; + public HWND hWnd; + public byte byDrawFrame; //0:不抽帧,1:抽帧 + public byte byVolumeType; //0-普通录像卷 1-存档卷 + public byte byVolumeNum; //卷号,目前指存档卷号 + public byte byStreamType; //码流类型 0-主码流, 1-子码流,2-码流三 + public int dwFileIndex; //存档卷上的录像文件索引,搜索存档卷录像时返回的值 + public byte byAudioFile; //音频文件0-否,1-是 + public byte byCourseFile; //课程文件0-否,1-是 + public byte byDownload; //是否下载 0-否,1-是 + public byte byOptimalStreamType; //是否按最优码流类型回放 0-否,1-是(对于双码流设备,某一段时间内的录像文件与指定码流类型不同,则返回实际码流类型的录像) + public byte[] byRes2 = new byte[20]; + } + + //图片查找条件 + public static class NET_DVR_FIND_PICTURE_PARAM extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public int lChannel; // 通道号 + public byte byFileType; //图片查找类型 + public byte byNeedCard; // 是否需要卡号 + /* + 0-保留,1-澳,2-京,3-渝,4-闽,5-甘,6-粤,7-桂, + 8-贵,9-琼,10-冀,11-豫,12-黑,13-鄂,14-湘, + 15-吉,16-苏,17-赣,18-辽,19-蒙,20-宁,21-青, + 22-鲁,23-晋,24-陕,25-沪,26-川,27-台,28-津, + 29-藏,30-港,31-新,32-云,33-浙,34-皖,0xff-全部 + */ + public byte byProvince; //省份索引值 + public byte byEventType; // 事件类型:0保留,1-交通事件;2-违章取证;3-其他事件 + public byte[] sCardNum = new byte[CARDNUM_LEN_V30]; // 卡号 + public NET_DVR_TIME struStartTime = new NET_DVR_TIME();//查找图片的开始时间 + public NET_DVR_TIME struStopTime = new NET_DVR_TIME();// 查找图片的结束时间 + //ITC3.7 新增 + public int dwTrafficType; //图片检索生效项 参考 VCA_OPERATE _TYPE + public int dwVehicleType; //车辆类型 参考 VCA_VEHICLE_TYPE + //违规检测类型参考 VCA_ILLEGAL_TYPE 当前不支持复选 + public int dwIllegalType; + public byte byLaneNo; //车道号(1~99) + public byte bySubHvtType;//0-保留,1-机动车(机动车子类型中支持车牌检索,省份检索),2-非机动车,3-行人 + public byte[] byRes2 = new byte[2]; + public byte[] sLicense = new byte[MAX_LICENSE_LEN/*16*/]; //车牌号码 + public byte byRegion; // 区域索引值 0-保留,1-欧洲(Europe Region),3-欧洲&(EU&CIS), 4-中东(Middle East),0xff-所有 + public byte byCountry; // 国家索引值,参照:COUNTRY_INDEX + public byte byArea; //地区 + public byte byISO8601; //是否是8601的时间格式,即时差字段是否有效0-时差无效,年月日时分秒为设备本地时间 1-时差有效 + public byte cStartTimeDifferenceH; //开始时间与UTC的时差(小时),-12 ... +14, 正数表示东时区 + public byte cStartTimeDifferenceM; //开始时间与UTC的时差(分钟),-30, 0, 30, 45,正数表示东时区 + public byte cStopTimeDifferenceH; //结束时间与UTC的时差(小时),-12 ... +14,正数表示东时区 + public byte cStopTimeDifferenceM; //结束时间与UTC的时差(分钟),-30, 0, 30, 45,正数表示东时区 + } + + public static class NET_DVR_FIND_PICTURE extends HIKSDKStructure { + public byte[] sFileName = new byte[PICTURE_NAME_LEN];//图片名 + public NET_DVR_TIME struTime;//图片的时间 + public int dwFileSize;//图片的大小 + public byte[] sCardNum = new byte[CARDNUM_LEN_V30]; //卡号 + public byte byPlateColor;//参考结构 VCA_PLATE_COLOR + public byte byVehicleLogo;//参考结构 VLR_VEHICLE_CLASS + public byte byEventSearchStatus; //连续图片表示同一查找结果的时候,0-表示后面没有图片信息,1-表示后面还有图片信息。总共图片信息包括最后一张状态为0的图片。 + public byte byRecogResult;//识别结果参考结构VTR_RESULT + public byte[] sLicense = new byte[MAX_LICENSE_LEN/*16*/]; //车牌号码 + public byte[] byRes = new byte[12]; + } + + + public class NET_DVR_FIND_PICTURE_V50 extends HIKSDKStructure { + public byte[] sFileName = new byte[PICTURE_NAME_LEN];//图片名 + public NET_DVR_TIME struTime = new NET_DVR_TIME();//图片的时间 + public int dwFileSize;//图片的大小 + public byte[] sCardNum = new byte[CARDNUM_LEN_V30]; //卡号 + public byte byPlateColor;//参考结构 VCA_PLATE_COLOR + public byte byVehicleLogo;//参考结构 VLR_VEHICLE_CLASS + public byte byFileType; //文件类型, :0定时抓图1 移动侦测抓图 2 报警抓图3 报警 | 移动侦测抓图 4 报警 & 移动侦测抓图 6 手动抓图 ,9-智能图片,10- PIR报警,11- 无线报警,12- 呼救报警, 0xa 预览时截图,0xd 人脸侦测, 0xe 越界侦测,0xf 入侵区域侦测,0x10 场景变更侦测, 0x11-设备本地回放时截图, 0x12-智能侦测 + public byte byRecogResult;//识别结果参考结构VTR_RESULT + public byte[] sLicense = new byte[MAX_LICENSE_LEN/*16*/]; //车牌号码 + public byte byEventSearchStatus; //连续图片表示同一查找结果的时候,0-表示后面没有图片信息,1-表示后面还有图片信息。总共图片信息包括最后一张状态为0的图片。 + public NET_DVR_ADDRESS struAddr; //图片所在的地址信息,图片下载时用到 + public byte[] byRes = new byte[256]; // 保留字节 + public NET_DVR_PIC_EXTRA_INFO_UNION uPicExtraInfo; //图片附件信息 + } + + + public class NET_DVR_PIC_PARAM extends HIKSDKStructure { + public Pointer pDVRFileName; + public Pointer pSavedFileBuf; + public int dwBufLen; + public IntByReference lpdwRetLen; + public NET_DVR_ADDRESS struAddr; + public byte[] byRes = new byte[256]; + } + + + //查找结果结构体 + public static class NET_DVR_FIND_PICTURE_V40 extends HIKSDKStructure { + public byte[] sFileName = new byte[PICTURE_NAME_LEN];//图片名 + public NET_DVR_TIME struTime = new NET_DVR_TIME();//图片的时间 + public int dwFileSize;//图片的大小 + public byte[] sCardNum = new byte[CARDNUM_LEN_V30]; //卡号 + public byte byPlateColor;//参考结构 VCA_PLATE_COLOR + public byte byVehicleLogo;//参考结构 VLR_VEHICLE_CLASS + public byte byFileType; //文件类型, :0定时抓图1 移动侦测抓图 2 报警抓图3 报警 | 移动侦测抓图 4 报警 & 移动侦测抓图 6 手动抓图 ,9-智能图片,10- PIR报警,11- 无线报警,12- 呼救报警, 0xa 预览时截图,0xd 人脸侦测, 0xe 越界侦测,0xf 入侵区域侦测,0x10 场景变更侦测, 0x11-设备本地回放时截图, 0x12-智能侦测, 0x32-防区报警, 0x33-紧急求助, 0x34-业务咨询 + public byte byRecogResult;//识别结果参考结构VTR_RESULT + public byte[] sLicense = new byte[MAX_LICENSE_LEN/*16*/]; //车牌号码 + public byte byEventSearchStatus; //连续图片表示同一查找结果的时候,0-表示后面没有图片信息,1-表示后面还有图片信息。总共图片信息包括最后一张状态为0的图片。 + public byte[] byRes = new byte[75]; // 保留字节 + public NET_DVR_PIC_EXTRA_INFO_UNION uPicExtraInfo; //图片附件信息 + } + + public static class NET_DVR_FACE_EXTRA_INFO extends Union { + public NET_VCA_RECT[] struVcaRect = new NET_VCA_RECT[MAX_FACE_PIC_NUM]; //人脸子图坐标信息 + public byte[] byRes = new byte[64]; + } + + //图片附件信息联合体 + public static class NET_DVR_PIC_EXTRA_INFO_UNION extends Union { + public byte[] byUnionLen = new byte[544]; //联合体长度,无实际意义 + public NET_DVR_FACE_EXTRA_INFO struFaceExtraInfo; //人脸侦测信息 + } + + public static class NET_DVR_PACKET_INFO_EX extends Union { + public short wWidth; //width + public short wHeight; //height + public int dwTimeStamp; //lower time stamp + public int dwTimeStampHigh;//higher time stamp + public int dwYear; //year + public int dwMonth; //month + public int dwDay; //day + public int dwHour; //hour + public int dwMinute; //minute + public int dwSecond; //second + public int dwMillisecond; //millisecond + public int dwFrameNum; //frame num + public int dwFrameRate; //frame rate,当帧率小于0时,0x80000002:表示1/2帧率,同理可推0x80000010为1/16帧率 + public int dwFlag; //flag E帧标记 + public int dwFilePos; //file pos + public int dwPacketType; //Packet type:0 -file head,1 -video I frame,2- video B frame, 3- video P frame, 10- audio packet, 11- private packet + public int dwPacketSize; //packet size + public Pointer pPacketBuffer; //packet buffer + public byte[] byRes1 = new byte[4]; + public int dwPacketMode; //打包方式:0-保留,1-FU_A打包方式 + public byte[] byRes2 = new byte[16]; + public int[] dwReserved = new int[6]; //reserved[0] 表示私有数据类型 + } + + //云台区域选择放大缩小(HIK 快球专用) + public static class NET_DVR_POINT_FRAME extends HIKSDKStructure { + public int xTop; //方框起始点的x坐标 + public int yTop; //方框结束点的y坐标 + public int xBottom; //方框结束点的x坐标 + public int yBottom; //方框结束点的y坐标 + public int bCounter; //保留 + @Override + protected List getFieldOrder() { + return Arrays.asList( + "xTop", + "yTop", + "xBottom", + "yBottom", + "bCounter" + ); + } + } + + //语音对讲参数 + public static class NET_DVR_COMPRESSION_AUDIO extends HIKSDKStructure { + public byte byAudioEncType; //0- G722,1- G711_U,2- G711_A,5- MP2L2,6- G726,7- AAC,8- PCM,9-G722,10-G723,11-G729,12-AAC_LC,13-AAC_LD,14-Opus,15-MP3,16-ADPCM + public byte byAudioSamplingRate;//音频采样率 0-默认,1-16kHZ,2-32kHZ,3-48kHZ, 4- 44.1kHZ,5-8kHZ + public byte byAudioBitRate;// 音频码率 参考 BITRATE_ENCODE_INDEX + public byte[] byres=new byte[4];//这里保留音频的压缩参数 + public byte bySupport;//bySupport Bit0表示 Mp2l2前4个字节的含义表示后面内容音频数据长度 + } + + public static class NET_DVR_AUDIODEC_INFO extends HIKSDKStructure { + public int nchans; /* 声道数 */ + public int sample_rate; /* 采样率 */ + public int aacdec_profile; /* 编码用的框架 */ + public int[] reserved = new int[16]; /* 保留 */ + } + + //音频解码 + public static class NET_DVR_AUDIODEC_PROCESS_PARAM extends HIKSDKStructure { + public Pointer in_buf; /* 输入数据buf */ + public Pointer out_buf; /* 输出数据buf */ + public int in_data_size; /* 输入in_buf内数据byte数 */ + public int proc_data_size; /* 输出解码库处理in_buf中数据大小bytes */ + public int out_frame_size; /* 解码一帧后数据BYTE数 */ + public NET_DVR_AUDIODEC_INFO dec_info = new NET_DVR_AUDIODEC_INFO(); /* 输出解码信息 */ + public int g726dec_reset; /* 重置开关 */ + public int g711_type; /* g711编码类型,0 - U law, 1- A law */ + public int[] reserved = new int[16]; /* 保留 */ + } + + public static class NET_DVR_AUDIOENC_INFO extends HIKSDKStructure { + public int in_frame_size; /* 输入一帧数据大小(BYTES),由GetInfoParam函数返回 */ + public int[] reserved = new int[16]; /* 保留 */ + } + + //音频编码 + public static class NET_DVR_AUDIOENC_PROCESS_PARAM extends HIKSDKStructure { + public Pointer in_buf; /* 输入buf */ + public Pointer out_buf; /* 输出buf */ + public int out_frame_size; /* 编码一帧后的BYTE数 */ + public int g726enc_reset; /* 重置开关 */ + public int g711_type; /* g711编码类型,0 - U law, 1- A law */ + public int enc_mode; /* 音频编码模式,AMR编码配置 */ + public int[] reserved = new int[16]; /* 保留 */ + } + + //用于接收报警信息的缓存区 + public static class RECV_ALARM extends HIKSDKStructure { + public byte[] RecvBuffer = new byte[4000];//此处的400应不小于最大报警报文长度 + } + + //布防参数 + public static class NET_DVR_SETUPALARM_PARAM extends HIKSDKStructure { + public int dwSize; + public byte byLevel; //布防优先级,0-一等级(高),1-二等级(中),2-三等级(低) + public byte byAlarmInfoType; //上传报警信息类型(抓拍机支持),0-老报警信息(NET_DVR_PLATE_RESULT),1-新报警信息(NET_ITS_PLATE_RESULT)2012-9-28 + public byte byRetAlarmTypeV40; //0--返回NET_DVR_ALARMINFO_V30或NET_DVR_ALARMINFO, 1--设备支持NET_DVR_ALARMINFO_V40则返回NET_DVR_ALARMINFO_V40,不支持则返回NET_DVR_ALARMINFO_V30或NET_DVR_ALARMINFO + public byte byRetDevInfoVersion; //CVR上传报警信息回调结构体版本号 0-COMM_ALARM_DEVICE, 1-COMM_ALARM_DEVICE_V40 + public byte byRetVQDAlarmType; //VQD报警上传类型,0-上传报报警NET_DVR_VQD_DIAGNOSE_INFO,1-上传报警NET_DVR_VQD_ALARM + public byte byFaceAlarmDetection; + public byte bySupport; + public byte byBrokenNetHttp; + public short wTaskNo; //任务处理号 和 (上传数据NET_DVR_VEHICLE_RECOG_RESULT中的字段dwTaskNo对应 同时 下发任务结构 NET_DVR_VEHICLE_RECOG_COND中的字段dwTaskNo对应) + public byte byDeployType; //布防类型:0-客户端布防,1-实时布防 + public byte[] byRes1 = new byte[3]; + public byte byAlarmTypeURL;//bit0-表示特征抓拍报警上传(INTER_FACESNAP_RESULT);0-表示二进制传输,1-表示URL传输(设备支持的情况下,设备支持能力根据具体报警能力集判断,同时设备需要支持URL的相关服务,当前是”云存储“) + public byte byCustomCtrl;//Bit0- 表示支持副驾驶人脸子图上传: 0-不上传,1-上传,(注:只在公司内部8600/8200等平台开放) + + + } + + public static class NET_DVR_SETUPALARM_PARAM_V50 extends HIKSDKStructure { + public int dwSize; + public byte byLevel; //布防优先级,0-一等级(高),1-二等级(中),2-三等级(低) + public byte byAlarmInfoType; //上传报警信息类型(抓拍机支持),0-老报警信息(NET_DVR_PLATE_RESULT),1-新报警信息(NET_ITS_PLATE_RESULT)2012-9-28 + public byte byRetAlarmTypeV40; //0--返回NET_DVR_ALARMINFO_V30或NET_DVR_ALARMINFO, 1--设备支持NET_DVR_ALARMINFO_V40则返回NET_DVR_ALARMINFO_V40,不支持则返回NET_DVR_ALARMINFO_V30或NET_DVR_ALARMINFO + public byte byRetDevInfoVersion; //CVR上传报警信息回调结构体版本号 0-COMM_ALARM_DEVICE, 1-COMM_ALARM_DEVICE_V40 + public byte byRetVQDAlarmType; //VQD报警上传类型,0-上传报报警NET_DVR_VQD_DIAGNOSE_INFO,1-上传报警NET_DVR_VQD_ALARM + //1-表示人脸侦测报警扩展(INTER_FACE_DETECTION),0-表示原先支持结构(INTER_FACESNAP_RESULT) + public byte byFaceAlarmDetection; + //Bit0- 表示二级布防是否上传图片: 0-上传,1-不上传 + //Bit1- 表示开启数据上传确认机制;0-不开启,1-开启 + //Bit6- 表示雷达检测报警(eventType:radarDetection)是否开启实时上传;0-不开启,1-开启(用于web插件实时显示雷达目标) + public byte bySupport; + //断网续传类型 + //bit0-车牌检测(IPC) (0-不续传,1-续传) + //bit1-客流统计(IPC) (0-不续传,1-续传) + //bit2-热度图统计(IPC) (0-不续传,1-续传) + //bit3-特征抓拍(IPC) (0-不续传,1-续传) + //bit4-人脸对比(IPC) (0-不续传,1-续传) + //bit5-JSON报警透传(IPC) (0-不续传,1-续传) + //bit6-热度图按人员停留时间统计数据上传事件(0-不续传,1-续传) + //bit7-热度图按人数统计数据上传事件的确认机制(0-不续传,1-续传) + public byte byBrokenNetHttp; + public short wTaskNo; //任务处理号 和 (上传数据NET_DVR_VEHICLE_RECOG_RESULT中的字段dwTaskNo对应 同时 下发任务结构 NET_DVR_VEHICLE_RECOG_COND中的字段dwTaskNo对应) + public byte byDeployType; //布防类型:0-客户端布防,1-实时布防 + public byte bySubScription; //订阅,按位表示,未开启订阅不上报 //占位 + //Bit7-移动侦测人车分类是否传图;0-不传图(V30上报),1-传图(V40上报) + public byte[] byRes1 = new byte[2]; + public byte byAlarmTypeURL;//bit0-表示特征抓拍报警上传(INTER_FACESNAP_RESULT);0-表示二进制传输,1-表示URL传输(设备支持的情况下,设备支持能力根据具体报警能力集判断,同时设备需要支持URL的相关服务,当前是”云存储“) + //bit1-表示EVENT_JSON中图片数据长传类型;0-表示二进制传输,1-表示URL传输(设备支持的情况下,设备支持能力根据具体报警能力集判断) + //bit2 - 人脸比对(报警类型为COMM_SNAP_MATCH_ALARM)中图片数据上传类型:0 - 二进制传输,1 - URL传输 + //bit3 - 异常行为检测(报警类型为COMM_ALARM_RULE)中图片数据上传类型:0 - 二进制传输,1 - URL传输,本字段设备是否支持,对应软硬件能力集中节点是否返回且为true + public byte byCustomCtrl;//Bit0- 表示支持副驾驶人脸子图上传: 0-不上传,1-上传 + public byte[] byRes4 = new byte[128]; + } + + + //区域框参数 + public static class NET_VCA_RECT extends HIKSDKStructure { + public float fX; + public float fY; + public float fWidth; + public float fHeight; + } + + //报警目标信息 + public static class NET_VCA_TARGET_INFO extends HIKSDKStructure { + public int dwID; + public NET_VCA_RECT struRect; + public byte[] byRes = new byte[4]; + } + + //前端设备信息 + public static class NET_VCA_DEV_INFO extends HIKSDKStructure { + public NET_DVR_IPADDR struDevIP; + public short wPort; + public byte byChannel; + public byte byIvmsChannel; + } + + //事件规则信息 + public static class NET_VCA_RULE_INFO extends HIKSDKStructure { + public byte byRuleID; + public byte byRes; + public short wEventTypeEx; + public byte[] byRuleName = new byte[NAME_LEN]; + public int dwEventType; + public NET_VCA_EVENT_UNION uEventParam; + + public void read() { + super.read(); + switch (wEventTypeEx) { + case 1: + uEventParam.setType(NET_VCA_TRAVERSE_PLANE.class); + break; + case 2: + uEventParam.setType(NET_VCA_AREA.class); + break; + case 3: + uEventParam.setType(NET_VCA_AREA.class); + break; + case 4: + uEventParam.setType(NET_VCA_INTRUSION.class); + break; + case 15: + uEventParam.setType(NET_VCA_LEAVE_POSITION.class); + break; + default: + break; + } + uEventParam.read(); + } + + public void write() { + super.write(); + uEventParam.write(); + } + + } + + //警戒规则参数联合体 + public static class NET_VCA_EVENT_UNION extends Union { + public int[] uLen = new int[23]; + public NET_VCA_TRAVERSE_PLANE struTraversePlane; //警戒参数 + public NET_VCA_AREA struArea; //进入/离开区域参数 + public NET_VCA_INTRUSION struIntrusion; //区域入侵参数 + public NET_VCA_LEAVE_POSITION struLeavePos; //参数 + + } + + //穿越警戒面参数 + public static class NET_VCA_TRAVERSE_PLANE extends HIKSDKStructure { + public NET_VCA_LINE struPlaneBottom; + public int dwCrossDirection; + public byte bySensitivity; + public byte byPlaneHeight; + public byte byDetectionTarget;/*检测目标:0- 所有目标,1- 人,2- 车 */ + public byte[] byRes2 = new byte[37]; + } + + + //根据报警延迟时间来标识报警中带图片,报警间隔和IO报警一致,1秒发送一个。 +//入侵参数 + public static class NET_VCA_INTRUSION extends HIKSDKStructure + { + public NET_VCA_POLYGON struRegion;//区域范围 + public short wDuration; //行为事件触发时间阈值: 1-120秒,建议5秒,判断是有效报警的时间 在ATM系统中触发文件阈值为 1-1000秒 + public byte bySensitivity; //灵敏度参数,范围[1-100] + public byte byRate; //占比:区域内所有未报警目标尺寸目标占区域面积的比重,归一化为-; + /* + 检测目标,可支持多选,具体定义为: + 0~所有目标(表示不锁定检测目标,所有目标都将进行检测) + 0x01 ~ 人, + 0x02 ~ 车, + 0x04 ~ 其他, + 该字段支持多选,按位取值,例如3表示1+2. + */ + public byte byDetectionTarget; + public byte byPriority;//优先级,0~低,1~中,2~高 + public byte byAlarmConfidence; //报警置信度, 0-低,1-较低,2-较高,3-高 + public byte byRecordConfidence; //录像置信度, 0-低,1-较低,2-较高,3-高 + } + + public static class NET_VCA_LEAVE_POSITION extends HIKSDKStructure { + public NET_VCA_POLYGON struRegion; //区域范围 + public short wLeaveDelay; //无人报警时间,单位:s + public short wStaticDelay; //睡觉报警时间,单位:s + public byte byMode; //模式,0-事件,,3-在岗(当人员回到岗位) + public byte byPersonType; //值岗人数类型,0-单人值岗,1-双人值岗 + public byte byOnPosition; //在岗人数,1-10,默认1 + public byte bySensitivity; //灵敏度参数,范围[1,5] + } + + public static class NET_DVR_HANDLEEXCEPTION_V40 extends HIKSDKStructure { + public int dwHandleType;/*处理方式,各种异常处理方式的"或"结果,异常处理方式: + 0x00: 无响应 0x01: 布防器上警告 0x02: 声音警告 0x04: 上传中心 + 0x08: 触发报警输出 0x10: Jpeg抓图并上传EMail + 0x20: 无线声光报警器联动 0x40: 联动电子地图(目前仅PCNVR支持) + 0x200:抓图并上传ftp 0x400: 虚焦侦测联动聚焦 + 0x800: PTZ联动(球机目标) + E.g. dwHandleType==0x01|0x04 表示配置报警发生时联动布防器上警告并且将报警信息上传中心。 */ + public int dwMaxRelAlarmOutChanNum;/*设备最大支持的触发报警输出通道数(只读) */ + public int dwRelAlarmOutChanNum;/*已配置的触发的报警输出通道个数,决定dwRelAlarmOut取前多少个数组下标 */ + public int[] dwRelAlarmOut = new int[MAX_CHANNUM_V30];/*触发报警输出通道,取数组前dwRelAlarmOutChanNum个值, + 其值表示报警输出通道号(从1开始),初始值是0xfffffffff(不关联通道)。 + 例如,dwRelAlarmOutChanNum=5,则可以配置触发报警输出通道dwRelAlarmOut[0]~dwRelAlarmOut[4]。 */ + public byte[] byRes = new byte[64]; /*保留,置为0 */ + } + + public static final int MAX_ALERTLINE_NUM = 8; + + public static class NET_VCA_TRAVERSE_PLANE_DETECTION extends HIKSDKStructure { + public int dwSize; + public byte byEnable;//使能 + public byte byEnableDualVca;// 启用支持智能后检索 0-不启用,1-启用 + public byte[] byRes1 = new byte[2]; + public NET_VCA_TRAVERSE_PLANE[] struAlertParam = new NET_VCA_TRAVERSE_PLANE[MAX_ALERTLINE_NUM]; //警戒线参数 + public NET_DVR_SCHEDTIMEWEEK[] struAlarmSched = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS]; + public NET_DVR_HANDLEEXCEPTION_V40 struHandleException; //异常处理方式 + public int dwMaxRelRecordChanNum; //报警触发的录象通道 数(只读)最大支持数量 + public int dwRelRecordChanNum; //报警触发的录象通道 数 实际支持的数量 + public int[] byRelRecordChan = new int[MAX_CHANNUM_V30];//触发录像的通道号 + public NET_DVR_SCHEDTIME[] struHolidayTime = new NET_DVR_SCHEDTIME[MAX_TIMESEGMENT_V30]; //假日布防时间 + public byte[] byRes2 = new byte[100]; + } + + + + + //快速移动参数 + public static class NET_VCA_RUN extends HIKSDKStructure { + public NET_VCA_POLYGON struRegion;//区域范围 + public float fRunDistance; //人快速移动最大距离, 范围: [0.1, 1.00] 像素模式 实际模式(1,20)m/s + public byte bySensitivity; //灵敏度参数,范围[1,5] + public byte byMode; // 0 像素模式 1 实际模式 + /* + 检测目标,可支持多选,具体定义为: + 0~所有目标(表示不锁定检测目标,所有目标都将进行检测) + 0x01 ~ 人, + 0x02 ~ 车,, + 0x04 ~ 其他, + 该字段支持多选,按位取值,例如3表示1+2. + */ + public byte byDetectionTarget; + public byte byRes; + } + + + //奔跑检测 + public static class NET_VCA_RUNNING extends HIKSDKStructure { + public NET_VCA_POLYGON struRegion; //区域范围 + public int dwSpeed; //奔跑速度,范围[1,10] + public short wDuration; // 触发报警时间阈值 + public byte byRunMode; //奔跑模式,0-保留,1:单人奔跑,2:多人奔跑 + public byte byRes; + } + + //倒地参数 + public static class NET_VCA_FALL_DOWN extends HIKSDKStructure { + public NET_VCA_POLYGON struRegion;//区域范围 + public short wDuration; /* 触发事件阈值 1-60s*/ + public short bySensitivity; /* 灵敏度参数,范围[1,5] */ + public short byHeightThreshold; //高度阈值,范围[0,250],默认90,单位:厘米 + public byte[] byRes = new byte[4]; + } + + public static final int MAX_INTRUSIONREGION_NUM = 8; //最大区域数数 + + public static class NET_VCA_FIELDDETECION extends HIKSDKStructure { + public int dwSize; + public byte byEnable; //使能,是否开启 + public byte byEnableDualVca;// 启用支持智能后检索 0-不启用,1-启用 + public byte byEnableHumanMisinfoFilter;// 启用人体去误报 0-不启用,1-启用 + public byte byEnableVehicleMisinfoFilter;// 启用车辆去误报 0-不启用,1-启用 + public NET_VCA_INTRUSION[] struIntrusion = new NET_VCA_INTRUSION[MAX_INTRUSIONREGION_NUM];//每个区域的参数设置 + public NET_DVR_SCHEDTIMEWEEK[] struAlarmSched = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS]; //布防时间 + public NET_DVR_HANDLEEXCEPTION_V40 struHandleException; //异常处理方式 + public int dwMaxRelRecordChanNum; //报警触发的录象通道 数(只读)最大支持数量 + public int dwRelRecordChanNum; //报警触发的录象通道 数 实际支持的数量 + public int[] byRelRecordChan = new int[MAX_CHANNUM_V30];//触发录像通道 + public NET_DVR_SCHEDTIME[] struHolidayTime = new NET_DVR_SCHEDTIME[MAX_TIMESEGMENT_V30]; //假日布防时间 + public byte[] byRes2 = new byte[100]; + } + + public static class NET_DVR_CHANNEL_GROUP extends HIKSDKStructure { + public int dwSize; + public int dwChannel; + public int dwGroup; + public byte byID; + public byte[] byRes1 = new byte[3]; + public int dwPositionNo; + public byte[] byRes = new byte[56]; + } + + //线结构参数 + public static class NET_VCA_LINE extends HIKSDKStructure { + public NET_VCA_POINT struStart; + public NET_VCA_POINT struEnd; + } + + //点坐标参数 + public static class NET_VCA_POINT extends HIKSDKStructure { + public float fX; + public float fY; + + + } + + //进入/离开区域参数 + public static class NET_VCA_AREA extends HIKSDKStructure { + public NET_VCA_POLYGON struRegion; + public byte bySensitivity; //灵敏度参数,范围[1,5] + /* + 检测目标,可支持多选,具体定义为: + 0~所有目标(表示不锁定检测目标,所有目标都将进行检测) + 0x01 ~ 人, + 0x02 ~ 车, + 0x04 ~ 其他, + 该字段支持多选,按位取值,例如3表示1+2. + */ + public byte byDetectionTarget; + public byte byPriority;//优先级,0~低,1~中,2~高 + public byte[] byRes = new byte[5]; + } + + //多边形结构体 + public static class NET_VCA_POLYGON extends HIKSDKStructure { + public int dwPointNum; + public NET_VCA_POINT[] struPos = new NET_VCA_POINT[VCA_MAX_POLYGON_POINT_NUM]; + } + + public static class NET_VCA_SIZE_FILTER extends HIKSDKStructure { + public byte byActive; //是否激活尺寸过滤器 0-否 非0-是 + public byte byMode; //过滤器模式SIZE_FILTER_MODE + public byte[] byRes = new byte[2]; //保留,置0 + public NET_VCA_RECT struMiniRect; //最小目标框,全0表示不设置 + public NET_VCA_RECT struMaxRect; //最大目标框,全0表示不设置 + } + + + //尺寸过滤策略 + public static class NET_VCA_FILTER_STRATEGY extends HIKSDKStructure { + public byte byStrategy; //尺寸过滤策略 0 - 不启用 1-高度和宽度过滤,2-面积过滤 + public byte[] byRes = new byte[11]; //保留 + } + + //异常行为检测报警 + public static class NET_VCA_RULE_ALARM extends HIKSDKStructure { + public int dwSize; + public int dwRelativeTime; + public int dwAbsTime; + public NET_VCA_RULE_INFO struRuleInfo; + public NET_VCA_TARGET_INFO struTargetInfo; + public NET_VCA_DEV_INFO struDevInfo; + public int dwPicDataLen; + public byte byPicType; + public byte byRelAlarmPicNum; //关联通道报警图片数量 + public byte bySmart;//IDS设备返回0(默认值),Smart Functiom Return 1 + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public int dwAlarmID; //报警ID,用以标识通道间关联产生的组合报警,0表示无效 + public short wDevInfoIvmsChannelEx; //与NET_VCA_DEV_INFO里的byIvmsChannel含义相同,能表示更大的值。老客户端用byIvmsChannel能继续兼容,但是最大到255。新客户端版本请使用wDevInfoIvmsChannelEx。 + public byte byRelativeTimeFlag; //dwRelativeTime字段是否有效 0-无效, 1-有效,dwRelativeTime表示UTC时间 + public byte byAppendInfoUploadEnabled; //附加信息上传使能 0-不上传 1-上传 + public Pointer pAppendInfo; //指向附加信息NET_VCA_APPEND_INFO的指针,byAppendInfoUploadEnabled为1时或者byTimeDiffFlag为1时有效 + public Pointer pImage; + } + + public static class NET_DVR_SYSTEM_TIME extends HIKSDKStructure { + public short wYear; //年 + public short wMonth; //月 + public short wDay; //日 + public short wHour; //时 + public short wMinute; //分 + public short wSecond; //秒 + public short wMilliSec; //毫秒 + public byte[] byRes = new byte[2]; + } + + //设备支持AI开放平台接入,上传视频检测数据 + public static class NET_AIOP_VIDEO_HEAD extends HIKSDKStructure { + public int dwSize; //dwSize = sizeof(NET_AIOP_VIDEO_HEAD) + public int dwChannel; //设备分析通道的通道号; + public NET_DVR_SYSTEM_TIME struTime = new NET_DVR_SYSTEM_TIME(); //时间 + public byte[] szTaskID = new byte[64]; //视频任务ID,来自于视频任务派发 + public int dwAIOPDataSize; //对应AIOPDdata数据长度 + public int dwPictureSize; //对应分析图片长度 + public byte[] szMPID = new byte[64]; //检测模型包ID,用于匹配AIOP的检测数据解析;可以通过URI(GET /ISAPI/Intelligent/AIOpenPlatform/algorithmModel/management?format=json)获取当前设备加载的模型包的label description信息; + public Pointer pBufferAIOPData; //AIOPDdata数据 + public Pointer pBufferPicture;//对应分析图片数据 + public byte byPictureMode;//图片数据传输模式 0-二进制,1-武汉云云存储,当byPictureMode为0时pBufferPicture为二进制数据,当byPictureMode为1时pBufferPicture为武汉云URL + public byte[] byRes2 = new byte[3];//保留字节 + public int dwPresetIndex; //预置点序号 + public byte[] byRes = new byte[176]; + } + + //设备支持AI开放平台接入,上传图片检测数据 + public static class NET_AIOP_PICTURE_HEAD extends HIKSDKStructure { + public int dwSize; //dwSize = sizeof(NET_AIOP_PICTURE_HEAD) + public NET_DVR_SYSTEM_TIME struTime = new NET_DVR_SYSTEM_TIME(); //时间 + public byte[] szPID = new byte[64]; //透传下发的图片ID,来自于图片任务派发 + public int dwAIOPDataSize; //对应AIOPDdata数据长度 + public byte byStatus; //状态值:0-成功,1-图片大小错误 + public byte[] byRes1 = new byte[3]; + public byte[] szMPID = new byte[64]; //检测模型包ID,用于匹配AIOP的检测数据解析; + public Pointer pBufferAIOPData;//AIOPDdata数据 + public int dwPresetIndex; //预置点序号 + public byte[] byRes = new byte[180]; + } + + + public static class NET_DVR_AI_PICTUR_UPLOAD extends HIKSDKStructure { + public int dwSize; + public byte[] szTaskID = new byte[64]; //任务id,strlen.max = 64,业务平台统一维护管理 + public byte[] szPID = new byte[64]; //图片id,strlen.max = 64,业务平台统一维护管理 + public byte[] byRes = new byte[128]; + } + + // AI开放平台接入轮询视频检测报警结构体。 + public static class NET_AIOP_POLLING_SNAP_HEAD extends HIKSDKStructure { + public int dwSize; //dwSize = sizeof(NET_AIOP_POLLING_SNAP_HEAD) + public int dwChannel; //设备分析通道的通道号(走SDK协议); + public NET_DVR_SYSTEM_TIME struTime = new NET_DVR_SYSTEM_TIME(); //时间 + public byte[] szTaskID = new byte[64]; //轮询抓图任务ID,来自于轮询抓图任务派发 + public int dwAIOPDataSize; //对应AIOPDdata数据长度 + public int dwPictureSize; //对应分析图片长度 + public byte[] szMPID = new byte[64]; //检测模型包ID,用于匹配AIOP的检测数据解析; + public Pointer pBufferAIOPData;//AIOPDdata数据 + public Pointer pBufferPicture;//分析图片数据 + public byte byPictureMode;//图片数据传输模式 0-二进制,1-武汉云云存储,当byPictureMode为0时pBufferPicture为二进制数据,当byPictureMode为1时pBufferPicture为武汉云URL + public byte[] byRes2 = new byte[3];//保留字节 + public int dwPresetIndex; //预置点序号 + public byte[] byRes = new byte[176]; + } + + // AI开放平台接入轮询视频检测报警结构体。 + public static class NET_AIOP_POLLING_VIDEO_HEAD extends HIKSDKStructure { + public int dwSize; //dwSize = sizeof(NET_AIOP_POLLING_VIDEO_HEAD) + public int dwChannel; //设备分析通道的通道号(走SDK协议); + public NET_DVR_SYSTEM_TIME struTime; //时间 + public byte[] szTaskID = new byte[64]; //轮询抓图任务ID,来自于轮询抓图任务派发 + public int dwAIOPDataSize; //对应AIOPDdata数据长度 + public int dwPictureSize; //对应分析图片长度 + public byte[] szMPID = new byte[64]; //检测模型包ID,用于匹配AIOP的检测数据解析; + public Pointer pBufferAIOPData;//AIOPDdata数据 + public Pointer pBufferPicture;//对应分析图片数据 + public byte byPictureMode;//图片数据传输模式 0-二进制,1-武汉云云存储,当byPictureMode为0时pBufferPicture为二进制数据,当byPictureMode为1时pBufferPicture为武汉云URL + public byte[] byRes2 = new byte[3];//保留字节 + public int dwPresetIndex; //预置点序号 + public byte[] byRes = new byte[176]; + } + + //规则触发参数 + public static class NET_VCA_RULE_TRIGGER_PARAM extends HIKSDKStructure { + public byte byTriggerMode; //规则的触发方式,0- 不启用,1- 点 2- 目标面积 + public byte byTriggerPoint; //触发点,触发方式为点时有效 0- 中,1-上,2-下 + public byte[] byRes1 = new byte[2]; //保留 + public float fTriggerArea; //触发目标面积百分比 [0,100],触发方式为目标面积时有效 + public byte[] byRes2 = new byte[4]; //保留 + } + + public static class NET_VCA_ONE_RULE_V42 extends HIKSDKStructure { + public byte byActive; //是否激活规则, 0-否,非0-是 + public byte byEventPriority;//事件优先级 0-低,1-中,2-高 + public byte[] byRes1 = new byte[4]; //保留,设置为0字段 + public short wEventType; //行为事件类型,参考VCA_RULE_EVENT_TYPE_EX + public byte[] byRuleName = new byte[NAME_LEN/*32*/]; //规则名称 + public NET_VCA_EVENT_UNION uEventParam; //异常行为检测事件参数 + public NET_VCA_SIZE_FILTER struSizeFilter; //尺寸过滤器 + public NET_DVR_SCHEDTIMEWEEK[] struAlarmTime = new NET_DVR_SCHEDTIMEWEEK[MAX_DAYS];//布防时间 + public NET_DVR_HANDLEEXCEPTION_V40 struAlarmHandleType; /*处理方式*/ + //异常处理方式中报警输出号与组号绑定,即组号为0时,表示关联的报警输出号范围为1-64,当组号为1时,表示关联的报警输出号范围为65-128, 且是组内紧凑排列,如果遇到0xffffffff表示本组 当前的及组内后续的报警出号无效 + public int[] dwRelRecordChan = new int[MAX_CHANNUM_V30]; /* 报警触发的录象通道(四字节的通道号,初始值是 0xffffffff)*/ + //关联的录像通道号与组号绑定,即组号为0时,表示关联的通道号范围为1-64,当组号为1时,表示关联的通道号范围为65-128, 且是组内紧凑排列,如果遇到0xffffffff表示本组 当前的及组内后续的关联通道号无效 + public short wAlarmDelay; //智能报警延时,0-5s,1-10,2-30s,3-60s,4-120s,5-300s,6-600s + public byte[] byRes2 = new byte[2]; //保留 + public NET_VCA_FILTER_STRATEGY struFilterStrategy; //尺寸过滤策略 + public NET_VCA_RULE_TRIGGER_PARAM struTriggerParam; //规则触发参数 + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_PTZ_POSITION extends HIKSDKStructure { + // 是否启用场景,在设置场景行为规则的时候该字段无效,在设置球机本地配置场景位置信息时作为使能位 + public byte byEnable; + public byte[] byRes1 = new byte[3]; //保留 + public byte[] byPtzPositionName = new byte[NAME_LEN]; //场景位置名称 + public NET_DVR_PTZPOS struPtzPos; //ptz 坐标 + public byte[] byRes2 = new byte[40]; + } + + //异常行为检测配置结构体 + public static class NET_VCA_RULECFG_V42 extends HIKSDKStructure { + public int dwSize; //结构图大小 + public byte byPicProType; //报警时图片处理方式 0-不处理 1-上传 + public byte byUpLastAlarm; //是否先上传最近一次的报警,0-否,1-是 + public byte byPicRecordEnable; //是否启用图片存储, 0-不启用, 1-启用 + public byte byRes1; + public NET_DVR_JPEGPARA struPicParam; //图片规格结构 + public NET_VCA_ONE_RULE_V42[] struRule = new NET_VCA_ONE_RULE_V42[16]; /* 规则数组*/ + public short[] wRelSnapChan = new short[3]; //关联抓图通道,当主通道报警时,同时会上传关联通道的抓拍图片,0表示不关联,其他值为关联通道号 + public byte byTrackEnable; //是否启用 + public byte byRes2; + public NET_DVR_PTZ_POSITION struPTZPosition; //场景位置信息 + public short wTrackDuration; //持续时间,单位s + public short wIntervalTime; //单次报警间隔时间(秒)[1-7200](ˆ默认为600) + public short wHeightLimit;//目标检测高度下限(厘米)[0-250](默认为80cm),小于此高度的目标将不作为目标进行检测 + public byte[] byRes = new byte[58];//保留 + } + + public static final int CID_CODE_LEN = 4; + public static final int DEV_SERIAL_LEN = 9; + public static final int ACCOUNTNUM_LEN = 6; + public static final int ACCOUNTNUM_LEN_32 = 32; + + public static class NET_DVR_CID_ALARM extends HIKSDKStructure { + public int dwSize; + public byte[] sCIDCode = new byte[CID_CODE_LEN/*4*/]; //CID事件号 + public byte[] sCIDDescribe = new byte[NAME_LEN/*32*/]; //CID事件名 + public NET_DVR_TIME_EX struTriggerTime = new NET_DVR_TIME_EX(); //触发报警的时间点 + public NET_DVR_TIME_EX struUploadTime = new NET_DVR_TIME_EX(); //上传报警的时间点 + public byte[] sCenterAccount = new byte[ACCOUNTNUM_LEN/*6*/]; //中心帐号 + public byte byReportType; //见定义NET_DVR_ALARMHOST_REPORT_TYPE + public byte byUserType; //用户类型,0-网络用户 1-键盘用户,2-手机用户,3-系统用户 + public byte[] sUserName = new byte[NAME_LEN/*32*/]; //网络用户用户名 + public short wKeyUserNo; //键盘用户号 0xFFFF表示无效 + public byte byKeypadNo; //键盘号 0xFF表示无效 + public byte bySubSysNo; //子系统号 0xFF表示无效 + public short wDefenceNo; //防区号 0xFFFF表示无效 + public byte byVideoChanNo; //视频通道号 0xFF表示无效 + public byte byDiskNo; //硬盘号 0xFF表示无效 + public short wModuleAddr; //模块地址 0xFFFF表示无效 + public byte byCenterType; //0-无效, 1-中心账号(长度6),2-扩展的中心账号(长度9) + public byte byRes1; + public byte[] sCenterAccountV40 = new byte[ACCOUNTNUM_LEN_32/*32*/]; //中心账号V40,使用此字段时sCenterAccount无效 + public byte[] byDevSerialNo = new byte[DEV_SERIAL_LEN]; /*产品序列号*/ + public byte byRepeaterNo; //中继器号,为0无效 + public short wRemoteCtrllerUserNo; //遥控器用户号,为0无效 + public int dwIOTChannelNo; //IOT通道号 + public byte[] byRes2 = new byte[12]; + } + + public static class NET_DVR_SENSOR_ALARM extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public int dwAbsTime; // 绝对时标信息 OSD显示信息 + public byte[] byName = new byte[NAME_LEN]; // sensor 名称 + public byte bySensorChannel; // 模拟量通道 + public byte byType; // 模拟量类型 + public byte byAlarmType; // 1-上4、2-上3、3-上2、4-上1、5-下1、6-下2、7-下3、8-下4 和当前模式有关 + // 例如当为1000时,有上1下1,2,3报警四种报警 + public byte byAlarmMode; //报警模式,五种,-HHHH、-HHHL、-HHLL、HLLL、-LLLL, 作为平台报警程度判断功能,即:1111(上上上上),1110(上上上下),1100(上上下下),1000(上下下下),0000(下下下下) + public float fValue; // 但前模拟量的值 + public float fOriginalValue; //原始电流电压值,保留小数点后三位,具体值表示电流还是电压根据NET_DVR_SENSOR_INFO的bySensorStandard类型 + public byte[] byRes2 = new byte[28]; // 保留字节 + } + + //开关量报警上传 + public static class NET_DVR_SWITCH_ALARM extends HIKSDKStructure { + public int dwSize; + public byte[] byName = new byte[NAME_LEN]; // switch 名称 + public short wSwitchChannel; // 开关量通道, 0-255 + public byte byAlarmType; // 报警类型 0--正常,1--短路,2--断路,3-异常 + public byte[] byRes = new byte[41]; // 保留字节 + } + + public static class NET_DVR_ALARMHOST_EXCEPTION_ALARM extends HIKSDKStructure { + public int dwSize; // 结构体大小 + // 异常参数 1-设备防拆报警 2-设备防拆后后恢复正常 3-主电源掉电报警 4-主电源掉电后恢复正常 5-内部通信故障报警 + // 6-内部通信故障后恢复正常 7-电话线断线 8-电话线断线恢复 9-自检失败报警 10-自检失败后恢复正常 + // 11蓄电池欠压 12蓄电池电压恢复正常,13-蓄电池故障;14-MBUS模块掉线;15-MBUS模块掉线恢复;16-键盘掉线; + //17-键盘掉线恢复;18-设备被移动;19-设备被移动复位 20-485外设线路断报警 21-485外设线路断后恢复正常 + //25-子板1插上,26-子板1拔出, 27-子板2插上,28-子板2拔出 + public int dwExceptionType; + public byte[] byRes = new byte[36]; // 保留 + } + + + public static class NET_DVR_ALARMHOST_POINT_VALUE extends HIKSDKStructure { + public byte byChanType; //接入类型,1-本地模拟量通道,2-本地开关量通道,3-485通道,4-网络通道 + public byte byPointType; //点类型,1-遥测(模拟量),2-遥信(开关量) + public byte[] byRes1 = new byte[2]; //保留 + public int dwChanNo; //485通道号,0xffffffff表示无效,通道类型为1时:表示本地模拟量通道号,通道类型为2时表示本地开关量通道号,通道类型为3时表示485通道号。 + public int dwSubChanNo; //槽位号, 0xffffffff表示无效,通道类型为3时使用 + public int dwVariableNo; //变量编号,0xffffffff表示无效 + public int dwPointNo; //104点号,0xffffffff表示无效 + public int iValue; //监测点的值,表示低32位 + public int iValueEx; //监测点的值,表示高32位 + public byte[] byRes = new byte[12]; + } + + public static class NET_DVR_ALARMHOST_DATA_UNION extends HIKSDKStructure { + public byte[] byLength = new byte[40]; + public NET_DVR_ALARMHOST_POINT_VALUE struPointValue; //监测点实时数据 + } + + public static class NET_DVR_ALARMHOST_DATA_UPLOAD extends HIKSDKStructure { + public int dwSize; + public byte byDataType; //数据类型,1-监测点实时数据上传 + public byte[] byRes1 = new byte[3]; + public NET_DVR_ALARMHOST_DATA_UNION struAlarmData; + public byte[] byRes2 = new byte[32]; + } + + //车牌识别结果子结构 + public static class NET_DVR_PLATE_INFO extends HIKSDKStructure { + public byte byPlateType; //车牌类型 + public byte byColor; //车牌颜色 + public byte byBright; //车牌亮度 + public byte byLicenseLen; //车牌字符个数 + public byte byEntireBelieve; //整个车牌的置信度,-100 + public byte byRegion; // 区域索引值 0-保留,1-欧洲(EU),3-欧洲&(EU&CIS) ,4-中东(ME),0xff-所有 + public byte byCountry; // 国家索引值,参照枚举COUNTRY_INDEX(不支持"COUNTRY_ALL = 0xff, //ALL 全部") + public byte byArea; //区域(省份),各国家内部区域枚举,阿联酋参照 EMI_AREA + public byte byPlateSize; //车牌尺寸,0~未知,1~long, 2~short(中东车牌使用) + public byte byAddInfoFlag; + public short wCRIndex;//国家/地区索引,索引值参考_CR_ INDEX_ + public byte[] byRes = new byte[12]; //保留 + public byte[] sPlateCategory = new byte[8];//车牌附加信息, 即中东车牌中车牌号码旁边的小字信息,(目前只有中东地区支持) + public int dwXmlLen; //XML报警信息长度 + public Pointer pXmlBuf; // XML报警信息指针,报警类型为 COMM_ITS_PLATE_RESUL时有效,其XML对应到EventNotificationAlert XML Block + public NET_VCA_RECT struPlateRect = new NET_VCA_RECT(); //车牌位置 + public byte[] sLicense = new byte[MAX_LICENSE_LEN]; //车牌号码,注:中东车牌需求把小字也纳入车牌号码,小字和车牌号中间用空格分隔 + public byte[] byBelieve = new byte[MAX_LICENSE_LEN]; //各个识别字符的置信度,如检测到车牌"浙A12345", 置信度为,20,30,40,50,60,70,则表示"浙"字正确的可能性只有%,"A"字的正确的可能性是% + } + + public static class NET_DVR_VEHICLE_INFO extends HIKSDKStructure { + public int dwIndex; //车辆序号 + public byte byVehicleType; //车辆类型 0 表示其它车型,1 表示小型车,2 表示大型车 ,3表示行人触发 ,4表示二轮车触发 5表示三轮车触发(3.5Ver) + public byte byColorDepth; //车身颜色深浅 + public byte byColor; //车身颜色,参考VCR_CLR_CLASS + /*雷达异常状态: + 0~雷达正常, + 1~雷达故障 + 2~雷达一直发送某一个相同速度值 + 3~雷达送出数据为0 + 4~雷达送出数据过大或者过小 + */ + public byte byRadarState; + public short wSpeed; //单位km/h + public short wLength; //前一辆车的车身长度 + /*违规类型,0-正常,1-低速,2-超速,3-逆行,4-闯红灯,5-压车道线,6-不按导向,7-路口滞留, + 8-机占非,9-违法变道,10-不按车道 11-违反禁令,12-路口停车,13-绿灯停车, 14-未礼让行人(违法代码1357), + 15-违章停车,16-违章掉头,17-占用应急车道,18-禁右,19-禁左,20-压黄线,21-未系安全带,22-行人闯红灯,23-加塞,24-违法使用远光灯, + 25-驾驶时拨打接听手持电话,26-左转不让直行,27-右转不让左转,28-掉头不让直行,29-大弯小转, 30-闯绿灯,31-未带头盔, + 32-非机动车载人,33-非机动车占用机动车道,34-非机动车打伞棚, 35-黑烟车, 36-鸣笛*/ + public byte byIllegalType; + public byte byVehicleLogoRecog; //参考枚举类型 VLR_VEHICLE_CLASS + public byte byVehicleSubLogoRecog; //车辆品牌子类型识别;参考VSB_VOLKSWAGEN_CLASS等子类型枚举。 + public byte byVehicleModel; //车辆子品牌年款,0-未知,参考"车辆子品牌年款.xlsx" + public byte[] byCustomInfo = new byte[16]; //自定义信息 + public short wVehicleLogoRecog; //车辆主品牌,参考"车辆主品牌.xlsx" (该字段兼容byVehicleLogoRecog); + public byte byIsParking;//是否停车 0-无效,1-停车,2-未停车 + public byte byRes;//保留字节 + public int dwParkingTime; //停车时间,单位:s + public byte[] byRes3 = new byte[8]; + } + + //手动抓拍 + public static class NET_DVR_MANUALSNAP extends HIKSDKStructure { + public byte byOSDEnable;//0-不关闭(默认),1-关闭 + public byte byLaneNo;//车道号, 范围为1-6,默认为1(抓拍机内部测试使用) + public byte byChannel;//通道号 + public byte[] byRes = new byte[21]; //保留 + } + + //交通抓拍结果信息 + public static class NET_DVR_PLATE_RESULT extends HIKSDKStructure { + public int dwSize; + public byte byResultType; + public byte byChanIndex; + public short wAlarmRecordID; + public int dwRelativeTime; + public byte[] byAbsTime = new byte[32]; + public int dwPicLen; + public int dwPicPlateLen; + public int dwVideoLen; + public byte byTrafficLight; + public byte byPicNum; + public byte byDriveChan; + public byte byVehicleType; + public int dwBinPicLen; + public int dwCarPicLen; + public int dwFarCarPicLen; + public Pointer pBuffer3; + public Pointer pBuffer4; + public Pointer pBuffer5; + public byte[] byRes3 = new byte[8]; + public NET_DVR_PLATE_INFO struPlateInfo; + public NET_DVR_VEHICLE_INFO struVehicleInfo; + public Pointer pBuffer1; + public Pointer pBuffer2; + } + + public static class NET_DVR_TIME_V30 extends HIKSDKStructure { + public short wYear; + public byte byMonth; + public byte byDay; + public byte byHour; + public byte byMinute; + public byte bySecond; + public byte byRes; + public short wMilliSec; + public byte[] byRes1 = new byte[2]; + + + } + + public static class NET_ITS_PICTURE_INFO extends HIKSDKStructure { + public int dwDataLen; + public byte byType; + public byte byDataType; + public byte byCloseUpType; + public byte byPicRecogMode; + public int dwRedLightTime; + public byte[] byAbsTime = new byte[32]; + public NET_VCA_RECT struPlateRect = new NET_VCA_RECT(); + public NET_VCA_RECT struPlateRecgRect = new NET_VCA_RECT(); + public Pointer pBuffer; + public int dwUTCTime;//UTC时间 + public byte byCompatibleAblity;//兼容能力字段,按位表示,值:0- 无效,1- 有效 + public byte byTimeDiffFlag; /*时差字段是否有效 0-时差无效, 1-时差有效 */ + public byte cTimeDifferenceH; /*与UTC的时差(小时),-12 ... +14, +表示东区,,byTimeDiffFlag为1时有效*/ + public byte cTimeDifferenceM; /*与UTC的时差(分钟),-30, 30, 45, +表示东区,byTimeDiffFlag为1时有效*/ + public byte[] byRes2 = new byte[4]; + } + + public static class NET_ITS_PLATE_RESULT extends HIKSDKStructure { + public int dwSize; + public int dwMatchNo; + public byte byGroupNum; + public byte byPicNo; + public byte bySecondCam; + public byte byFeaturePicNo; + public byte byDriveChan; + public byte byVehicleType; + public byte byDetSceneID; + public byte byVehicleAttribute; + public short wIllegalType; + public byte[] byIllegalSubType = new byte[8]; + public byte byPostPicNo; + public byte byChanIndex; + public short wSpeedLimit; + public byte byChanIndexEx; //byChanIndexEx*256+byChanIndex表示真实通道号。 + public byte byRes2; + public NET_DVR_PLATE_INFO struPlateInfo = new NET_DVR_PLATE_INFO(); + public NET_DVR_VEHICLE_INFO struVehicleInfo = new NET_DVR_VEHICLE_INFO(); + public byte[] byMonitoringSiteID = new byte[48]; + public byte[] byDeviceID = new byte[48]; + public byte byDir; + public byte byDetectType; + public byte byRelaLaneDirectionType; + public byte byCarDirectionType; + public int dwCustomIllegalType; + public Pointer pIllegalInfoBuf; + public byte byIllegalFromatType; + public byte byPendant; + public byte byDataAnalysis; + public byte byYellowLabelCar; + public byte byDangerousVehicles; + public byte byPilotSafebelt; + public byte byCopilotSafebelt; + public byte byPilotSunVisor; + public byte byCopilotSunVisor; + public byte byPilotCall; + public byte byBarrierGateCtrlType; + public byte byAlarmDataType; + public NET_DVR_TIME_V30 struSnapFirstPicTime = new NET_DVR_TIME_V30(); + public int dwIllegalTime; + public int dwPicNum; + public NET_ITS_PICTURE_INFO[] struPicInfo = new NET_ITS_PICTURE_INFO[6]; + } + + public int MAX_PARKNO_LEN = 16; //车位编号长度 + public int MAX_ID_LEN = 48; //编号最大长度 + + //停车场数据上传 + public static class NET_ITS_PARK_VEHICLE extends HIKSDKStructure { + public int dwSize; //结构长度 + public byte byGroupNum; //图片组数量(单次轮询抓拍的图片数量) + public byte byPicNo; //连拍的图片组上传图片序号(接收到图片组数量后,表示接收完成 + //接收超时不足图片组数量时,根据需要保留或删除) + public byte byLocationNum; //单张图片所管理的车位数 + public byte byParkError; //停车异常,0-正常 1 异常 + public byte[] byParkingNo = new byte[MAX_PARKNO_LEN];//车位编号 + public byte byLocationStatus; //车位车辆状态,0-无车,1有车 + public byte bylogicalLaneNum;//逻辑车位号,0-3,一个相机最大能管4个车位 (0代表最左边,3代表最右边) + public short wUpLoadType;//第零位表示:0~轮训上传、1~变化上传 + public byte[] byRes1 = new byte[4]; //保留字节 + public int dwChanIndex; //通道号数字通道 + public NET_DVR_PLATE_INFO struPlateInfo; //车牌信息结构 + public NET_DVR_VEHICLE_INFO struVehicleInfo; //车辆信息 + public byte[] byMonitoringSiteID = new byte[MAX_ID_LEN]; //监测点编号 + public byte[] byDeviceID = new byte[MAX_ID_LEN]; //设备编号 + public int dwPicNum; //图片数量(与picGroupNum不同,代表本条信息附带的图片数量,图片信息由struVehicleInfoEx定义 + public NET_ITS_PICTURE_INFO[] struPicInfo = new NET_ITS_PICTURE_INFO[2]; //图片信息,单张回调,最多2张图,由序号区分 + public byte[] byRes2 = new byte[256]; + } + + public static class NET_DVR_SNAPCFG extends HIKSDKStructure { + + public int dwSize; + public byte byRelatedDriveWay;//触发IO关联的车道号 + public byte bySnapTimes; //线圈抓拍次数,0-不抓拍,非0-连拍次数,目前最大5次 + public short wSnapWaitTime; //抓拍等待时间,单位ms,取值范围[0,60000] + public short[] wIntervalTime = new short[MAX_INTERVAL_NUM];//连拍间隔时间,ms + public int dwSnapVehicleNum; //抓拍车辆序号。 + public NET_DVR_JPEGPARA struJpegPara;//抓拍图片参数 + public byte[] byRes2 = new byte[16]; + } + + // 道闸控制 + public static class NET_DVR_BARRIERGATE_CFG extends HIKSDKStructure { + public int dwSize; + public int dwChannel; //通道号 + public byte byLaneNo; //道闸号(0-表示无效值(设备需要做有效值判断),1-道闸1) + /* + 若老的平台不支持byUnlock字段,该字段将赋值为0,通过“0-关闭道闸,1-开启道闸,2-停止道闸”中的任何一种操作皆可进行解锁。 + 若新平台支持byUnlock字段,需byUnlock字段赋值为1,并结合4~解锁道闸来进行解锁。byUnlock字段赋值为1后,“0-关闭道闸,1-开启道闸,2-停止道闸”操作将不可用于解锁。 + */ + public byte byBarrierGateCtrl;//0-关闭道闸,1-开启道闸,2-停止道闸 3-锁定道闸,4~解锁道闸 + public byte byEntranceNo;//出入口编号 [1,8] + public byte byUnlock;//启用解锁使能,0~为不启用,1~启用 + public byte[] byRes = new byte[12]; + } + + + public static class NET_DVR_GROUP_PARAM extends HIKSDKStructure { + public int dwTeenage;//少年(人数) + public int dwYouth;//青年(人数) + public int dwMidLife;//中年(人数) + public int dwElderly;//老年(人数) + public int dwChild;//儿童(人数) + public int dwAdolescent;//青少年(人数) + public int dwPrime;//壮年(人数) + public int dwMidage;//中老年(人数) + public byte[] byRes = new byte[48]; + } + + public static class NET_DVR_SEXGROUP_PARAM extends HIKSDKStructure { + public int dwMale;//男(人数) + public int dwFemale;//女(人数) + public byte[] byRes = new byte[64]; + } + + public static class NET_DVR_PROGRAM_INFO extends HIKSDKStructure { + public int dwProgramNo; //节目编号 + public byte[] sProgramName = new byte[NAME_LEN]; //节目名称 + public byte[] byRes = new byte[16]; + } + + public static class NET_DVR_FACECAPTURE_STATISTICS_RESULT extends HIKSDKStructure { + public int dwSize; + public NET_DVR_TIME_EX struStartTime;/*间隔开始时间*/ + public NET_DVR_TIME_EX struEndTime;/*间隔结束时间*/ + public byte byStatType;//数据类型统计:Bit0-年龄段有效,Bit1-性别有效,Bit2-人数有效 + public byte[] byRes = new byte[7]; + public int dwPeopleNum;//人数统计 + public byte[] byRes2=new byte[80]; // + public NET_DVR_SEXGROUP_PARAM struSexGroupParam;//性别人数统计 + public NET_DVR_PROGRAM_INFO struProgramInfo; //节目信息 + public byte[] byRes1 = new byte[76]; + } + + //获取交通数据条件结构 + public static class NET_DVR_TRAFFIC_DATA_QUERY_COND extends HIKSDKStructure { + public int dwSize; + /* + Bit0-通道有效 + Bit1-时间有效 + Bit2-车牌号有效 + Bit3-车牌类型有效 + Bit4-车牌颜色有效 + Bit5-车身颜色有效 + Bit6-车辆类型有效 + Bit7-车辆品牌有效 + Bit8-车道号有效 + Bit9-监测方向有效 + Bit10-最低速度有效 + Bit11-最高速度有效 + Bit12-数据类型有效 + Bit13-布防方式类型有效 + Bit14-违法取证有效 + Bit15-事件类型有效 + Bit16-取证类型有效 + */ + public int dwQueryCond;//查询条件 0表示无效,1表示有效 + public int dwChannel;//默认是1([1~32],bit0表示通道1,依次类推bit31表示通道32) + public NET_DVR_TIME_V30 struStartTime;//开始时间 + public NET_DVR_TIME_V30 struEndTime;//结束时间 + public byte[] sLicense = new byte[MAX_LICENSE_LEN/*16*/];//(设备支持模糊查询, GB2312编码) + /* + Bit0-未知(其他) + Bit1-标准民用车与特种车 + Bit2-02式民用车牌 + Bit3- + Bit4-警车 + Bit5-民用车双行尾牌 + Bit6-使馆车牌 + Bit7-农用车 + Bit8-摩托车 + */ + public int dwPlateType;//车牌类型(支持按位表示,可以复选) + /* + Bit0-未知(其他) + Bit1-黄色 + Bit2-白色 + Bit3-黑色 + Bit4-绿色 + Bit5-蓝色 + */ + public int dwPlateColor;//车牌颜色(支持按位表示,可以复选) + /* + Bit0-未ª知(其他) + Bit1-白色 + Bit2-银色 + Bit3-灰色 + Bit4-黑色 + Bit5-红色 + Bit6-深蓝色 + Bit7-蓝色 + Bit8-黄色 + Bit9-绿色 + Bit10-棕色 + Bit11-粉色 + Bit12-紫色 + Bit13-深灰色 + */ + public int dwVehicleColor;//车身颜色(支持按位表示,可以复选) + /* + Bit0-未知(其他) + Bit1-客车 + Bit2-大货车 + Bit3-轿车 + Bit4-面包车 + Bit5-小货车 + Bit6-行人 + Bit7-二轮车 + Bit8-三轮车 + Bit9-SUV/MPV + Bit10-中型客车 + */ + public int dwVehicleType;//车辆类型(支持按位表示,可以复选) + /** + * Bit0-其他(保留) + * Bit1-低速 + * Bit2-超速 + * Bit3-逆行 + * Bit4-闯红灯 + * Bit5-压车道线 + * Bit6-不按导向 + * Bit7-路口滞留 + * Bit8-机占非 + * Bit9-违法变道 + * Bit10-不按车道 + * Bit11-违反禁令 + * Bit12-路口停车 + * Bit13-绿灯停车 + * Bit14-未礼让行人 + * Bit15-违章停车 + * Bit16-违章掉头 + * Bit17-占用应急车道 + * Bit18-未系安全带 + */ + public int dwIllegalType; + /** + * Bit0-其他(保留) + * Bit1-拥堵 + * Bit2-停车 + * Bit3-逆行 + * Bit4-行人 + * Bit5-抛洒物 + * Bit6-烟雾 + * Bit7-压线 + * Bit8-禁止名单 + * Bit9-超速 + * Bit10-变道 + * Bit11-掉头 + * Bit12-机占非 + * Bit13-加塞 + */ + public int dwEventType; + /** + * Bit0-其他(保留) + * Bit1-城市公路违法停车 + * Bit2-高速公路违法停车 + * Bit3-压线 + * Bit4-逆行 + * Bit5-违法变道 + * Bit6-机占非 + */ + public int dwForensiceType; + public short wVehicleLogoRecog; //车辆主品牌,参考"车辆主品牌.xlsx" (仅单选) + public byte byLaneNo;//车道号(0~255,0号车道 表示 车道号未知) + public byte byDirection;//监测方向,1-上行,2-下行,3-双向,4-由东向西,5-由南向北,6-由西向东,7-由北向南 + public short wMinSpeed;//最低速度(0~999)单位km/h + public short wMaxSpeed;//最高速度(0~999)单位km/h + public byte byDataType;//数据类型 0-卡口数据,1-违法数据,2-交通事件,3-取证数据 (仅单选) + public byte byExecuteCtrl;//布防 0-允许名单,1-禁止名单,0xff-其他 + public byte[] byRes = new byte[254]; + } + + public static final int MAX_TRAFFIC_PICTURE_NUM = 8; //交通图片数量 + + //交通数据结构体 + public static class NET_DVR_TRAFFIC_DATA_QUERY_RESULT extends HIKSDKStructure { + public int dwSize; + public int dwChannel;//默认是1([1~32]) + public byte[] sLicense = new byte[MAX_LICENSE_LEN/*16*/]; + /* + Bit0-未知(其他) + Bit1-标准民用车与特种车 + Bit2-02式民用车牌 + Bit4-警车 + Bit5-民用车双行尾牌 + Bit6-使馆车牌 + Bit7-农用车 + Bit8-摩托车 + */ + public int dwPlateType;//车牌类型 + /* + Bit0-未知(其他) + Bit1-黄色 + Bit2-白色 + Bit3-黑色 + Bit4-绿色 + Bit5-蓝色 + */ + public int dwPlateColor;//车牌颜色 + /* + Bit0-未知(其他) + Bit1-白色 + Bit2-银色 + Bit3-灰色 + Bit4-黑色 + Bit5-红色 + Bit6-深蓝色 + Bit7-蓝色 + Bit8-黄色 + Bit9-绿色 + Bit10-棕色 + Bit11-粉色 + Bit12-紫色 + Bit13-深灰色 + */ + public int dwVehicleColor;//车身颜色 + /* + Bit0-未知(其他) + Bit1-客车 + Bit2-大货车 + Bit3-轿车 + Bit4-面包车 + Bit5-小货车 + Bit6-行人 + Bit7-二轮车 + Bit8-三轮车 + Bit9-SUV/MPV + Bit10-中型客车 + Bit11-机动车 + Bit12-非机动车 + Bit13-小型轿车 + Bit14-微型轿车 + Bit15-皮卡车 + Bit16-集装箱卡车 + Bit17-微卡,栏板卡 + Bit18-渣土车 + Bit19-吊车,工程车 + Bit20-油罐车 + Bit21-混凝土搅拌车 + Bit22-平板拖车 + Bit23-两厢轿车 + Bit24-三厢轿车 + Bit25-轿跑 + Bit26-小型客车 + */ + public int dwVehicleType;//车辆类型 + /** + * Bit0-其他(保留) + * Bit1-低速 + * Bit2-超速 + * Bit3-逆行 + * Bit4-闯红灯 + * Bit5-压车道线 + * Bit6-不按导向 + * Bit7-路口滞留 + * Bit8-机占非 + * Bit9-违法变道 + * Bit10-不按车道 + * Bit11-违反禁令 + * Bit12-路口停车 + * Bit13-绿灯停车 + * Bit14-未礼让行人 + * Bit15-违章停车 + * Bit16-违章掉头 + * Bit17-占用应急车道 + * Bit18-未系安全带 + */ + public int dwIllegalType; + /** + * Bit0-其他(保留) + * Bit1-拥堵 + * Bit2-停车 + * Bit3-逆行 + * Bit4-行人 + * Bit5-抛洒物 + * Bit6-烟雾 + * Bit7-压线 + * Bit8-禁止名单 + * Bit9-超速 + * Bit10-变道 + * Bit11-掉头 + * Bit12-机占非 + * Bit13-加塞 + */ + public int dwEventType; + /** + * Bit0-其他(保留) + * Bit1-城市公路违法停车 + * Bit2-高速公路违法停车 + * Bit3-压线 + * Bit4-逆行 + * Bit5-违法变道 + * Bit6-机占非 + */ + public int dwForensiceType; + public short wVehicleLogoRecog; //车辆主品牌,参考"车辆主品牌.xlsx" + public byte byLaneNo;//车道号(0~255,0号车道 表示 车道号未知) + public byte byDirection;//监测方向,1-上行,2-下行,3-双向,4-由东向西,5-由南向北,6-由西向东,7-由北向南 + public short wSpeed;//速度(0~999)单位km/h + public byte byDataType;//数据类型: 0-卡口 1-违法 2-事件 3-取证 + public byte[] byRes = new byte[253]; + public NET_DVR_TRAFFIC_PICTURE_PARAM[] struTrafficPic = new NET_DVR_TRAFFIC_PICTURE_PARAM[MAX_TRAFFIC_PICTURE_NUM/*8*/]; + } + + //交通图片参数子结构 + public static final int PICTURE_NAME_LEN = 64; + + public static class NET_DVR_TRAFFIC_PICTURE_PARAM extends HIKSDKStructure { + public NET_DVR_TIME_V30 struRelativeTime = new NET_DVR_TIME_V30(); //抓拍相对时标 + public NET_DVR_TIME_V30 struAbsTime = new NET_DVR_TIME_V30(); //抓拍绝对时标 + public byte[] szPicName = new byte[PICTURE_NAME_LEN/*64*/]; + public byte byPicType;//图片类型 0-车牌图,1-抓拍原图,2-合成图,3-特写图 + public byte[] byRes = new byte[63]; + } + + public static class NET_DVR_VEHICLE_CONTROL_COND extends HIKSDKStructure { + public int dwChannel; + public int dwOperateType; + public byte[] sLicense = new byte[MAX_LICENSE_LEN]; + public byte[] sCardNo = new byte[48]; + public byte byListType; + public byte[] byRes1 = new byte[3]; + public int dwDataIndex; + public byte[] byRes = new byte[116]; + } + + public static class NET_DVR_VEHICLE_CONTROL_LIST_INFO extends HIKSDKStructure { + public int dwSize; + public int dwChannel; + public int dwDataIndex; + public byte[] sLicense = new byte[16]; + public byte byListType; + public byte byPlateType; + public byte byPlateColor; + public byte[] byRes = new byte[21]; + public byte[] sCardNo = new byte[48]; + public NET_DVR_TIME_V30 struStartTime = new NET_DVR_TIME_V30(); + public NET_DVR_TIME_V30 struStopTime = new NET_DVR_TIME_V30(); + public byte[] sOperateIndex = new byte[32]; + public byte[] byRes1 = new byte[224]; + } + + //车辆报警 + public static class NET_DVR_VEHICLE_CONTROL_ALARM extends HIKSDKStructure { + public int dwSize; + public byte byListType; //名单属性:0-允许名单,1-禁止名单,2-临时名单 + public byte byPlateType; //车牌类型 + public byte byPlateColor; //车牌颜色 + public byte byRes1; + public byte[] sLicense = new byte[MAX_LICENSE_LEN];//车牌号码 + public byte[] sCardNo = new byte[MAX_CARDNO_LEN]; // 卡号 + public NET_DVR_TIME_V30 struAlarmTime = new NET_DVR_TIME_V30(); //报警时间 + public int dwChannel; //设备通道号,如果直连的是IPC,则为ipc通道号;如果连的DVR\nvr,则为DVR\NVR的通道号 + public int dwPicDataLen; //图片数据大小,0表示无图片,不为0是表示后面带图片数据 + public byte byPicType; //图片类型,0-JPEG + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public byte[] byRes3 = new byte[2]; + public Pointer pPicData; + public byte[] byRes2 = new byte[48]; + } + + public int MAX_LED_INFO_LEN = 512; + public int MAX_VOICE_INFO_LEN = 128; + + //LED屏幕显示参数 + public static class NET_DVR_LEDDISPLAY_CFG extends HIKSDKStructure { + public int dwSize;//结构体大小 + public byte[] sDisplayInfo = new byte[MAX_LED_INFO_LEN/*512*/]; // LED显示内容 + public byte byDisplayMode;//显示方式:0~左移,1~右移,2~立即显示 + public byte bySpeedType;//速度类型:0~快,1~中,2~慢 + public byte byShowPlateEnable;//显示车牌使能,0~关闭,1~启用 + public byte byRes1; + public int dwShowTime;//显示时长,1~60秒 + public byte[] byRes = new byte[128]; + } + + //语音播报控制参数 + public static class NET_DVR_VOICEBROADCAST_CFG extends HIKSDKStructure { + public int dwSize;//结构体大小 + public byte[] sInfo = new byte[MAX_VOICE_INFO_LEN/*128*/]; //语音播报内容 + public byte byBroadcastNum;// 语音播报次数, 1~10次 + public byte byIntervalTime;// 语音播报间隔时间,1~5s + public byte[] byRes = new byte[126]; + } + + //缴费金额信息 + public static class NET_DVR_CHARGEACCOUNT_CFG extends HIKSDKStructure { + public int dwSize;//结构体大小 + public float fAccount;//实际收费金额 + public byte[] byRes = new byte[128]; + } + + public static final int DOOR_NAME_LEN = 32; //门名称 + public static final int STRESS_PASSWORD_LEN = 8; //胁迫密码长度 + public static final int SUPER_PASSWORD_LEN = 8; //胁迫密码长度 + public static final int UNLOCK_PASSWORD_LEN = 8; // 解除密码长度 + + public static class NET_DVR_DOOR_CFG extends HIKSDKStructure { + public int dwSize; + public byte[] byDoorName = new byte[DOOR_NAME_LEN]; //门名称 + public byte byMagneticType; //门磁类型,0-常闭,1-常开 + public byte byOpenButtonType; //开门按钮类型,0-常闭,1-常开 + public byte byOpenDuration; //开门持续时间,1-255s(楼层继电器动作时间) + public byte byDisabledOpenDuration; //卡开门持续时间,1-255s + public byte byMagneticAlarmTimeout; //门磁检测超时报警时间,0-255s,0表示不报警 + public byte byEnableDoorLock; //是否启用闭门回锁,0-否,1-是 + public byte byEnableLeaderCard; //是否启用首卡常开功能,0-否,1-是 + public byte byLeaderCardMode; //首卡模式,0-不启用首卡功能,1-首卡常开模式,2-首卡授权模式(使用了此字段,则byEnableLeaderCard无效) + public int dwLeaderCardOpenDuration; //首卡常开持续时间,1-1440min + public byte[] byStressPassword = new byte[STRESS_PASSWORD_LEN]; //胁迫密码 + public byte[] bySuperPassword = new byte[SUPER_PASSWORD_LEN]; //超级密码 + public byte[] byUnlockPassword = new byte[UNLOCK_PASSWORD_LEN]; //解除码NET_DVR_LOCAL_CONTROLLER_STATUS + public byte byUseLocalController; //只读,是否连接在就地控制器上,0-否,1-是 + public byte byRes1; + public short wLocalControllerID; //只读,就地控制器序号,1-64,0代表未注册 + public short wLocalControllerDoorNumber; //只读,就地控制器的门编号,1-4,0代表未注册 + public short wLocalControllerStatus; //只读,就地控制器在线状态:0-离线,1-网络在线,2-环路1上的RS485串口1,3-环路1上的RS485串口2,4-环路2上的RS485串口1,5-环路2上的RS485串口2,6-环路3上的RS485串口1,7-环路3上的RS485串口2,8-环路4上的RS485串口1,9-环路4上的RS485串口2(只读) + public byte byLockInputCheck; //是否启用门锁输入检测(1字节,0不启用,1启用,默认不启用) + public byte byLockInputType; //门锁输入类型(1字节,0常闭,1常开,默认常闭) + public byte byDoorTerminalMode; //门相关端子工作模式(1字节,0防剪防短,1普通,默认防剪防短) + public byte byOpenButton; //是否启用开门按钮(1字节,0是,1否,默认是) + public byte byLadderControlDelayTime; //梯控访客延迟时间,1-255min + public byte[] byRes2 = new byte[43]; + } + + public static class NET_DVR_DOOR_STATUS_PLAN extends HIKSDKStructure { + public int dwSize; + public int dwTemplateNo; //计划模板编号,为0表示取消关联,恢复默认状态(普通状态) + public byte[] byRes = new byte[64]; + } + + + public static class NET_DVR_EVENT_CARD_LINKAGE_COND extends HIKSDKStructure { + public int dwSize; + public int dwEventID; //事件ID + public short wLocalControllerID; //就地控制器序号[1,64] + public byte[] byRes = new byte[106]; + } + + public static final int MAX_ALARMHOST_ALARMIN_NUM = 512;//网络报警主机最大报警输入口数 + public static final int MAX_ALARMHOST_ALARMOUT_NUM = 512;//网络报警主机最大报警输出口数 + + public static class NET_DVR_EVENT_CARD_LINKAGE_CFG_V50 extends HIKSDKStructure { + public int dwSize; //结构体大小 + public byte byProMode; //联动方式,0-事件,1-卡号, 2-MAC地址 + public byte[] byRes1 = new byte[3]; + public int dwEventSourceID; //事件源ID,当主类型为设备事件时无效, 当主类型是门事件时为门编号;当主类型为读卡器事件时,为读卡器ID;当为报警输入事件时为防区报警输入ID或事件报警输入ID。0xffffffff表示联动全部 + public NET_DVR_EVETN_CARD_LINKAGE_UNION uLinkageInfo = new NET_DVR_EVETN_CARD_LINKAGE_UNION(); //联动方式参数 + public byte[] byAlarmout = new byte[MAX_ALARMHOST_ALARMOUT_NUM]; //关联的报警输出号,按位表示,为0表示不关联,为1表示关联 + public byte[] byRes2 = new byte[32]; //保留 + public byte[] byOpenDoor = new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动开门,0-不联动,1-联动 + public byte[] byCloseDoor = new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动关门,0-不联动,1-联动 + public byte[] byNormalOpen = new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动常开,0-不联动,1-联动 + public byte[] byNormalClose = new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动常关,0-不联动,1-联动 + public byte byMainDevBuzzer; //主机蜂鸣器 0-不联动,1-联动输出 + public byte byCapturePic; //是否联动抓拍,0-不联动抓拍,1-联动抓拍 + public byte byRecordVideo; //是否联动录像,0-不联动录像,1-联动录像 + public byte[] byRes3 = new byte[29]; //保留 + public byte[] byReaderBuzzer = new byte[MAX_CARD_READER_NUM_512]; //联动读卡器蜂鸣器,按位表示,0-不联动,1-联动 + public byte[] byAlarmOutClose = new byte[MAX_ALARMHOST_ALARMOUT_NUM]; //关联报警输出关闭,按字节表示,为0表示不关联,为1表示关联 + public byte[] byAlarmInSetup = new byte[MAX_ALARMHOST_ALARMIN_NUM]; //关联防区布防,按字节表示,为0表示不关联,为1表示关联 + public byte[] byAlarmInClose = new byte[MAX_ALARMHOST_ALARMIN_NUM]; //关联防区撤防,按字节表示,为0表示不关联,为1表示关联 + public byte[] byRes = new byte[500]; //保留 + } + + public static class NET_DVR_EVENT_LINKAGE_CARD_CFG_V51 extends HIKSDKStructure { + public int dwSize; //结构体大小 + public byte byProMode; //联动方式,0-事件,1-卡号,2-MAC地址,3-工号(人员ID) + public byte[] byRes1=new byte[3]; + public int dwEventSourceID; //事件源ID,当主类型为设备事件时无效, 当主类型是门事件时为门编号;当主类型为读卡器事件时,为读卡器ID;当为报警输入事件时为防区报警输入ID或事件报警输入ID。0xffffffff表示联动全部 + public NET_DVR_EVETN_CARD_LINKAGE_UNION uLinkageInfo; //联动方式参数 + public byte[] byAlarmout=new byte[MAX_ALARMHOST_ALARMOUT_NUM]; //关联的报警输出号,按位表示,为0表示不关联,为1表示关联 + public byte[] byRes2=new byte[32]; //保留 + public byte[] byOpenDoor=new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动开门,0-不联动,1-联动 + public byte[] byCloseDoor=new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动关门,0-不联动,1-联动 + public byte[] byNormalOpen=new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动常开,0-不联动,1-联动 + public byte[] byNormalClose=new byte[MAX_DOOR_NUM_256]; //按位表示,是否联动常关,0-不联动,1-联动 + public byte byMainDevBuzzer; //主机蜂鸣器 0-不联动,1-联动输出 + public byte byCapturePic; //是否联动抓拍,0-不联动抓拍,1-联动抓拍 + public byte byRecordVideo; //是否联动录像,0-不联动录像,1-联动录像 + public byte byMainDevStopBuzzer; //主机停止蜂鸣 0-不联动,1-联动输出 + public short wAudioDisplayID; //联动语音播放ID:0-不联动,目前范围1-32 + public byte byAudioDisplayMode; //联动语音播放模式:0-关闭,1-单次播放,2-循环播放 + public byte[] byRes3=new byte[25]; //保留 + public byte[] byReaderBuzzer=new byte[MAX_CARD_READER_NUM_512]; //联动读卡器蜂鸣器,按位表示,0-不联动,1-联动 + public byte[] byAlarmOutClose=new byte[MAX_ALARMHOST_ALARMOUT_NUM]; //关联报警输出关闭,按字节表示,为0表示不关联,为1表示关联 + public byte[] byAlarmInSetup=new byte[MAX_ALARMHOST_ALARMIN_NUM]; //关联防区布防,按字节表示,为0表示不关联,为1表示关联 + public byte[] byAlarmInClose=new byte[MAX_ALARMHOST_ALARMIN_NUM]; //关联防区撤防,按字节表示,为0表示不关联,为1表示关联 + public byte[] byReaderStopBuzzer=new byte[MAX_CARD_READER_NUM_512]; //联动读卡器停止蜂鸣,按字节表示,0-不联动,1-联动 + public byte[] byRes=new byte[512]; //保留 + } + + + + + public static class NET_DVR_EVENT_LINKAGE_INFO extends HIKSDKStructure { + public short wMainEventType; //事件主类型,0-设备事件,1-报警输入事件,2-门事件,3-读卡器事件 + public short wSubEventType; //事件次类型 + public byte[] byRes = new byte[28]; + } + + public static class NET_DVR_EVETN_CARD_LINKAGE_UNION extends Union { + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //卡号 + public NET_DVR_EVENT_LINKAGE_INFO struEventLinkage; //事件联动时参数 + public byte[] byMACAddr = new byte[MACADDR_LEN]; //物理MAC地址 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + } + + //卡参数配置条件 + public static class NET_DVR_CARD_CFG_COND extends HIKSDKStructure { + public int dwSize; + public int dwCardNum; + public byte byCheckCardNo; + public byte[] ibyRes = new byte[31]; + } + + //获取卡参数的发送数据 + public static class NET_DVR_CARD_CFG_SEND_DATA extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[32]; + public byte[] byRes = new byte[16]; + } + + public static class CARDRIGHTPLAN extends HIKSDKStructure { + public byte[] byRightPlan = new byte[4]; + } + + //卡参数 + public static class NET_DVR_CARD_CFG extends HIKSDKStructure { + public int dwSize; + public int dwModifyParamType; + public byte[] byCardNo = new byte[32]; + public byte byCardValid; + public byte byCardType; + public byte byLeaderCard; + public byte byRes1; + public int dwDoorRight; + public NET_DVR_VALID_PERIOD_CFG struValid; + public int dwBelongGroup; + public byte[] byCardPassword = new byte[8]; + public CARDRIGHTPLAN[] byCardRightPlan = new CARDRIGHTPLAN[32]; + public int dwMaxSwipeTime; + public int dwSwipeTime; + public short wRoomNumber; + public short wFloorNumber; + public byte[] byRes2 = new byte[20]; + } + + public int ACS_CARD_NO_LEN = 32; //门禁卡号长度 + public int MAX_GROUP_NUM_128 = 128; //最大群组数 + public int MAX_DOOR_NUM_256 = 256; //最大门数 + public int CARD_PASSWORD_LEN = 8; //卡密码长度 + public int MAX_CARD_READER_NUM = 64; //最大读卡器数 + public int MAX_DOOR_CODE_LEN = 8; //房间代码长度 + public int MAX_LOCK_CODE_LEN = 8; //锁代码长度 + public int MAX_CARD_RIGHT_PLAN_NUM = 4; //卡权限最大计划个数 + public int MAX_CASE_SENSOR_NUM = 8; //最大case sensor触发器数 + + public static class CARDRIGHTPLAN_WORD extends HIKSDKStructure { + public short[] wRightPlan = new short[MAX_CARD_RIGHT_PLAN_NUM]; + } + + public static class NET_DVR_CARD_CFG_V50 extends HIKSDKStructure { + public int dwSize; + public int dwModifyParamType;//需要修改的卡参数,设置卡参数时有效,按位表示,每位代表一种参数,1为需要修改,0为不修改 + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //卡号 + public byte byCardValid; //卡是否有效,0-无效,1-有效(用于删除卡,设置时置为0进行删除,获取时此字段始终为1) + public byte byCardType; //卡类型,1-普通卡,3-禁止名单卡,4-巡更卡,5-胁迫卡,6-超级卡,7-来宾卡,8-解除卡,9-员工卡,10-应急卡,11-应急管理卡,默认普通卡 + public byte byLeaderCard; //是否为首卡,1-是,0-否 + public byte byRes1; + public byte[] byDoorRight = new byte[MAX_DOOR_NUM_256]; //门权限(楼层权限),按位表示,1为有权限,0为无权限,从低位到高位表示对门1-N是否有权限 + public NET_DVR_VALID_PERIOD_CFG struValid; //有效期参数 + public byte[] byBelongGroup = new byte[MAX_GROUP_NUM_128]; //所属群组,按字节表示,1-属于,0-不属于 + public byte[] byCardPassword = new byte[CARD_PASSWORD_LEN]; //卡密码 + public CARDRIGHTPLAN_WORD[] wCardRightPlan = new CARDRIGHTPLAN_WORD[MAX_DOOR_NUM_256]; //卡权限计划,取值为计划模板编号,同个门不同计划模板采用权限或的方式处理 + public int dwMaxSwipeTime; //最大刷卡次数,0为无次数限制(开锁次数) + public int dwSwipeTime; //已刷卡次数 + public short wRoomNumber; //房间号 + public short wFloorNumber; //层号 + public int dwEmployeeNo; //工号 + public byte[] byName = new byte[NAME_LEN]; //姓名 + public short wDepartmentNo; //部门编号 + public short wSchedulePlanNo; //排班计划编号 + public byte bySchedulePlanType; //排班计划类型:0-无意义、1-个人、2-部门 + public byte byRightType; //下发权限类型:0-普通发卡权限、1-二维码权限、2-蓝牙权限(可视对讲设备二维码权限配置项:房间号、卡号(虚拟卡号)、最大刷卡次数(开锁次数)、有效期参数;蓝牙权限:卡号(萤石APP账号)、其他参数配置与普通发卡权限一致) + public byte[] byRes2 = new byte[2]; + public int dwLockID; //锁ID + public byte[] byLockCode = new byte[MAX_LOCK_CODE_LEN]; //锁代码 + public byte[] byRoomCode = new byte[MAX_DOOR_CODE_LEN]; //房间代码 + public int dwCardRight; //卡权限 + public int dwPlanTemplate; //计划模板(每天)各时间段是否启用,按位表示,0--不启用,1-启用 + public int dwCardUserId; //持卡人ID + public byte byCardModelType; //0-空,1- S50,2- S70,3- FM1208 CPU卡,4- FM1216 CPU卡,5-国密CPU卡,6-身份证,7- NFC + public byte[] byRes3 = new byte[83]; + } + //有效期参数结构体 + public static class NET_DVR_VALID_PERIOD_CFG extends HIKSDKStructure { + public byte byEnable; + public byte byBeginTimeFlag; //是否限制起始时间的标志,0-不限制,1-限制 + public byte byEnableTimeFlag; //是否限制终止时间的标志,0-不限制,1-限制 + public byte byTimeDurationNo; //有效期索引,从0开始(时间段通过SDK设置给锁,后续在制卡时,只需要传递有效期索引即可,以减少数据量) + public NET_DVR_TIME_EX struBeginTime; + public NET_DVR_TIME_EX struEndTime; + public byte byTimeType; //时间类型 + public byte[] byRes2 = new byte[31]; + } + + //扩展结构体信息 + public static class NET_DVR_ID_CARD_INFO_EXTEND extends HIKSDKStructure { + public byte byRemoteCheck; //是否需要远程核验(0-无效,1-不需要(默认),2-需要) + public byte byThermometryUnit; //测温单位(0-摄氏度(默认),1-华氏度,2-开尔文) + public byte byIsAbnomalTemperature; //特征抓拍测温是否温度异常:1-是,0-否 + public byte byRes2; + public float fCurrTemperature; //人脸温度(精确到小数点后一位) + public NET_VCA_POINT struRegionCoordinates = new NET_VCA_POINT(); //人脸温度坐标 + public int dwQRCodeInfoLen; //二维码信息长度,不为0是表示后面带数据 + public int dwVisibleLightDataLen; //热成像相机可见光图片长度,不为0是表示后面带数据 + public int dwThermalDataLen; //热成像图片长度,不为0是表示后面带数据 + public Pointer pQRCodeInfo; //二维码信息指针 + public Pointer pVisibleLightData; //热成像相机可见光图片指针 + public Pointer pThermalData; //热成像图片指针 + public byte[] byRes = new byte[1024]; + } + + //身份证信息报警 + public static class NET_DVR_ID_CARD_INFO_ALARM extends HIKSDKStructure { + public int dwSize; //结构长度 + public NET_DVR_ID_CARD_INFO struIDCardCfg = new NET_DVR_ID_CARD_INFO();//身份证信息 + public int dwMajor; //报警主类型,参考宏定义 + public int dwMinor; //报警次类型,参考宏定义 + public NET_DVR_TIME_V30 struSwipeTime = new NET_DVR_TIME_V30(); //时间 + public byte[] byNetUser = new byte[MAX_NAMELEN];//网络操作的用户名 + public NET_DVR_IPADDR struRemoteHostAddr = new NET_DVR_IPADDR();//远程主机地址 + public int dwCardReaderNo; //读卡器编号,为0无效 + public int dwDoorNo; //门编号,为0无效 + public int dwPicDataLen; //图片数据大小,不为0是表示后面带数据 + public Pointer pPicData; + public byte byCardType; //卡类型,1-普通卡,3-禁止名单卡,4-巡更卡,5-胁迫卡,6-超级卡,7-来宾卡,8-解除卡,为0无效 + public byte byDeviceNo; // 设备编号,为0时无效(有效范围1-255) + public byte byMask; //是否带口罩:0-保留,1-未知,2-不戴口罩,3-戴口罩 + public byte byCurrentEvent; //是否为实时事件:0-无效,1-是(实时事件),2-否(离线事件) + public int dwFingerPrintDataLen; // 指纹数据大小,不为0是表示后面带数据 + public Pointer pFingerPrintData; + public int dwCapturePicDataLen; // 抓拍图片数据大小,不为0是表示后面带数据 + public Pointer pCapturePicData; + public int dwCertificatePicDataLen; //证件抓拍图片数据大小,不为0是表示后面带数据 + public Pointer pCertificatePicData; + public byte byCardReaderKind; //读卡器属于哪一类,0-无效,1-IC读卡器,2-身份证读卡器,3-二维码读卡器,4-指纹头 + public byte[] byRes3 = new byte[2]; + public byte byIDCardInfoExtend; //pIDCardInfoExtend是否有效:0-无效,1-有效 + public Pointer pIDCardInfoExtend; //byIDCardInfoExtend为1时,表示指向一个NET_DVR_ID_CARD_INFO_EXTEND结构体 + public int dwSerialNo; //事件流水号,为0无效 + public byte[] byRes = new byte[168]; + } + + public static final int CARD_READER_DESCRIPTION = 32; //读卡器描述 + + public static class NET_DVR_CARD_READER_CFG_V50 extends HIKSDKStructure { + public int dwSize; + public byte byEnable; //是否使能,1-使能,0-不使能 + public byte byCardReaderType; //读卡器类型,1-DS-K110XM/MK/C/CK,2-DS-K192AM/AMP,3-DS-K192BM/BMP,4-DS-K182AM/AMP,5-DS-K182BM/BMP,6-DS-K182AMF/ACF,7-韦根或485不在线,8- DS-K1101M/MK,9- DS-K1101C/CK,10- DS-K1102M/MK/M-A,11- DS-K1102C/CK,12- DS-K1103M/MK,13- DS-K1103C/CK,14- DS-K1104M/MK,15- DS-K1104C/CK,16- DS-K1102S/SK/S-A,17- DS-K1102G/GK,18- DS-K1100S-B,19- DS-K1102EM/EMK,20- DS-K1102E/EK,21- DS-K1200EF,22- DS-K1200MF,23- DS-K1200CF,24- DS-K1300EF,25- DS-K1300MF,26- DS-K1300CF,27- DS-K1105E,28- DS-K1105M,29- DS-K1105C,30- DS-K182AMF,31- DS-K196AMF,32-DS-K194AMP,33-DS-K1T200EF/EF-C/MF/MF-C/CF/CF-C,34-DS-K1T300EF/EF-C/MF/MF-C/CF/CF-C,35-DS-K1T105E/E-C/M/M-C/C/C-C,36-DS-K1T803F/F-M/F-S/F-E,37-DS-K1A801F/F-M/F-S/F-E,38-DS-K1107M/MK,39-DS-K1107E/EK,40-DS-K1107S/SK,41-DS-K1108M/MK,42-DS-K1108E/EK,43-DS-K1108S/SK,44-DS-K1200F,45-DS-K1S110-I,46-DS-K1T200M-PG/PGC,47-DS-K1T200M-PZ/PZC,48-DS-K1109H + public byte byOkLedPolarity; //OK LED极性,0-阴极,1-阳极 + public byte byErrorLedPolarity; //Error LED极性,0-阴极,1-阳极 + public byte byBuzzerPolarity; //蜂鸣器极性,0-阴极,1-阳极 + public byte bySwipeInterval; //重复刷卡间隔时间,单位:秒 + public byte byPressTimeout; //按键超时时间,单位:秒 + public byte byEnableFailAlarm; //是否启用读卡失败超次报警,0-不启用,1-启用 + public byte byMaxReadCardFailNum; //最大读卡失败次数 + public byte byEnableTamperCheck; //是否支持防拆检测,0-disable ,1-enable + public byte byOfflineCheckTime; //掉线检测时间 单位秒 + public byte byFingerPrintCheckLevel; //指纹识别等级,1-1/10误认率,2-1/100误认率,3-1/1000误认率,4-1/10000误认率,5-1/100000误认率,6-1/1000000误认率,7-1/10000000误认率,8-1/100000000误认率,9-3/100误认率,10-3/1000误认率,11-3/10000误认率,12-3/100000误认率,13-3/1000000误认率,14-3/10000000误认率,15-3/100000000误认率,16-Automatic Normal,17-Automatic Secure,18-Automatic More Secure(目前门禁不支持) + public byte byUseLocalController; //只读,是否连接在就地控制器上,0-否,1-是 + public byte byRes1; + public short wLocalControllerID; //只读,就地控制器序号, byUseLocalController=1时有效,1-64,0代表未注册 + public short wLocalControllerReaderID; //只读,就地控制器的读卡器ID,byUseLocalController=1时有效,0代表未注册 + public short wCardReaderChannel; //只读,读卡器通信通道号,byUseLocalController=1时有效,0韦根或离线,1-RS485A,2-RS485B + public byte byFingerPrintImageQuality; //指纹图像质量,0-无效,1-低质量(V1),2-中等质量(V1),3-高质量(V1),4-最高质量(V1),5-低质量(V2),6-中等质量(V2),7-高质量(V2),8-最高质量(V2) + public byte byFingerPrintContrastTimeOut; //指纹对比超时时间,0-无效,范围1-20代表:1s-20s,0xff-无限大 + public byte byFingerPrintRecogizeInterval; //指纹连续识别间隔,0-无效,范围1-10代表:1s-10s,0xff-无延迟 + public byte byFingerPrintMatchFastMode; //指纹匹配快速模式,0-无效,范围1-5代表:快速模式1-快速模式5,0xff-自动 + public byte byFingerPrintModuleSensitive; //指纹模组灵敏度,0-无效,范围1-8代表:灵敏度级别1-灵敏度级别8 + public byte byFingerPrintModuleLightCondition; //指纹模组光线条件,0-无效,1-室外,2-室内 + public byte byFaceMatchThresholdN; //人脸比对阀值,范围0-100 + public byte byFaceQuality; //人脸质量,范围0-100 + public byte byFaceRecogizeTimeOut; //特征识别超时时间,范围1-20代表:1s-20s,0xff-无限大 + public byte byFaceRecogizeInterval; //人脸连续识别间隔,0-无效,范围1-10代表:1s-10s,0xff-无延迟 + public short wCardReaderFunction; //只读,读卡器种类,按位表示:第1位-指纹,第二位-人脸,第三位-指静脉 + public byte[] byCardReaderDescription = new byte[CARD_READER_DESCRIPTION]; //读卡器描述 + public short wFaceImageSensitometry; //只读,人脸图像曝光度,范围0-65535 + public byte byLivingBodyDetect; //真人检测,0-无效,1-不启用,2-启用 + public byte byFaceMatchThreshold1; //人脸1:1匹配阀值,范围0-100 + public short wBuzzerTime; //蜂鸣时间,范围0s-5999s(0-代表长鸣) + public byte byFaceMatch1SecurityLevel; //人脸1:1识别安全等级,0-无效,1-一般,2-较强,3-极强 + public byte byFaceMatchNSecurityLevel; //人脸1:N识别安全等级,0-无效,1-一般,2-较强,3-极强 + public byte byEnvirMode;//特征识别环境模式,0-无效,1-室内,2-其他; + public byte byLiveDetLevelSet;//活体检测阈值等级设置,0-无效,1-低,2-中,3-高; + public byte byLiveDetAntiAttackCntLimit;//活体检测防攻击次数, 0-无效,1-255次(客户端、设备统一次数限制,根据能力级限制); + public byte byEnableLiveDetAntiAttack;//活体检测防攻击使能,0-无效,1-不启用,2-启用 + public byte bySupportDelFPByID;//只读,读卡器是否支持按手指ID删除指纹,0-无效,1-不支持,2-支持 + public byte byFaceContrastMotionDetLevel;//人脸比对时移动侦测级别,0-无效,1-低,2-中,3-高,0xff-禁用 + public byte byDayFaceMatchThresholdN; //白天人脸1:N匹配阀值,范围0-100 + public byte byNightFaceMatchThresholdN; //夜晚人脸1:N匹配阀值,范围0-100 + public byte byFaceRecogizeEnable; //特征识别使能:0-无效,1-开启,2-关闭 + public byte byBlockListMatchThreshold; //禁止名单匹配阀值,范围0-100 + public byte byRes3; + public byte byDefaultVerifyMode; //只读,读卡器默认验证方式(出厂默认),1-休眠,2-刷卡+密码,3-刷卡,4-刷卡或密码,5-指纹,6-指纹+密码,7-指纹或刷卡,8-指纹+刷卡,9-指纹+刷卡+密码,10-人脸或指纹或刷卡或密码,11-人脸+指纹,12-人脸+密码,13-人脸+刷卡,14-人脸,15-工号+密码,16-指纹或密码,17-工号+指纹,18-工号+指纹+密码,19-人脸+指纹+刷卡,20-人脸+密码+指纹,21-工号+人脸,22-人脸或人脸+刷卡,23-指纹或人脸,24-刷卡或人脸或密码,25-刷卡或人脸,26-刷卡或人脸或指纹,27-刷卡或指纹或密码 + public int dwFingerPrintCapacity;//只读,指纹容量 + public int dwFingerPrintNum;//只读,已存在指纹数量 + public byte byEnableFingerPrintNum;//只读,指纹容量使能:0-不使能,1-使能(只有当该字段为1-使能时,dwFingerPrintCapacity和dwFingerPrintNum才有效) + public byte[] byRes = new byte[231]; + } + + /**************** + * 优化接口结构体定义开始 + *************/ + + public static final int NET_SDK_CONFIG_STATUS_SUCCESS = 1000; + public static final int NET_SDK_CONFIG_STATUS_NEED_WAIT = 1001; + public static final int NET_SDK_CONFIG_STATUS_FINISH = 1002; + public static final int NET_SDK_CONFIG_STATUS_FAILED = 1003; + public static final int NET_SDK_CONFIG_STATUS_EXCEPTION = 1004; + + public static final int NET_SDK_GET_NEXT_STATUS_SUCCESS = 1000; + public static final int NET_SDK_GET_NEXT_STATUS_NEED_WAIT = 1001; + public static final int NET_SDK_NEXT_STATUS__FINISH = 1002; + public static final int NET_SDK_GET_NEXT_STATUS_FAILED = 1003; + + public static class NET_DVR_CARD_COND extends HIKSDKStructure { + public int dwSize; + public int dwCardNum; //设置或获取卡数量,获取时置为0xffffffff表示获取所有卡信息 + public byte[] byRes = new byte[64]; + } + + public static class NET_DVR_CARD_SEND_DATA extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //卡号 + public byte[] byRes = new byte[16]; + } + + public static class NET_DVR_CARD_RECORD extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; + public byte byCardType; + public byte byLeaderCard; + public byte byUserType; + public byte byRes1; + public byte[] byDoorRight = new byte[MAX_DOOR_NUM_256]; + public NET_DVR_VALID_PERIOD_CFG struValid = new NET_DVR_VALID_PERIOD_CFG(); + public byte[] byBelongGroup = new byte[MAX_GROUP_NUM_128]; + public byte[] byCardPassword = new byte[CARD_PASSWORD_LEN]; + public short[] wCardRightPlan = new short[MAX_DOOR_NUM_256]; + public int dwMaxSwipeTimes; + public int dwSwipeTimes; + public int dwEmployeeNo; + public byte[] byName = new byte[NAME_LEN]; + //按位表示,0-无权限,1-有权限 + //第0位表示:弱电报警 + //第1位表示:开门提示音 + //第2位表示:限制客卡 + //第3位表示:通道 + //第4位表示:反锁开门 + //第5位表示:巡更功能 + public int dwCardRight; + public byte[] byRes = new byte[256]; + } + + public static class NET_DVR_CARD_STATUS extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; + public int dwErrorCode; + public byte byStatus; // 状态:0-失败,1-成功 + public byte[] byRes = new byte[23]; + } + + + public static class NET_DVR_FACE_COND extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; + public int dwFaceNum; + public int dwEnableReaderNo; + public byte[] byRes = new byte[124]; + } + + public static class NET_DVR_FACE_RECORD extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; + public int dwFaceLen; + public Pointer pFaceBuffer; + public byte[] byRes = new byte[128]; + } + + public static class NET_DVR_FACE_STATUS extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; + public byte[] byErrorMsg = new byte[ERROR_MSG_LEN]; + public int dwReaderNo; + public byte byRecvStatus; + public byte[] byRes = new byte[131]; + } + + public static class NET_DVR_FINGERPRINT_COND extends HIKSDKStructure { + public int dwSize; + public int dwFingerprintNum; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; + public int dwEnableReaderNo; + public byte byFingerPrintID; + public byte[] byRes = new byte[131]; + } + + public static class NET_DVR_FINGERPRINT_RECORD extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; + public int dwFingerPrintLen; //指纹数据长度 + public int dwEnableReaderNo; //需要下发指纹的读卡器编号 + public byte byFingerPrintID; //手指编号,有效值范围为1-10 + public byte byFingerType; //指纹类型 0-普通指纹,1-胁迫指纹 + public byte[] byRes1 = new byte[30]; + public byte[] byFingerData = new byte[MAX_FINGER_PRINT_LEN]; //指纹数据内容 + public byte[] byRes = new byte[96]; + } + + public static class NET_DVR_FINGERPRINT_STATUS extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //指纹关联的卡号 + public byte byCardReaderRecvStatus; //指纹读卡器状态,按字节表示,0-失败,1-成功,2-该指纹模组不在线,3-重试或指纹质量差,4-内存已满,5-已存在该指纹,6-已存在该指纹ID,7-非法指纹ID,8-该指纹模组无需配置 + public byte byFingerPrintID; //手指编号,有效值范围为1-10 + public byte byFingerType; //指纹类型 0-普通指纹,1-胁迫指纹 + public byte byRecvStatus; //主机错误状态:0-成功,1-手指编号错误,2-指纹类型错误,3-卡号错误(卡号规格不符合设备要求),4-指纹未关联工号或卡号(工号或卡号字段为空),5-工号不存在,6-指纹数据长度为0,7-读卡器编号错误,8-工号错误 + public byte[] byErrorMsg = new byte[ERROR_MSG_LEN]; //下发错误信息,当byCardReaderRecvStatus为5时,表示已存在指纹对应的卡号 + public int dwCardReaderNo; //当byCardReaderRecvStatus为5时,表示已存在指纹对应的指纹读卡器编号,可用于下发错误返回。0时表示无错误信息 + public byte[] byRes = new byte[20]; + } + + public static class NET_DVR_CAPTURE_FINGERPRINT_COND extends HIKSDKStructure { + public int dwSize; + public byte byFingerPrintPicType; //图片类型:0-无意义 + public byte byFingerNo; //手指编号,范围1-10 + public byte[] byRes = new byte[126]; + } + + // + public static class NET_DVR_CAPTURE_FINGERPRINT_CFG extends HIKSDKStructure { + public int dwSize; + public int dwFingerPrintDataSize; //指纹数据大小 + public byte[] byFingerData = new byte[MAX_FINGER_PRINT_LEN]; //图片类型:0-无意义 + public int dwFingerPrintPicSize; //指纹图片大小,等于0时,代表无指纹图片数据 + public Pointer pFingerPrintPicBuffer; //指纹图片缓存 + public byte byFingerNo; //手指编号,范围1-10 + public byte byFingerPrintQuality; //指纹质量,范围1-100 + public byte[] byRes = new byte[62]; + } + + public static class NET_DVR_FINGER_PRINT_INFO_CTRL_V50 extends HIKSDKStructure { + public int dwSize; + public byte byMode; //删除方式,0-按卡号(人员ID)方式删除,1-按读卡器删除 + public byte[] byRes1 = new byte[3]; //保留 + public NET_DVR_DEL_FINGER_PRINT_MODE_V50 struProcessMode; //处理方式 + public byte[] byRes = new byte[64]; //保留 + } + + public static class NET_DVR_DEL_FINGER_PRINT_MODE_V50 extends Union { + public byte[] uLen = new byte[588]; //联合体长度 + public NET_DVR_FINGER_PRINT_BYCARD_V50 struByCard; //按卡号(人员ID)的方式删除 + public NET_DVR_FINGER_PRINT_BYREADER_V50 struByReader; //按读卡器的方式删除 + } + + public static class NET_DVR_FINGER_PRINT_BYREADER_V50 extends HIKSDKStructure { + public int dwCardReaderNo; //按值表示,指纹读卡器编号 + public byte byClearAllCard; //是否删除所有卡的指纹信息,0-按卡号(人员ID)删除指纹信息,1-删除所有卡(人员ID)的指纹信息 + public byte[] byRes1 = new byte[3]; //保留 + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //指纹关联的卡号 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + public byte[] byRes = new byte[516]; //保留 + } + + public static class NET_DVR_FINGER_PRINT_BYCARD_V50 extends HIKSDKStructure { + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //指纹关联的卡号 + public byte[] byEnableCardReader = new byte[MAX_CARD_READER_NUM_512]; //指纹的读卡器信息,按位表示 + public byte[] byFingerPrintID = new byte[10]; //需要删除的手指编号,按数组下标,值表示0-不删除,1-删除该指纹 + public byte[] byRes1 = new byte[2]; + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + } + + //人脸删除控制参数结构体 + public static class NET_DVR_FACE_PARAM_CTRL extends HIKSDKStructure { + public int dwSize; + public byte byMode; //删除方式,0-按卡号方式删除,1-按读卡器删除 + public byte[] byRes1 = new byte[3]; //保留 + public NET_DVR_DEL_FACE_PARAM_MODE struProcessMode = new NET_DVR_DEL_FACE_PARAM_MODE(); //处理方式 + public byte[] byRes = new byte[64]; //保留 + + public void read() { + super.read(); + switch (byMode) { + case 0: + struProcessMode.setType(NET_DVR_FACE_PARAM_BYCARD.class); + break; + case 1: + struProcessMode.setType(NET_DVR_FACE_PARAM_BYREADER.class); + break; + default: + break; + } + struProcessMode.read(); + } + + public void write() { + super.write(); + struProcessMode.write(); + } + } + + //指纹删除控制参数结构体 + public static class NET_DVR_FINGER_PRINT_INFO_CTRL extends HIKSDKStructure { + public int dwSize; + public byte byMode; //删除方式,0-按卡号方式删除,1-按读卡器删除 + public byte[] byRes1 = new byte[3]; //保留 + public NET_DVR_DEL_FINGER_PRINT_MODE struProcessMode = new NET_DVR_DEL_FINGER_PRINT_MODE(); //处理方式 + public byte[] byRes = new byte[64]; //保留 + + public void read() { + super.read(); + switch (byMode) { + case 0: + struProcessMode.setType(NET_DVR_FINGER_PRINT_BYCARD.class); + break; + case 1: + struProcessMode.setType(NET_DVR_FINGER_PRINT_BYREADER.class); + break; + default: + break; + } + struProcessMode.read(); + } + + public void write() { + super.write(); + struProcessMode.write(); + } + } + + public static class NET_DVR_DEL_FINGER_PRINT_MODE extends Union { + // public byte[] uLen = new byte[588]; //联合体长度 + public NET_DVR_FINGER_PRINT_BYCARD struByCard; //按卡号的方式删除 + public NET_DVR_FINGER_PRINT_BYREADER struByReader; //按读卡器的方式删除 + } + + public static class NET_DVR_FINGER_PRINT_BYCARD extends HIKSDKStructure { + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //人脸关联的卡号 + public byte[] byEnableCardReader = new byte[MAX_CARD_READER_NUM_512]; //人脸的读卡器信息,按数组表示 + public byte[] byFaceID = new byte[MAX_FACE_NUM]; //需要删除的人脸编号,按数组下标,值表示0-不删除,1-删除该人脸 + public byte[] byRes1 = new byte[34]; //保留 + } + + public static class NET_DVR_FINGER_PRINT_BYREADER extends HIKSDKStructure { + public int dwCardReaderNo; //按值表示,人脸读卡器编号 + public byte byClearAllCard; //是否删除所有卡的人脸信息,0-按卡号删除人脸信息,1-删除所有卡的人脸信息 + public byte[] byRes1 = new byte[3]; //保留 + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //人脸关联的卡号 + public byte[] byRes = new byte[548]; //保留 + } + + //门禁主机参数 + public static class NET_DVR_ACS_CFG extends HIKSDKStructure { + public int dwSize; //结构体大小 + public byte byRS485Backup; //是否启用下行RS485通信备份功能,0-不启用,1-启用 + public byte byShowCapPic; //是否显示抓拍图片, 0-不显示,1-显示 + public byte byShowCardNo; //是否显示卡号,0-不显示,1-显示 + public byte byShowUserInfo; //是否显示用户信息,0-不显示,1-显示 + public byte byOverlayUserInfo;//是否叠加用户信息,0-不叠加,1-叠加 + public byte byVoicePrompt; //是否启用语音提示,0-不启用,1-启用 + public byte byUploadCapPic; //联动抓拍是否上传图片,0-不上传,1-上传 + public byte bySaveCapPic; //是否保存抓拍图片,0-不保存,1-保存 + public byte byInputCardNo; //是否是否允许按键输入卡号,0-不允许,1-允许 + public byte byEnableWifiDetect; //是否启动wifi,0-不启动,1-启动 + public byte byEnable3G4G; //3G4G使能,0-不使能,1-使能 + public byte byProtocol;//读卡器通信协议类型,0-私有协议(默认),1-OSDP协议 + public byte[] byRes = new byte[500]; + } + + /************** + * 优化接口结构体定义结束 + ***************************/ + public static class NET_DVR_UPLOAD_ID_BLOCKLIST_COND extends HIKSDKStructure { + public int dwSize; + public int dwBlockListNum; //禁止名单数量 + public byte[] byRes = new byte[128]; + } + + public static class NET_DVR_UPLOAD_ID_BLOCKLIST_CFG extends HIKSDKStructure { + public int dwSize; + public NET_DVR_ID_CARD_INFO struIDCardCfg; //身份证信息(该结构体中姓名和身份证号码为必填项,其他字段为选填项) + public byte byBlockListValid; //身份证禁止名单是否有效:0-无效,1-有效(用于按身份证号码删除身份证禁止名单,该字段为0时代表删除) + public byte[] byRes = new byte[127]; //预留 + } + + public static class NET_DVR_UPLOAD_ID_BLOCKLIST_STATUS extends HIKSDKStructure { + public int dwSize; + public byte[] byIDNum = new byte[MAX_ID_NUM_LEN]; //身份证号码 + public byte byStatus; //状态:0-无效,1-处理中,2-上传失败,3-成功 + public byte[] byRes = new byte[63]; + } + + public static class REMOTECONFIGSTATUS extends HIKSDKStructure { + public byte[] byStatus = new byte[4]; + public byte[] byErrorCode = new byte[4]; + } + + + //开锁记录 + public static class NET_DVR_UNLOCK_RECORD_INFO extends HIKSDKStructure { + public byte byUnlockType; //开锁方式,参考UNLOCK_TYPE_ENUM + public byte[] byRes1 = new byte[3]; //保留 + public byte[] byControlSrc = new byte[NAME_LEN]; //操作发起源信息,刷卡开锁时为卡号,蓝牙开锁时为萤石的APP账号,二维码开锁时为访客的手机号,其余情况下为设备编号 + public int dwPicDataLen; //图片数据长度 + public Pointer pImage; //图片指针 + public int dwCardUserID; //持卡人ID + public short nFloorNumber;//刷卡开锁时有效,为楼层号 + public short wRoomNumber; //操作发起源附加信息,刷卡开锁时有效,为房间号, + public short wLockID; //(对于门口机,0-表示本机控制器上接的锁、1-表示外接控制器上接的锁) + public byte[] byRes2 = new byte[2]; + public byte[] byLockName = new byte[LOCK_NAME_LEN]; //刷卡开锁时有效,锁名称,对应门参数配置中门名称 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + public byte[] byRes = new byte[136]; //保留 + } + + //公告信息阅读回执 + public static class NET_DVR_NOTICEDATA_RECEIPT_INFO extends HIKSDKStructure { + public byte[] byNoticeNumber = new byte[MAX_NOTICE_NUMBER_LEN]; //公告编号 + public byte[] byRes = new byte[224]; //保留 + } + + //认证记录(设备未实现) + public static class NET_DVR_AUTH_INFO extends HIKSDKStructure { + public byte byAuthResult; //认证结果:0-无效,1-认证成功,2-认证失败 + public byte byAuthType; //认证方式:0-无效,1-指纹,2-人脸 + public byte[] byRes1 = new byte[2]; //保留 + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN/*32*/]; //卡号 + public int dwPicDataLen; //图片数据长度(当认证方式byAuthType为人脸时有效) + public Pointer pImage; //图片指针(当认证方式byAuthType为人脸时有效) + public byte[] byRes = new byte[212]; //保留 + } + + //车牌信息上传 + public static class NET_DVR_UPLOAD_PLATE_INFO extends HIKSDKStructure { + public byte[] sLicense = new byte[MAX_LICENSE_LEN]; //车牌号码 + public byte byColor; //车牌颜色,参考结构VCA_PLATE_COLOR + public byte[] byRes = new byte[239]; //保留 + } + + public static class NET_DVR_SEND_CARD_INFO extends HIKSDKStructure { + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN/*32*/]; //卡号 + public byte[] byRes = new byte[224]; //保留 + } + + //防区报警信息结构体 + public static class NET_DVR_ZONE_ALARM_INFO extends HIKSDKStructure { + public byte[] byZoneName = new byte[NAME_LEN]; //防区名称 + public int dwZonendex;//防区号 + public byte byZoneType;//防区类型 ENUM_ALARM_ZONE_TYPE_MANUAL-紧急开关报警;ENUM_ALARM_ZONE_TYPE_MAGNETIC-门磁报警;ENUM_ALARM_ZONE_TYPE_SMOKE-烟感报警;ENUM_ALARM_ZONE_TYPE_ACTIVE_INFRARED-主动红外报警;ENUM_ALARM_ZONE_TYPE_PASSIVE_INFRARED-被动红外报警;ENUM_ALARM_ZONE_TYPE_GAS-煤气报警 + public byte[] byRes = new byte[219]; //保留,置为0 + } + //可视对讲报警信息联合体 + public static class NET_DVR_VIDEO_INTERCOM_ALARM_INFO_UNION extends Union { + public byte[] byLen = new byte[256]; //联合体大小 + public NET_DVR_ZONE_ALARM_INFO struZoneAlarm = new NET_DVR_ZONE_ALARM_INFO(); //开锁记录 + } + + //可视对讲报警信息结构体 + public static class NET_DVR_VIDEO_INTERCOM_ALARM extends HIKSDKStructure { + public int dwSize; //结构体大小 + public NET_DVR_TIME_EX struTime = new NET_DVR_TIME_EX(); //时间 + public byte[] byDevNumber = new byte[MAX_DEV_NUMBER_LEN]; //设备编号 + public byte byAlarmType;//报警类型:1- 防区报警,2- 防拆报警,3- 劫持报警,4- 多次密码开锁失败报警,5- 门没开,6- 门没关,7- SOS(呼救报警),8- 通话对讲,9- 智能锁劫持指纹报警, + // 10- 智能锁劫持密码报警,11- 智能锁撬门报警,12- 智能锁门锁锁定报警,13- 智能锁电量不足报警, 14-禁止名单报警, 15-智能锁掉线, 16-门禁安全模块防拆报警 + public byte[] byRes1 = new byte[3]; //保留 + public NET_DVR_VIDEO_INTERCOM_ALARM_INFO_UNION uAlarmInfo = new NET_DVR_VIDEO_INTERCOM_ALARM_INFO_UNION(); //报警信息,byAlarmType为1时有效 + public short wLockID; //锁ID,(0-表示门口机本机控制器上接的锁、1-表示外接控制器上接的锁)(报警类型为5和6时有效) + public byte[] byRes2 = new byte[254]; //保留,置为0 + } + + //可视对讲事件记录信息联合体 + public static class NET_DVR_VIDEO_INTERCOM_EVENT_INFO_UINON extends Union { + public byte[] byLen = new byte[256]; //联合体大小 + public NET_DVR_UNLOCK_RECORD_INFO struUnlockRecord = new NET_DVR_UNLOCK_RECORD_INFO(); //开锁记录 + public NET_DVR_NOTICEDATA_RECEIPT_INFO struNoticedataReceipt = new NET_DVR_NOTICEDATA_RECEIPT_INFO(); //公告信息阅读回执 + public NET_DVR_AUTH_INFO struAuthInfo = new NET_DVR_AUTH_INFO(); //认证记录(设备未实现) + public NET_DVR_UPLOAD_PLATE_INFO struUploadPlateInfo = new NET_DVR_UPLOAD_PLATE_INFO(); //车牌信息上传 + public NET_DVR_SEND_CARD_INFO struSendCardInfo = new NET_DVR_SEND_CARD_INFO(); //门口机发卡,对应设备处于发卡状态,刷卡时上传该事件 + } + + //可视对讲事件记录 + public static class NET_DVR_VIDEO_INTERCOM_EVENT extends HIKSDKStructure { + public int dwSize; //结构体大小 + public NET_DVR_TIME_EX struTime = new NET_DVR_TIME_EX(); //时间 + public byte[] byDevNumber = new byte[MAX_DEV_NUMBER_LEN]; //设备编号 + public byte byEventType; //事件信息类型,1-开锁记录,2-公告信息阅读回执,3-认证记录,4-车牌信息上传,5非法卡刷卡事件,6-门口机发卡记录(需要启动门口机发卡功能,刷卡时才会上传该事件) + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public byte[] byRes1 = new byte[2]; //保留 + public NET_DVR_VIDEO_INTERCOM_EVENT_INFO_UINON uEventInfo = new NET_DVR_VIDEO_INTERCOM_EVENT_INFO_UINON(); //事件信息,具体内容参考byEventType取值 + public int dwIOTChannelNo; //IOT通道号 + public byte[] byRes2 = new byte[252]; //保留 + } + + public static class NET_DVR_VIDEO_CALL_PARAM extends HIKSDKStructure + { + public int dwSize; + public int dwCmdType; //信令类型 0-请求呼叫,1-取消本次呼叫,2-接听本次呼叫 3-拒绝本地来电呼叫 4-被叫响铃超时 5-结束本次通话,6-设备正在通话中,7-客户端正在通话中,8室内机不在线 + public short wPeriod; //期号, 范围[0,9] + public short wBuildingNumber; //楼号 + public short wUnitNumber; //单元号 + public short wFloorNumber; //层号 + public short wRoomNumber; //房间号 + public short wDevIndex; //设备编号 + public byte byUnitType; //设备类型,1-门口机,2-管理机,3-室内机,4-围墙机,5-别墅门口机,6-二次确认机,7-8700客户端,8-4200客户端,9-APP + public byte[] byRes=new byte[115]; //保留 + } + + public static class NET_DVR_CONTROL_GATEWAY extends HIKSDKStructure { + public int dwSize; //结构体大小 + public int dwGatewayIndex; //门禁序号,从1开始 + public byte byCommand; //操作命令,0-关闭,1-打开,2-常开(通道状态),3-恢复(普通状态) + public byte byLockType; //锁类型,0-普通(以前默认都为0),1-智能锁 + public short wLockID; //锁ID,从1开始(远程开门口机锁时,0表示门口机本机控制器上接的锁、1表示外接控制器上接的锁) + public byte[] byControlSrc = new byte[NAME_LEN]; //操作发起源信息 + public byte byControlType; //开锁类型,1-布防,2-通话 + public byte[] byRes3 = new byte[3]; + public byte[] byPassword = new byte[PASSWD_LEN]; //锁密码,当byLockType为智能锁时有效 + public byte[] byRes2 = new byte[108]; //保留 + } + + + //公告图片信息结构体 + public static class NET_DVR_NOTICE_PIC extends HIKSDKStructure { + public Pointer pPicData; //图片指针 + public int dwPicDataLen; //图片数据长度 + public byte[] byRes = new byte[32]; //保留 + } + + //公告数据 + public static class NET_DVR_NOTICE_DATA extends HIKSDKStructure { + public int dwSize; //结构体大小 + public NET_DVR_TIME_EX struTime = new NET_DVR_TIME_EX(); //公告时间 + public byte[] byNoticeNumber = new byte[MAX_NOTICE_NUMBER_LEN]; //公告编号 + public byte[] byNoticeTheme = new byte[MAX_NOTICE_THEME_LEN];//公告主题 + public byte[] byNoticeDetail = new byte[MAX_NOTICE_DETAIL_LEN]; //公告详情 + public byte byLevel; //公告等级,1-广告类信息;2-物业信息;3-报警类信息;4-通知类信息 + public byte byPicNum; //公告图片数量 + public byte[] byRes1 = new byte[2]; //保留 + public NET_DVR_NOTICE_PIC[] struNoticePic = new NET_DVR_NOTICE_PIC[MAX_NOTICE_PIC_NUM]; //公告图片 + public byte[] byRes2 = new byte[128]; //保留 + } + + public static class NET_DVR_DATE extends HIKSDKStructure { + public short wYear; //年 + public byte byMonth; //月 + public byte byDay; //日 + } + + //身份证信息 + public static class NET_DVR_ID_CARD_INFO extends HIKSDKStructure { + public int dwSize; //结构长度 + public byte[] byName = new byte[MAX_ID_NAME_LEN]; //姓名 + public NET_DVR_DATE struBirth; //出生日期 + public byte[] byAddr = new byte[MAX_ID_ADDR_LEN]; //住址 + public byte[] byIDNum = new byte[MAX_ID_NUM_LEN]; //身份证号码 + public byte[] byIssuingAuthority = new byte[MAX_ID_ISSUING_AUTHORITY_LEN]; //签发机关 + public NET_DVR_DATE struStartDate; //有效开始日期 + public NET_DVR_DATE struEndDate; //有效截止日期 + public byte byTermOfValidity; //是否长期有效, 0-否,1-是(有效截止日期无效) + public byte bySex; //性别,1-男,2-女 + public byte byNation; // + public byte[] byRes = new byte[101]; + } + + public static class NET_DVR_ACS_EVENT_INFO_EXTEND_V20 extends HIKSDKStructure { + public byte byRemoteCheck; //是否需要远程核验(0-无效,1-不需要(默认),2-需要) + public byte byThermometryUnit; //测温单位(0-摄氏度(默认),1-华氏度,2-开尔文) + public byte byIsAbnomalTemperature; //特征抓拍测温是否温度异常:1-是,0-否 + public byte byRes2; + public float fCurrTemperature; //人脸温度(精确到小数点后一位) + public NET_VCA_POINT struRegionCoordinates = new NET_VCA_POINT(); //人脸温度坐标 + public int dwQRCodeInfoLen; //二维码信息长度,不为0是表示后面带数据 + public int dwVisibleLightDataLen; //热成像相机可见光图片长度,不为0是表示后面带数据 + public int dwThermalDataLen; //热成像图片长度,不为0是表示后面带数据 + public Pointer pQRCodeInfo; //二维码信息指针 + public Pointer pVisibleLightData; //热成像相机可见光图片指针 + public Pointer pThermalData; //热成像图片指针 + public byte[] byRes = new byte[1024]; + + + } + + //门禁主机报警信息结构体 + public static class NET_DVR_ACS_ALARM_INFO extends HIKSDKStructure { + public int dwSize; + public int dwMajor; //报警主类型,参考宏定义 + public int dwMinor; //报警次类型,参考宏定义 + public NET_DVR_TIME struTime = new NET_DVR_TIME(); //时间 + public byte[] sNetUser = new byte[MAX_NAMELEN];//网络操作的用户名 + public NET_DVR_IPADDR struRemoteHostAddr = new NET_DVR_IPADDR();//远程主机地址 + public NET_DVR_ACS_EVENT_INFO struAcsEventInfo = new NET_DVR_ACS_EVENT_INFO(); //详细参数 + public int dwPicDataLen; //图片数据大小,不为0是表示后面带数据 + public Pointer pPicData; + public short wInductiveEventType; //归纳事件类型,0-无效,客户端判断该值为非0值后,报警类型通过归纳事件类型区分,否则通过原有报警主次类型(dwMajor、dwMinor)区分 + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public byte byRes1; //保留字节 + public int dwIOTChannelNo; //IOT通道号 + public Pointer pAcsEventInfoExtend; //byAcsEventInfoExtend为1时,表示指向一个NET_DVR_ACS_EVENT_INFO_EXTEND结构体 + public byte byAcsEventInfoExtend; //pAcsEventInfoExtend是否有效:0-无效,1-有效 + public byte byTimeType; //时间类型:0-设备本地时间,1-UTC时间(struTime的时间) + public byte byRes2; //保留字节 + public byte byAcsEventInfoExtendV20; //pAcsEventInfoExtendV20是否有效:0-无效,1-有效 + public Pointer pAcsEventInfoExtendV20; //byAcsEventInfoExtendV20为1时,表示指向一个NET_DVR_ACS_EVENT_INFO_EXTEND_V20结构体 + public byte[] byRes = new byte[4]; + } + + //门禁主机事件信息 + public static class NET_DVR_ACS_EVENT_INFO extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[32]; + public byte byCardType; + public byte byAllowListNo; + public byte byReportChannel; + public byte byCardReaderKind; + public int dwCardReaderNo; + public int dwDoorNo; + public int dwVerifyNo; + public int dwAlarmInNo; + public int dwAlarmOutNo; + public int dwCaseSensorNo; + public int dwRs485No; + public int dwMultiCardGroupNo; + public short wAccessChannel; + public byte byDeviceNo; + public byte byDistractControlNo; + public int dwEmployeeNo; + public short wLocalControllerID; + public byte byInternetAccess; + public byte byType; + public byte[] byMACAddr = new byte[MACADDR_LEN]; //物理地址,为0无效 + public byte bySwipeCardType;//刷卡类型,0-无效,1-二维码 + public byte byMask; //是否带口罩:0-保留,1-未知,2-不戴口罩,3-戴口罩 + public int dwSerialNo; //事件流水号,为0无效 + public byte byChannelControllerID; //通道控制器ID,为0无效,1-主通道控制器,2-从通道控制器 + public byte byChannelControllerLampID; //通道控制器灯板ID,为0无效(有效范围1-255) + public byte byChannelControllerIRAdaptorID; //通道控制器红外转接板ID,为0无效(有效范围1-255) + public byte byChannelControllerIREmitterID; //通道控制器红外对射ID,为0无效(有效范围1-255) + public byte byHelmet;//可选,是否戴安全帽:0-保留,1-未知,2-不戴安全, 3-戴安全帽 + public byte[] byRes = new byte[3]; + } + + public static final int NET_DEV_NAME_LEN = 64; + + public static class NET_DVR_ACS_EVENT_INFO_EXTEND extends HIKSDKStructure { + public int dwFrontSerialNo; //事件流水号,为0无效(若该字段为0,平台根据dwSerialNo判断是否丢失事件;若该字段不为0,平台根据该字段和dwSerialNo字段共同判断是否丢失事件)(主要用于解决报警订阅后导致dwSerialNo不连续的情况) + public byte byUserType; //人员类型:0-无效,1-普通人(主人),2-来宾(访客),3-禁止名单人,4-管理员 + public byte byCurrentVerifyMode; //读卡器当前验证方式:0-无效,1-休眠,2-刷卡+密码,3-刷卡,4-刷卡或密码,5-指纹,6-指纹+密码,7-指纹或刷卡,8-指纹+刷卡,9-指纹+刷卡+密码,10-人脸或指纹或刷卡或密码,11-人脸+指纹,12-人脸+密码,13-人脸+刷卡,14-人脸,15-工号+密码,16-指纹或密码,17-工号+指纹,18-工号+指纹+密码,19-人脸+指纹+刷卡,20-人脸+密码+指纹,21-工号+人脸,22-人脸或人脸+刷卡,23-指纹或人脸,24-刷卡或人脸或密码,25-刷卡或人脸,26-刷卡或人脸或指纹,27-刷卡或指纹或密码 + public byte byCurrentEvent; //是否为实时事件:0-无效,1-是(实时事件),2-否(离线事件) + public byte byPurePwdVerifyEnable; //设备是否支持纯密码认证, 0-不支持,1-支持 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID)(对于设备来说,如果使用了工号(人员ID)字段,byEmployeeNo一定要传递,如果byEmployeeNo可转换为dwEmployeeNo,那么该字段也要传递;对于上层平台或客户端来说,优先解析byEmployeeNo字段,如该字段为空,再考虑解析dwEmployeeNo字段) + public byte byAttendanceStatus; //考勤状态:0-未定义,1-上班,2-下班,3-开始休息,4-结束休息,5-开始加班,6-结束加班 + public byte byStatusValue; //考勤状态值 + public byte[] byRes2 = new byte[2]; + public byte[] byUUID = new byte[NET_SDK_UUID_LEN/*36*/]; //UUID(该字段仅在对接萤石平台过程中才会使用) + public byte[] byDeviceName = new byte[NET_DEV_NAME_LEN/*64*/]; //设备序列号 + public byte[] byRes = new byte[24]; + + } + + /* + 门禁主机报警事件细节结构体 + */ + public static class NET_DVR_ACS_EVENT_DETAIL extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //卡号(mac地址),为0无效 + public byte byCardType; //卡类型,1-普通卡,3-禁止名单卡,4-巡更卡,5-胁迫卡,6-超级卡,7-来宾卡,8-解除卡,为0无效 + public byte byAllowListNo; //允许名单单号,1-8,为0无效 + public byte byReportChannel; //报告上传通道,1-布防上传,2-中心组1上传,3-中心组2上传,为0无效 + public byte byCardReaderKind; //读卡器属于哪一类,0-无效,1-IC读卡器,2-身份证读卡器,3-二维码读卡器,4-指纹头 + public int dwCardReaderNo; //读卡器编号,为0无效 + public int dwDoorNo; //门编号(楼层编号),为0无效 + public int dwVerifyNo; //多重卡认证序号,为0无效 + public int dwAlarmInNo; //报警输入号,为0无效 + public int dwAlarmOutNo; //报警输出号,为0无效 + public int dwCaseSensorNo; //事件触发器编号 + public int dwRs485No; //RS485通道号,为0无效 + public int dwMultiCardGroupNo; //群组编号 + public short wAccessChannel; //人员通道号 + public byte byDeviceNo; //设备编号,为0无效(有效范围1-255) + public byte byDistractControlNo;//分控器编号,为0无效 + public int dwEmployeeNo; //工号,为0无效 + public short wLocalControllerID; //就地控制器编号,0-门禁主机,1-64代表就地控制器 + public byte byInternetAccess; //网口ID:(1-上行网口1,2-上行网口2,3-下行网口1) + public byte byType; //防区类型,0:即时防区,1-24小时防区,2-延时防区 ,3-内部防区,4-钥匙防区 5-火警防区 6-周界防区 7-24小时无声防区 8-24小时辅助防区,9-24小时震动防区,10-门禁紧急开门防区,11-门禁紧急关门防区 0xff-无 + public byte[] byMACAddr = new byte[MACADDR_LEN]; //物理地址,为0无效 + public byte bySwipeCardType;//刷卡类型,0-无效,1-二维码 + public byte byEventAttribute; //事件属性:0-未定义,1-合法认证,2-其它 + public int dwSerialNo; //事件流水号,为0无效 + public byte byChannelControllerID; //通道控制器ID,为0无效,1-主通道控制器,2-从通道控制器 + public byte byChannelControllerLampID; //通道控制器灯板ID,为0无效(有效范围1-255) + public byte byChannelControllerIRAdaptorID; //通道控制器红外转接板ID,为0无效(有效范围1-255) + public byte byChannelControllerIREmitterID; //通道控制器红外对射ID,为0无效(有效范围1-255) + public int dwRecordChannelNum; //录像通道数目 + public Pointer pRecordChannelData;//录像通道,大小为sizeof(DWORD)* dwRecordChannelNum + public byte byUserType; //人员类型:0-无效,1-普通人(主人),2-来宾(访客),3-禁止名单人,4-管理员 + public byte byCurrentVerifyMode; //读卡器当前验证方式:0-无效,1-休眠,2-刷卡+密码,3-刷卡,4-刷卡或密码,5-指纹,6-指纹+密码,7-指纹或刷卡,8-指纹+刷卡,9-指纹+刷卡+密码,10-人脸或指纹或刷卡或密码,11-人脸+指纹,12-人脸+密码, + //13-人脸+刷卡,14-人脸,15-工号+密码,16-指纹或密码,17-工号+指纹,18-工号+指纹+密码,19-人脸+指纹+刷卡,20-人脸+密码+指纹,21-工号+人脸,22-人脸或人脸+刷卡,23-指纹或人脸,24-刷卡或人脸或密码,25-刷卡或人脸,26-刷卡或人脸或指纹,27-刷卡或指纹或密码 + public byte byAttendanceStatus; //考勤状态:0-未定义,1-上班,2-下班,3-开始休息,4-结束休息,5-开始加班,6-结束加班 + public byte byStatusValue; //考勤状态值 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID)(对于设备来说,如果使用了工号(人员ID)字段,byEmployeeNo一定要传递,如果byEmployeeNo可转换为dwEmployeeNo,那么该字段也要传递;对于上层平台或客户端来说,优先解析byEmployeeNo字段,如该字段为空,再考虑解析dwEmployeeNo字段) + public byte byRes1; //保留 + public byte byMask; //是否带口罩:0-保留,1-未知,2-不戴口罩,3-戴口罩 + public byte byThermometryUnit; //测温单位(0-摄氏度(默认),1-华氏度,2-开尔文) + public byte byIsAbnomalTemperature; //特征抓拍测温是否温度异常:1-是,0-否 + public float fCurrTemperature; //人脸温度(精确到小数点后一位) + public NET_VCA_POINT struRegionCoordinates; //人脸温度坐标 + public byte[] byRes = new byte[48]; + } + + /* + 门禁主机报警事件配置结构体 + */ + public static class NET_DVR_ACS_EVENT_CFG extends HIKSDKStructure { + public int dwSize; + public int dwMajor; //报警主类型,参考宏定义 + public int dwMinor; //报警次类型,参考宏定义 + public NET_DVR_TIME struTime = new NET_DVR_TIME(); //时间 + public byte[] sNetUser = new byte[MAX_NAMELEN];//网络操作的用户名 + public NET_DVR_IPADDR struRemoteHostAddr;//远程主机地址 + public NET_DVR_ACS_EVENT_DETAIL struAcsEventInfo; //详细参数 + public int dwPicDataLen; //图片数据大小,不为0是表示后面带数据 + public Pointer pPicData; + public short wInductiveEventType; //归纳事件类型,0-无效,其他值参见2.2章节,客户端判断该值为非0值后,报警类型通过归纳事件类型区分,否则通过原有报警主次类型(dwMajor、dwMinor)区分 + public byte byTimeType; //时间类型:0-设备本地时间(默认),1-UTC时间(struTime的时间) + public byte byRes1; + public int dwQRCodeInfoLen; //二维码信息长度,不为0是表示后面带数据 + public int dwVisibleLightDataLen; //热成像相机可见光图片长度,不为0是表示后面带数据 + public int dwThermalDataLen; //热成像图片长度,不为0是表示后面带数据 + public Pointer pQRCodeInfo; //二维码信息指针 + public Pointer pVisibleLightData; //热成像相机可见光图片指针 + public Pointer pThermalData; //热成像图片指针 + public byte[] byRes = new byte[36]; + } + + public static final int NET_SDK_MONITOR_ID_LEN = 64; + + public static class NET_DVR_ACS_EVENT_COND extends HIKSDKStructure { + public int dwSize; + public int dwMajor; //报警主类型,参考事件上传宏定义,0-全部 + public int dwMinor; //报警次类型,参考事件上传宏定义,0-全部 + public NET_DVR_TIME struStartTime; //开始时间 + public NET_DVR_TIME struEndTime; //结束时间 + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //卡号 + public byte[] byName = new byte[NAME_LEN]; //持卡人姓名 + public byte byPicEnable; //是否带图片,0-不带图片,1-带图片 + public byte byTimeType; //时间类型:0-设备本地时间(默认),1-UTC时间(struStartTime和struEndTime的时间) + public byte[] byRes2 = new byte[2]; //保留 + public int dwBeginSerialNo; //起始流水号(为0时默认全部) + public int dwEndSerialNo; //结束流水号(为0时默认全部) + public int dwIOTChannelNo; //IOT通道号,0-无效 + public short wInductiveEventType; //归纳事件类型,0-无效,其他值参见2.2章节,客户端判断该值为非0值后,报警类型通过归纳事件类型区分,否则通过原有报警主次类型(dwMajor、dwMinor)区分 + public byte bySearchType; //搜索方式:0-保留,1-按事件源搜索(此时通道号为非视频通道号),2-按布防点ID搜索 + public byte byEventAttribute; //事件属性:0-未定义,1-合法事件,2-其它 + public byte[] szMonitorID = new byte[NET_SDK_MONITOR_ID_LEN/*64*/]; //布防点ID(由设备序列号、通道类型、编号组成,例如门禁点:设备序列号+“DOOR”+门编号) + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + public byte[] byRes = new byte[140]; //保留 + } + + public static class NET_DVR_ACS_WORK_STATUS_V50 extends HIKSDKStructure { + public int dwSize; + public byte[] byDoorLockStatus = new byte[MAX_DOOR_NUM_256]; //门锁状态(继电器开合状态),0-正常关,1-正常开,2-短路报警,3-断路报警,4-异常报警 + public byte[] byDoorStatus = new byte[MAX_DOOR_NUM_256]; //门状态(楼层状态),1-休眠,2-常开状态(自由),3-常闭状态(禁用),4-普通状态(受控) + public byte[] byMagneticStatus = new byte[MAX_DOOR_NUM_256]; //门磁状态,0-正常关,1-正常开,2-短路报警,3-断路报警,4-异常报警 + public byte[] byCaseStatus = new byte[MAX_CASE_SENSOR_NUM]; //事件触发器状态,0-无输入,1-有输入 + public short wBatteryVoltage; //蓄电池电压值,实际值乘10,单位:伏特 + public byte byBatteryLowVoltage; //蓄电池是否处于低压状态,0-否,1-是 + public byte byPowerSupplyStatus; //设备供电状态,1-交流电供电,2-蓄电池供电 + public byte byMultiDoorInterlockStatus; //多门互锁状态,0-关闭,1-开启 + public byte byAntiSneakStatus; //反潜回状态,0-关闭,1-开启 + public byte byHostAntiDismantleStatus; //主机防拆状态,0-关闭,1-开启 + public byte byIndicatorLightStatus; //指示灯状态,0-掉线,1-在线 + public byte[] byCardReaderOnlineStatus = new byte[MAX_CARD_READER_NUM_512]; //读卡器在线状态,0-不在线,1-在线 + public byte[] byCardReaderAntiDismantleStatus = new byte[MAX_CARD_READER_NUM_512]; //读卡器防拆状态,0-关闭,1-开启 + public byte[] byCardReaderVerifyMode = new byte[MAX_CARD_READER_NUM_512]; //读卡器当前验证方式,1-休眠,2-刷卡+密码,3-刷卡,4-刷卡或密码 + public byte[] bySetupAlarmStatus = new byte[MAX_ALARMHOST_ALARMIN_NUM];//报警输入口布防状态,0-对应报警输入口处于撤防状态,1-对应报警输入口处于布防状态 + public byte[] byAlarmInStatus = new byte[MAX_ALARMHOST_ALARMIN_NUM]; //按位表示报警输入口报警状态,0-对应报警输入口当前无报警,1-对应报警输入口当前有报警 + public byte[] byAlarmOutStatus = new byte[MAX_ALARMHOST_ALARMOUT_NUM]; //按位表示报警输出口状态,0-对应报警输出口无报警,1-对应报警输出口有报警 + public int dwCardNum; //已添加的卡数量 + public byte byFireAlarmStatus; //消防报警状态显示:0-正常、1-短路报警、2-断开报警 + public byte byBatteryChargeStatus; //电池充电状态:0-无效;1-充电中;2-未充电 + public byte byMasterChannelControllerStatus; //主通道控制器在线状态:0-无效;1-不在线;2-在线 + public byte bySlaveChannelControllerStatus; //从通道控制器在线状态:0-无效;1-不在线;2-在线 + public byte byAntiSneakServerStatus; //反潜回服务器状态:0-无效,1-未启用,2-正常,3-断开 + public byte[] byRes3 = new byte[3]; + public int dwAllowFaceNum; //已添加的允许名单人脸数量(通过能力集判断) + public int dwBlockFaceNum; //已添加的禁止名单人脸数量(通过能力集判断) + public byte[] byRes2 = new byte[108]; + } + + public static final int ACS_PARAM_DOOR_STATUS_WEEK_PLAN = 0x00000001;//门状态周计划参数 + public static final int ACS_PARAM_VERIFY_WEEK_PALN = 0x00000002; //读卡器周计划参数 + public static final int ACS_PARAM_CARD_RIGHT_WEEK_PLAN = 0x00000004; //卡权限周计划参数 + public static final int ACS_PARAM_DOOR_STATUS_HOLIDAY_PLAN = 0x00000008; //门状态假日计划参数 + public static final int ACS_PARAM_VERIFY_HOLIDAY_PALN = 0x00000010; //读卡器假日计划参数 + public static final int ACS_PARAM_CARD_RIGHT_HOLIDAY_PLAN = 0x00000020; //卡权限假日计划参数 + public static final int ACS_PARAM_DOOR_STATUS_HOLIDAY_GROUP = 0x00000040; //门状态假日组参数 + public static final int ACS_PARAM_VERIFY_HOLIDAY_GROUP = 0x00000080;//读卡器验证方式假日组参数 + public static final int ACS_PARAM_CARD_RIGHT_HOLIDAY_GROUP = 0x00000100; //卡权限假日组参数 + public static final int ACS_PARAM_DOOR_STATUS_PLAN_TEMPLATE = 0x00000200;//门状态计划模板参数 + public static final int ACS_PARAM_VERIFY_PALN_TEMPLATE = 0x00000400; //读卡器验证方式计划模板参数 + public static final int ACS_PARAM_CARD_RIGHT_PALN_TEMPLATE = 0x00000800; //卡权限计划模板参数 + public static final int ACS_PARAM_CARD = 0x00001000; //卡参数 + public static final int ACS_PARAM_GROUP = 0x00002000; //群组参数 + public static final int ACS_PARAM_ANTI_SNEAK_CFG = 0x00004000; //反潜回参数 + public static final int ACS_PAPAM_EVENT_CARD_LINKAGE = 0x00008000; //事件及卡号联动参数 + public static final int ACS_PAPAM_CARD_PASSWD_CFG = 0x00010000; //密码开门使能参数 + public static final int ACS_PARAM_PERSON_STATISTICS_CFG = 0x00020000; //人数统计参数 + public static final int ACS_PARAM_BLOCKLIST_PICTURE = 0x00040000; //禁止名单图片参数 + public static final int ACS_PARAM_ID_BLOCKLIST = 0x00080000; //身份证禁止名单参数 + public static final int ACS_PARAM_EXAM_INFO = 0x00100000; //考试信息参数 + public static final int ACS_PARAM_EXAMINEE_INFO = 0x00200000; //考生信息参数 + public static final int ACS_PARAM_FAILED_FACE_INFO = 0x00400000; //升级设备人脸建模失败记录 + + public static class NET_DVR_ACS_PARAM_TYPE extends HIKSDKStructure { + public int dwSize; + public int dwParamType; //参数类型,按位表示 + + public short wLocalControllerID; //就地控制器序号[1,64],0代表门禁主机 + public byte[] byRes = new byte[30]; + } + + + public static class NET_DVR_FACE_PARAM_COND extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //人脸关联的卡号 + public byte[] byEnableCardReader = new byte[MAX_CARD_READER_NUM_512]; //人脸的读卡器是否有效,0-无效,1-有效 + public int dwFaceNum; //设置或获取人脸数量,获取时置为0xffffffff表示获取所有人脸信息 + public byte byFaceID; //人脸编号,有效值范围为1-2 0xff表示该卡所有人脸 + public byte[] byRes = new byte[127]; //保留 + } + + public static class NET_DVR_FACE_PARAM_CFG extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //人脸关联的卡号 + public int dwFaceLen; //人脸数据长度,设备端返回的即加密后的数据 + public Pointer pFaceBuffer; //人脸数据指针 + public byte[] byEnableCardReader = new byte[MAX_CARD_READER_NUM_512]; //需要下发人脸的读卡器,按数组表示,从低位到高位表示,0-不下发该读卡器,1-下发到该读卡器 + public byte byFaceID; //人脸编号,有效值范围为1-2 + public byte byFaceDataType; //人脸数据类型:0-模板(默认),1-图片 + public byte[] byRes = new byte[126]; + } + + public static class NET_DVR_FACE_PARAM_STATUS extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //人脸关联的卡号 + public byte[] byCardReaderRecvStatus = new byte[MAX_CARD_READER_NUM_512]; //人脸读卡器状态,按字节表示,0-失败,1-成功,2-重试或人脸质量差,3-内存已满,4-已存在该人脸,5-非法人脸ID + public byte[] byErrorMsg = new byte[ERROR_MSG_LEN]; //下发错误信息,当byCardReaderRecvStatus为4时,表示已存在人脸对应的卡号 + public int dwCardReaderNo; //纹读卡器编号,可用于下发错误返回 + public byte byTotalStatus; //下发总的状态,0-当前人脸未下完所有读卡器,1-已下完所有读卡器(这里的所有指的是门禁主机往所有的读卡器下发了,不管成功与否) + public byte byFaceID; //人脸编号,有效值范围为1-2 + public byte[] byRes = new byte[130]; + } + + public static class NET_DVR_FACE_PARAM_BYCARD extends HIKSDKStructure { + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //人脸关联的卡号 + public byte[] byEnableCardReader = new byte[MAX_CARD_READER_NUM_512]; //人脸的读卡器信息,按数组表示 + public byte[] byFaceID = new byte[MAX_FACE_NUM]; //需要删除的人脸编号,按数组下标,值表示0-不删除,1-删除该人脸 + public byte[] byRes1 = new byte[42]; //保留 + } + + public static class NET_DVR_FACE_PARAM_BYREADER extends HIKSDKStructure { + public int dwCardReaderNo; //按值表示,人脸读卡器编号 + public byte byClearAllCard; //是否删除所有卡的人脸信息,0-按卡号删除人脸信息,1-删除所有卡的人脸信息 + public byte[] byRes1 = new byte[3]; //保留 + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //人脸关联的卡号 + public byte[] byRes = new byte[548]; //保留 + } + + public static class NET_DVR_DEL_FACE_PARAM_MODE extends Union { + public byte[] uLen = new byte[588]; //联合体长度 + public NET_DVR_FACE_PARAM_BYCARD struByCard; //按卡号的方式删除 + public NET_DVR_FACE_PARAM_BYREADER struByReader; //按读卡器的方式删除 + } + + public static class NET_DVR_CHECK_FACE_PICTURE_COND extends HIKSDKStructure { + public int dwSize; + public int dwPictureNum; //图片数量 + public byte byCheckTemplate; //0-校验图片是否合法(默认),1-校验图片和建模数据是否匹配 + public byte[] byRes = new byte[127]; + } + + public static class NET_DVR_CHECK_FACE_PICTURE_CFG extends HIKSDKStructure { + public int dwSize; + public int dwPictureNo; //图片编号 + public int dwPictureLen; //图片长度(图片大小不超过200k) + public Pointer pPictureBuffer; //图片指针 + public int dwFaceTemplateLen; //人脸建模数据长度 + public Pointer pFaceTemplateBuffer; //人脸建模数据指针 + public byte[] byRes = new byte[248]; + } + + public static class NET_DVR_CHECK_FACE_PICTURE_STATUS extends HIKSDKStructure { + public int dwSize; + public int dwPictureNo; //图片编号 + public byte byCheckStatus; //校验结果:0-无效,1-建模成功,2-建模失败,3-人脸模块通讯异常,4-图像无人脸,5-人脸朝上,6-人脸朝下,7-人脸偏左,8-人脸偏右,9-人脸顺时旋转, + //10 - 人脸逆时旋转,11-人眼间距小,12-人脸和模板匹配,13-人脸和模板不匹配,14-传输数据有误 + public byte[] byRes = new byte[127]; + } + + public static class NET_DVR_FINGER_PRINT_CFG_V50 extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //指纹关联的卡号 + public int dwFingerPrintLen; //指纹数据长度 + public byte[] byEnableCardReader = new byte[MAX_CARD_READER_NUM_512]; //需要下发指纹的读卡器,按数组表示,从低位到高位表示,0-不下发该读卡器,1-下发到该读卡器 + public byte byFingerPrintID; //手指编号,有效值范围为1-10 + public byte byFingerType; //指纹类型 0-普通指纹,1-胁迫指纹,2-巡更指纹,3-超级指纹,4-解除指纹 + public byte[] byRes1 = new byte[30]; + public byte[] byFingerData = new byte[MAX_FINGER_PRINT_LEN]; //指纹数据内容 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + public byte[] byLeaderFP = new byte[MAX_DOOR_NUM_256]; //对门是否有首次认证功能(按字节表示):0-无首次认证功能,1-有首次认证功能 + public byte[] byRes = new byte[128]; + } + + public static class NET_DVR_FINGER_PRINT_STATUS_V50 extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //指纹关联的卡号 + public byte[] byCardReaderRecvStatus = new byte[MAX_CARD_READER_NUM_512]; //指纹读卡器状态,按字节表示,0-失败,1-成功,2-该指纹模组不在线,3-重试或指纹质量差,4-内存已满,5-已存在该指纹,6-已存在该指纹ID,7-非法指纹ID,8-该指纹模组无需配置,10-指纹读卡器版本过低(无法支持工号) + public byte byFingerPrintID; //手指编号,有效值范围为1-10 + public byte byFingerType; //指纹类型 0-普通指纹,1-胁迫指纹,2-巡更指纹,3-超级指纹,4-解除指纹 + public byte byTotalStatus; //下发总的状态,0-当前指纹未下完所有读卡器,1-已下完所有读卡器(这里的所有指的是门禁主机往所有的读卡器下发了,不管成功与否) + public byte byRecvStatus; //主机错误状态:0-成功,1-手指编号错误,2-指纹类型错误,3-卡号错误(卡号规格不符合设备要求),4-指纹未关联工号或卡号(工号或卡号字段为空),5-工号不存在,6-指纹数据长度为0,7-读卡器编号错误,8-工号错误 + public byte[] byErrorMsg = new byte[ERROR_MSG_LEN]; //下发错误信息,当byCardReaderRecvStatus为5时,表示已存在指纹对应的卡号 + public int dwCardReaderNo; //当byCardReaderRecvStatus为5时,表示已存在指纹对应的指纹读卡器编号,可用于下发错误返回。0时表示无错误信息 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + public byte[] byErrorEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //下发错误信息,当byCardReaderRecvStatus为5时,表示已存在指纹对应的工号(人员ID) + public byte[] byRes = new byte[128]; + } + + public static class NET_DVR_FINGER_PRINT_INFO_COND_V50 extends HIKSDKStructure { + public int dwSize; + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //指纹关联的卡号(该字段获取时有效,设置时无效) + public byte[] byEnableCardReader = new byte[MAX_CARD_READER_NUM_512]; //指纹的读卡器是否有效,0-无效,1-有效 + public int dwFingerPrintNum; //设置或获指纹数量,获取时置为0xffffffff表示获取所有指纹信息 + public byte byFingerPrintID; //手指编号,有效值范围为1-10 0xff表示该卡所有指纹 + public byte byCallBackMode; //设备回调方式,0-设备所有读卡器下完了返回,1-在时间段内下了部分也返回 + public byte[] byRes2 = new byte[2]; //保留 + public byte[] byEmployeeNo = new byte[NET_SDK_EMPLOYEE_NO_LEN]; //工号(人员ID) + public byte[] byRes1 = new byte[128]; //保留 + } + + public static class NET_DVR_GROUP_CFG extends HIKSDKStructure { + public int dwSize; + public byte byEnable; //是否启用,0-不启用,1-启用 + public byte[] byRes1 = new byte[3]; + public NET_DVR_VALID_PERIOD_CFG struValidPeriodCfg = new NET_DVR_VALID_PERIOD_CFG(); //群组有效期参数 + public byte[] byGroupName = new byte[32]; //群组名称 + public byte[] byRes2 = new byte[32]; + } + + public static class NET_DVR_MULTI_CARD_CFG_V50 extends HIKSDKStructure { + public int dwSize; + public byte byEnable; + public byte bySwipeIntervalTimeout; + public byte[] byRes1 = new byte[2]; + public NET_DVR_MULTI_CARD_GROUP_CFG_V50[] struGroupCfg = (NET_DVR_MULTI_CARD_GROUP_CFG_V50[]) new NET_DVR_MULTI_CARD_GROUP_CFG_V50().toArray(20); + public byte[] byRes2 = new byte[32]; + } + + public static class NET_DVR_MULTI_CARD_GROUP_CFG_V50 extends HIKSDKStructure { + public byte byEnable; + public byte byEnableOfflineVerifyMode; + public byte[] byRes1 = new byte[2]; + public int dwTemplateNo; + public NET_DVR_GROUP_COMBINATION_INFO_V50[] struGroupCombination = (NET_DVR_GROUP_COMBINATION_INFO_V50[]) new NET_DVR_GROUP_COMBINATION_INFO_V50().toArray(8); + } + + public static class NET_DVR_GROUP_COMBINATION_INFO_V50 extends HIKSDKStructure { + public byte byEnable; + public byte byMemberNum; + public byte bySequenceNo; + public byte byRes; + public int dwGroupNo; + } + + + //自定义结构体,用于二维数组转换 + public static class NET_DVR_SINGLE_PLAN_SEGMENT_WEEK extends HIKSDKStructure { + public NET_DVR_SINGLE_PLAN_SEGMENT[] struPlanCfgDay = new NET_DVR_SINGLE_PLAN_SEGMENT[MAX_TIMESEGMENT_V30]; //一天的计划参数 + } + + public static class NET_DVR_WEEK_PLAN_CFG extends HIKSDKStructure { + public int dwSize; + public byte byEnable; //是否使能,1-使能,0-不使能 + public byte[] byRes1 = new byte[3]; + public NET_DVR_SINGLE_PLAN_SEGMENT_WEEK[] struPlanCfg = new NET_DVR_SINGLE_PLAN_SEGMENT_WEEK[MAX_DAYS]; //周计划参数 + public byte[] byRes2 = new byte[16]; + } + + public static class NET_DVR_SINGLE_PLAN_SEGMENT extends HIKSDKStructure { + public byte byEnable; //是否使能,1-使能,0-不使能 + public byte byDoorStatus; //门状态模式(梯控模式),0-无效,1-常开状态(自由),2-常闭状态(禁用),3-普通状态(门状态计划使用) + public byte byVerifyMode; //验证方式,0-无效,1-刷卡,2-刷卡+密码(读卡器验证方式计划使用),3-刷卡,4-刷卡或密码(读卡器验证方式计划使用), 5-指纹,6-指纹+密码,7-指纹或刷卡,8-指纹+刷卡,9-指纹+刷卡+密码(无先后顺序),10-人脸或指纹或刷卡或密码,11-人脸+指纹,12-人脸+密码, + //13-人脸+刷卡,14-人脸,15-工号+密码,16-指纹或密码,17-工号+指纹,18-工号+指纹+密码,19-人脸+指纹+刷卡,20-人脸+密码+指纹,21-工号+人脸,22-人脸或人脸+刷卡 + public byte[] byRes = new byte[5]; + public NET_DVR_TIME_SEGMENT struTimeSegment; //时间段参数 + } + + + public static class NET_DVR_TIME_SEGMENT extends HIKSDKStructure { + public NET_DVR_SIMPLE_DAYTIME struBeginTime; //开始时间点 + public NET_DVR_SIMPLE_DAYTIME struEndTime; //结束时间点 + } + + public static class NET_DVR_SIMPLE_DAYTIME extends HIKSDKStructure { + public byte byHour; //时 + public byte byMinute; //分 + public byte bySecond; //秒 + public byte byRes; + } + + public static class NET_DVR_WEEK_PLAN_COND extends HIKSDKStructure { + public int dwSize; + public int dwWeekPlanNumber; //周计划编号 + public short wLocalControllerID; //就地控制器序号[1,64] + public byte[] byRes = new byte[106]; + } + + public static final int TEMPLATE_NAME_LEN = 32; //计划模板名称长度 + public static final int MAX_HOLIDAY_GROUP_NUM = 16; //计划模板最大假日组数 + + public static class NET_DVR_PLAN_TEMPLATE extends HIKSDKStructure { + public int dwSize; + public byte byEnable; //是否启用,1-启用,0-不启用 + public byte[] byRes1 = new byte[3]; + public byte[] byTemplateName = new byte[TEMPLATE_NAME_LEN]; //模板名称 + public int dwWeekPlanNo; //周计划编号,0为无效 + public int[] dwHolidayGroupNo = new int[MAX_HOLIDAY_GROUP_NUM]; //假日组编号,就前填充,遇0无效 + public byte[] byRes2 = new byte[32]; + } + + public static class NET_DVR_PLAN_TEMPLATE_COND extends HIKSDKStructure { + public int dwSize; + public int dwPlanTemplateNumber; //计划模板编号,从1开始,最大值从门禁能力集获取 + public short wLocalControllerID; //就地控制器序号[1,64],0无效 + public byte[] byRes = new byte[106]; + } + + public static class NET_DVR_CAPTURE_FACE_COND extends HIKSDKStructure { + public int dwSize; + public byte[] byRes = new byte[128]; + } + + public static class NET_DVR_FACE_FEATURE extends HIKSDKStructure { + public NET_VCA_RECT struFace; //人脸子图区域 + public NET_VCA_POINT struLeftEye; // 左眼坐标 + public NET_VCA_POINT struRightEye; // 右眼坐标 + public NET_VCA_POINT struLeftMouth; // 嘴左边坐标 + public NET_VCA_POINT struRightMouth; // 嘴右边坐标 + public NET_VCA_POINT struNoseTip; // 鼻子坐标 + } + + public static class NET_DVR_CAPTURE_FACE_CFG extends HIKSDKStructure { + public int dwSize; + public int dwFaceTemplate1Size; //人脸模板1数据大小,等于0时,代表无人脸模板1数据 + public Pointer pFaceTemplate1Buffer; //人脸模板1数据缓存(不大于2.5k) + public int dwFaceTemplate2Size; //人脸模板2数据大小,等于0时,代表无人脸模板2数据 + public Pointer pFaceTemplate2Buffer; //人脸模板2数据缓存(不大于2.5K) + public int dwFacePicSize; //人脸图片数据大小,等于0时,代表无人脸图片数据 + public Pointer pFacePicBuffer; //人脸图片数据缓存 + public byte byFaceQuality1; //人脸质量,范围1-100 + public byte byFaceQuality2; //人脸质量,范围1-100 + public byte byCaptureProgress; //采集进度,目前只有两种进度值:0-未采集到人脸,100-采集到人脸(只有在进度为100时,才解析人脸信息) + public byte byFacePicQuality; //人脸图片中人脸质量 + public int dwInfraredFacePicSize; //红外人脸图片数据大小,等于0时,代表无人脸图片数据 + public Pointer pInfraredFacePicBuffer; //红外人脸图片数据缓存 + public byte byInfraredFacePicQuality; //红外人脸图片中人脸质量 + public byte[] byRes1 = new byte[3]; + public NET_DVR_FACE_FEATURE struFeature = new NET_DVR_FACE_FEATURE(); //人脸抠图特征信息 + public byte[] byRes = new byte[56]; + } + + public static class NET_DVR_XML_CONFIG_INPUT extends HIKSDKStructure { + public int dwSize; + public Pointer lpRequestUrl; + public int dwRequestUrlLen; + public Pointer lpInBuffer; + public int dwInBufferSize; + public int dwRecvTimeOut; + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_STRING_POINTER extends HIKSDKStructure { + public byte[] byString; + + public NET_DVR_STRING_POINTER(int iLen) { + byString = new byte[iLen]; + } + } + + public static class NET_DVR_XML_CONFIG_OUTPUT extends HIKSDKStructure { + public int dwSize; + public Pointer lpOutBuffer; + public int dwOutBufferSize; + public int dwReturnedXMLSize; + public Pointer lpStatusBuffer; + public int dwStatusSize; + public byte[] byRes = new byte[32]; + } + + //报警场景信息 + public static class NET_DVR_SCENE_INFO extends HIKSDKStructure { + public int dwSceneID; //场景ID, 0 - 表示该场景无效 + public byte[] bySceneName = new byte[NAME_LEN]; //场景名称 + public byte byDirection; //监测方向 1-上行,2-下行,3-双向,4-由东向西,5-由南向北,6-由西向东,7-由北向南,8-其它 + public byte[] byRes1 = new byte[3]; //保留 + public NET_DVR_PTZPOS struPtzPos; //Ptz 坐标 + public byte[] byRes2 = new byte[64]; //保留 + } + + // 方向结构体 + public static class NET_DVR_DIRECTION extends HIKSDKStructure { + public NET_VCA_POINT struStartPoint = new NET_VCA_POINT(); // 方向起始点 + public NET_VCA_POINT struEndPoint = new NET_VCA_POINT(); // 方向结束点 + } + + // 交通事件信息 + public static class NET_DVR_AID_INFO extends HIKSDKStructure { + public byte byRuleID; // 规则序号,为规则配置结构下标,0-16 + public byte[] byRes1 = new byte[3]; + public byte[] byRuleName = new byte[NAME_LEN]; // 规则名称 + public int dwAIDType; // 报警事件类型 + public NET_DVR_DIRECTION struDirect = new NET_DVR_DIRECTION(); // 报警指向区域 + public byte bySpeedLimit; //限速值,单位km/h[0,255] + public byte byCurrentSpeed; //当前速度值,单位km/h[0,255] + public byte byVehicleEnterState; //车辆出入状态:0- 无效,1- 驶入,2- 驶出 + public byte byState; //0-变化上传,1-轮巡上传 + public byte[] byParkingID = new byte[16]; //停车位编号 + public int dwAIDTypeEx; // 报警事件类型扩展,参考TRAFFIC_AID_TYPE_EX + public byte[] byRes2 = new byte[16]; // 保留字节 + } + + public int ILLEGAL_LEN = 32; //违法代码长度 + public int MONITORSITE_ID_LEN = 48;//监测点编号长度 + public int DEVICE_ID_LEN = 48; + + //交通取证报警 + public static class NET_DVR_TFS_ALARM extends HIKSDKStructure { + public int dwSize; //结构体大小 + public int dwRelativeTime; //相对时标 + public int dwAbsTime; //绝对时标 + public int dwIllegalType; //违章类型,采用国标定义,当dwIllegalType值为0xffffffff时使用byIllegalCode + public int dwIllegalDuration; //违法持续时间(单位:秒) = 抓拍最后一张图片的时间 - 抓拍第一张图片的时间 + public byte[] byMonitoringSiteID = new byte[MONITORSITE_ID_LEN];//监测点编号(路口编号、内部编号) + public byte[] byDeviceID = new byte[DEVICE_ID_LEN]; //设备编号 + public NET_VCA_DEV_INFO struDevInfo = new NET_VCA_DEV_INFO(); //前端设备信息 + public NET_DVR_SCENE_INFO struSceneInfo = new NET_DVR_SCENE_INFO(); //场景信息 + public NET_DVR_TIME_EX struBeginRecTime = new NET_DVR_TIME_EX(); //录像开始时间 + public NET_DVR_TIME_EX struEndRecTime = new NET_DVR_TIME_EX(); //录像结束时间 + public NET_DVR_AID_INFO struAIDInfo = new NET_DVR_AID_INFO(); //交通事件信息 + public NET_DVR_PLATE_INFO struPlateInfo = new NET_DVR_PLATE_INFO(); //车牌信息 + public NET_DVR_VEHICLE_INFO struVehicleInfo = new NET_DVR_VEHICLE_INFO(); //车辆信息 + public int dwPicNum; //图片数量 + public NET_ITS_PICTURE_INFO[] struPicInfo = new NET_ITS_PICTURE_INFO[8]; //图片信息,最多8张 + public byte bySpecificVehicleType; //具体车辆种类 参考识别结果类型VTR_RESULT + public byte byLaneNo; //关联车道号 + public byte[] byRes1 = new byte[2]; //保留 + public NET_DVR_TIME_V30 struTime = new NET_DVR_TIME_V30();//手动定位,当前时间。 + public int dwSerialNo;//序号; + public byte byVehicleAttribute;//车辆属性,按位表示,0- 无附加属性(普通车),bit1- 黄标车(类似年检的标志),bit2- 危险品车辆,值:0- 否,1- 是 + public byte byPilotSafebelt;//0-表示未知,1-系安全带,2-不系安全带 + public byte byCopilotSafebelt;//0-表示未知,1-系安全带,2-不系安全带 + public byte byPilotSunVisor;//0-表示未知,1-不打开遮阳板,2-打开遮阳板 + public byte byCopilotSunVisor;//0-表示未知, 1-不打开遮阳板,2-打开遮阳板 + public byte byPilotCall;// 0-表示未知, 1-不打电话,2-打电话 + public byte[] byRes2 = new byte[2]; //保留 + public byte[] byIllegalCode = new byte[ILLEGAL_LEN/*32*/];//违法代码扩展,当dwIllegalType值为0xffffffff;使用这个值 + public short wCountry; // 国家索引值,参照枚举COUNTRY_INDEX + public byte byRegion; //区域索引值,0-保留,1-欧洲(Europe Region),,3-欧洲&(EU&CIS) , 4-中东(Middle East),0xff-所有 + public byte byCrossLine;//是否压线停车(侧方停车),0-表示未知,1-不压线,2-压线 + public byte[] byParkingSerialNO = new byte[16];//泊车位编号 + public byte byCrossSpaces;//是否跨泊车位停车(侧方停车),0-表示未知,1-未跨泊车位停车,2-跨泊车位停车 + public byte byAngledParking;//是否倾斜停车(侧方停车), 0-表示未知,1-未倾斜停车,2-倾斜停车 + public byte byAlarmValidity;//报警置信度,可以输出驶入驶出的置信度,范围0-100;置信度越高,事件真实性越高 + public byte byDoorsStatus;//车门状态 0-车门关闭 1-车门开启 + public int dwXmlLen;//XML报警信息长度 + public Pointer pXmlBuf; // XML报警信息指针,其XML对应到EventNotificationAlert XML Block + public byte byVehicleHeadTailStatus;//车头车尾状态 0-保留 1-车头 2-车尾 + public byte byBrokenNetHttp; //断网续传标志位,0-不重传数据,1-重传数据 + public byte[] byRes = new byte[30]; //保留 + } + + public static class NET_ITS_OVERLAPCFG_COND extends HIKSDKStructure { + public int dwSize; + public int dwChannel; + public int dwConfigMode; //配置模式,0-终端,1-前端(直连前端或终端接前端) + public byte byPicModeType;//0-表示小图(独立图),1-表示大图(合成图) + /* + 0表示关联 抓拍MPR模式(多帧触发抓拍 IPC使用) + 1 表示关联 抓拍 HVT 模式(混卡IPC使用) + */ + public byte byRelateType; + public byte[] byRes = new byte[14]; + + } + + //字符叠加每一条信息结构体 + public static class NET_ITS_OVERLAP_SINGLE_ITEM_PARAM_V50 extends HIKSDKStructure { + public byte[] byRes1 = new byte[2]; // 保留 + public byte byItemType; //类型,详见OVERLAP_ITEM_TYPE + public byte byChangeLineNum; //叠加项后的换行数[0-10](默认0) + public byte bySpaceNum; //叠加项后的空格数[0-255](默认0) + public byte[] byRes2 = new byte[2]; + public byte byEnablePos; //是否启用坐标显示 + public short wStartPosTop; //起始上坐标,只对图片内部叠加有效[0~2448](默认0) + public short wStartPosLeft; //起始左坐标,只对图片内部叠加有效[0~2448](默认0) + //自定义类型;与byItemType参数对应。可将byItemType参数类型自定义名称。若自定义内容为空,便默认以byItemType参数中的类型命名。 + public byte[] byItemTypeCustom = new byte[32]; + public byte[] byRes = new byte[8]; + + } + + public int MAX_OVERLAP_ITEM_NUM = 50; //最大字符叠加种数 + + public static class NET_ITS_OVERLAP_ITEM_PARAM_V50 extends HIKSDKStructure { + public NET_ITS_OVERLAP_SINGLE_ITEM_PARAM_V50[] struSingleItem = new NET_ITS_OVERLAP_SINGLE_ITEM_PARAM_V50[MAX_OVERLAP_ITEM_NUM]; //单条字符参数 + public int dwLinePercent; //叠加行百分比(0-100),(默认100) + public int dwItemsStlye; //叠加方式:0-横排,1-竖排(默认横排) + public short wStartPosTop; //起始上坐标,只对图片内部叠加有效[0~2448](默认0) + public short wStartPosLeft; //起始左坐标,只对图片内部叠加有效[0~2448](默认0) + public short wCharStyle; //字体类型,0-宋体1-魏体(默认) + public short wCharSize; //字符大小,0--16x16,1--32x32,2-48x48,3--64x64 (默认),8x128(Ver3.7) + public short wCharInterval; //字符间距,[0~16],可设单位:像素(默认) + public byte[] byRes1 = new byte[2]; + public int dwForeClorRGB; //前景色的RGB值bit0-1:(B) bit2-3:(G) bit4-5:(G) (默认x00FFFFFF-白) + public int dwBackClorRGB; //背景色的RGB值,只对图片外叠加有效bit0-1:(B) bit2-3:(G) bit4-5:(G) (默认x00000000-黑) + public byte byColorAdapt; //颜色是否自适应0-否1-是 + //(Ver3.7 新增) + // 参数补零使能 0-补零, 1-不补零(详细注释)速度,限速值 不足3位补0 + public byte byParamFillZeroEnble; + public byte byPlateLeftCornerEnable;// 车牌小图叠加左上角使能 0-不叠加, 1-叠加 + public byte byRes2; + public short wStartSPicPosTop; //起始上坐标,只对图片内部叠加有效[0~2448](默认0) + public short wStartSPicPosLeft; //起始左坐标,只对图片内部叠加有效[0~2448](默认0) + //OSD叠加位置 0-图片内,1-图片上边缘,2-图片下边缘(合成图专用的是上边缘外)(V3.7) + public byte byOsdLocate; + public byte[] byRes = new byte[63]; + + } + + //叠加项具体信息 + public static class NET_ITS_OVERLAP_INFO_PARAM extends HIKSDKStructure { + public byte[] bySite = new byte[128]; //地点描述 + public byte[] byRoadNum = new byte[32]; //路口编号 + public byte[] byInstrumentNum = new byte[32]; //设备编号 + public byte[] byDirection = new byte[32]; //方向编号 + public byte[] byDirectionDesc = new byte[32]; //方向描述 + public byte[] byLaneDes = new byte[32]; //车道描述 + public byte[] byRes1 = new byte[32]; //保留 + public byte[] byMonitoringSite1 = new byte[44]; //监测点1信息 + public byte[] byMonitoringSite2 = new byte[32]; //监测点2信息 + public byte[] byRes = new byte[64]; //保留 + } + + public static class NET_ITS_OVERLAP_CFG_V50 extends HIKSDKStructure { + public int dwSize; + public byte byEnable; //是否启用,0-不启用,1-启用 + public byte[] byRes1 = new byte[3]; + public NET_ITS_OVERLAP_ITEM_PARAM_V50 struOverLapItemV50 = new NET_ITS_OVERLAP_ITEM_PARAM_V50(); //字符串参数 + public NET_ITS_OVERLAP_INFO_PARAM struOverLapInfo = new NET_ITS_OVERLAP_INFO_PARAM(); //字符串内容信息 + public byte[] byRes = new byte[120]; + + } + + //人体特征识别结果结构体 + public static class NET_VCA_HUMAN_FEATURE extends HIKSDKStructure { + public byte byRes3; + public byte bySex; //性别, 0-表示“未知”(算法不支持),1 – 男 , 2 – 女, 0xff-算法支持,但是没有识别出来 + public byte byEyeGlass; //是否戴眼镜 0-表示“未知”(算法不支持),1 – 不戴, 2 – 戴,0xff-算法支持,但是没有识别出来 + //抓拍图片人脸年龄的使用方式,如byAge为15,byAgeDeviation为1,表示,实际人脸图片年龄的为14-16之间 + public byte byRes4;// 0-表示“未知”(算法不支持),0xff-算法支持,但是没有识别出来 + public byte byDeviation;//误差值 + public byte byRes0; //字段预留 + public byte byMask; //是否戴口罩 0-表示“未知”(算法不支持),1 – 不戴, 2 – 戴, 0xff-算法支持,但是没有识别出来 + public byte bySmile; //是否微笑 0-表示“未知”(算法不支持),1 – 不微笑, 2 – 微笑, 0xff-算法支持,但是没有识别出来 + public byte byFaceExpression; /* 表情,参见FACE_EXPRESSION_GROUP_ENUM*/ + public byte byRes1; + public byte byRes2; + public byte byHat; // 帽子, 0-不支持,1-不戴帽子,2-戴帽子,0xff-unknow表示未知,算法支持未检出 + public byte[] byRes = new byte[4]; //保留 + } + + //特征抓拍附加信息结构体 + public static class NET_VCA_FACESNAP_ADDINFO extends HIKSDKStructure { + //人脸矩形框,该坐标为人脸小图(头肩照)中人脸的坐标 + public NET_VCA_RECT struFacePicRect = new NET_VCA_RECT(); + public int iSwingAngle;//旋转角, -90~90度 + public int iTiltAngle;//俯仰角, -90~90度 + public int dwPupilDistance;//瞳距,范围为:最小值为10像素,最大值为当前分辨率宽度/1.6 + public byte byBlockingState;//目标遮挡状态, 0-表示“未知”(算法不支持),1~无遮挡,2~瞬时轻度遮挡,3~持续轻度遮挡,4~严重遮挡 + public byte byFaceSnapThermometryEnabled;//特征抓拍测温使能 1-开启 0-关闭 + public byte byIsAbnomalTemperature;//特征抓拍测温是否温度异常 1-是 0-否 + public byte byThermometryUnit;//测温单位: 0-摄氏度(℃),1-华氏度(℉),2-开尔文(K) + public NET_DVR_TIME_EX struEnterTime = new NET_DVR_TIME_EX(); // 最佳抓拍下进入时间 + public NET_DVR_TIME_EX struExitTime = new NET_DVR_TIME_EX(); // 最佳抓拍下离开时间 + public float fFaceTemperature; // 人脸温度( - 20.0℃~150.0℃,精确到小数点后1位) + public float fAlarmTemperature;// 测温报警警阈值(精确到小数点后1位) + public byte[] byRes = new byte[472];// 保留字节 + } + + //特征抓拍结果 + public static class NET_VCA_FACESNAP_RESULT extends HIKSDKStructure { + public int dwSize; // 结构大小 + public int dwRelativeTime; // 相对时标 + public int dwAbsTime; // 绝对时标 + public int dwFacePicID; //人脸图ID + public int dwFaceScore; //人脸评分,0-100 + public NET_VCA_TARGET_INFO struTargetInfo = new NET_VCA_TARGET_INFO();//报警目标信息 + public NET_VCA_RECT struRect = new NET_VCA_RECT(); //人脸子图区域 + public NET_VCA_DEV_INFO struDevInfo = new NET_VCA_DEV_INFO(); //前端设备信息 + public int dwFacePicLen; //人脸子图的长度,为0表示没有图片,大于0表示有图片 + public int dwBackgroundPicLen; //背景图的长度,为0表示没有图片,大于0表示有图片(保留) + public byte bySmart; //IDS设备返回0(默认值),Smart Functiom Return 1 + public byte byAlarmEndMark;//报警结束标记0-保留,1-结束标记(该字段结合人脸ID字段使用,表示该ID对应的下报警结束,主要提供给NVR使用,用于判断报警结束,提取识别图片数据中,清晰度最高的图片) + public byte byRepeatTimes; //重复报警次数,0-无意义 + public byte byUploadEventDataType;//人脸图片数据长传方式:0-二进制数据,1-URL + public NET_VCA_HUMAN_FEATURE struFeature = new NET_VCA_HUMAN_FEATURE(); //人体属性 + public float fStayDuration; //停留画面中时间(单位: 秒) + public byte[] sStorageIP = new byte[16]; //存储服务IP地址 + public short wStoragePort; //存储服务端口号 + public short wDevInfoIvmsChannelEx; //与NET_VCA_DEV_INFO里的byIvmsChannel含义相同,能表示更大的值。老客户端用byIvmsChannel能继续兼容,但是最大到255。新客户端版本请使用wDevInfoIvmsChannelEx。 + public byte byFacePicQuality; + public byte byUIDLen; // 上传报警的标识长度 + public byte byLivenessDetectionStatus;// 活体检测状态:0-保留,1-未知(检测失败),2-非真人人脸,3-真人人脸,4-未开启活体检测 + /*附加信息标识位(即是否有NET_VCA_FACESNAP_ADDINFO结构体),0-无附加信息, 1-有附加信息。*/ + public byte byAddInfo; + public Pointer pUIDBuffer; //标识指针 + //附加信息指针,指向NET_VCA_FACESNAP_ADDINFO结构体 + public Pointer pAddInfoBuffer; + public byte byTimeDiffFlag; /*时差字段是否有效 0-时差无效, 1-时差有效 */ + public byte cTimeDifferenceH; /*与UTC的时差(小时),-12 ... +14, +表示东区,,byTimeDiffFlag为1时有效*/ + public byte cTimeDifferenceM; /*与UTC的时差(分钟),-30, 30, 45, +表示东区,byTimeDiffFlag为1时有效*/ + public byte byBrokenNetHttp; //断网续传标志位,0-不是重传数据,1-重传数据 + public Pointer pBuffer1; //人脸子图的图片数据 + public Pointer pBuffer2; //背景图的图片数据(保留,通过查找背景图接口可以获取背景图) + } + + //特征抓拍信息 + public static class NET_VCA_FACESNAP_INFO_ALARM extends HIKSDKStructure { + public int dwRelativeTime; // 相对时标 + public int dwAbsTime; // 绝对时标 + public int dwSnapFacePicID; //抓拍人脸图ID + public int dwSnapFacePicLen; //抓拍人脸子图的长度,为0表示没有图片,大于0表示有图片 + public NET_VCA_DEV_INFO struDevInfo = new NET_VCA_DEV_INFO(); //前端设备信息 + public byte byFaceScore; //人脸评分,指人脸子图的质量的评分,0-100 + public byte bySex;//性别,0-未知,1-男,2-女 + public byte byGlasses;//是否带眼镜,0-未知,1-是,2-否 + //抓拍图片人脸年龄的使用方式,如byAge为15,byAgeDeviation为1,表示,实际人脸图片年龄的为14-16之间 + public byte byRes2;// + public byte byDeviation;//误差值 + public byte byGroup;//段,详见HUMAN_GROUP_ENUM,若传入0xff表示未知 + public byte byFacePicQuality; + public byte byRes1; // 保留字节 + public int dwUIDLen; // 上传报警的标识长度 + public Pointer pUIDBuffer; //标识指针 + public float fStayDuration; //停留画面中时间(单位: 秒) + public Pointer pBuffer1; //抓拍人脸子图的图片数据 + } + + //籍贯参数 + public static class NET_DVR_AREAINFOCFG extends HIKSDKStructure { + public short wNationalityID; //国籍 + public short wProvinceID; //省 + public short wCityID; //市 + public short wCountyID; //县 + public int dwCode; //国家标准的省份、城市、县级代码,当这个字段不为0的时候,使用这个值,新设备上传这个值表示籍贯参数,老设备这个值为0 + } + + //人员信息 + public int MAX_HUMAN_BIRTHDATE_LEN = 10; + + public static class NET_VCA_HUMAN_ATTRIBUTE extends HIKSDKStructure { + public byte bySex; //性别:0-男,1-女 + public byte byCertificateType; //证件类型:0-身份证,1-警官证 + public byte[] byBirthDate = new byte[MAX_HUMAN_BIRTHDATE_LEN]; //出生年月,如:201106 + public byte[] byName = new byte[NAME_LEN]; //姓名 + public NET_DVR_AREAINFOCFG struNativePlace = new NET_DVR_AREAINFOCFG(); //籍贯参数 + public byte[] byCertificateNumber = new byte[NAME_LEN]; //证件号 + public int dwPersonInfoExtendLen;// 人员标签信息扩展长度 + public Pointer pPersonInfoExtend; //人员标签信息扩展信息 + public byte byGroup;//段,,如传入0xff表示未知 + public byte[] byRes2 = new byte[11]; + } + + + //禁止名单报警信息 + public static class NET_VCA_BLOCKLIST_INFO_ALARM extends HIKSDKStructure { + public NET_VCA_BLOCKLIST_INFO struBlockListInfo = new NET_VCA_BLOCKLIST_INFO(); //禁止名单基本信息 + public int dwBlockListPicLen; //禁止名单人脸子图的长度,为0表示没有图片,大于0表示有图片 + public int dwFDIDLen;// 人脸库ID长度 + public Pointer pFDID; //人脸库Id指针 + public int dwPIDLen;// 人脸库图片ID长度 + public Pointer pPID; //人脸库图片ID指针 + public short wThresholdValue; //人脸库阈值[0,100] + public byte[] byRes = new byte[2]; // 保留字节 + public Pointer pBuffer1; //禁止名单人脸子图的图片数据 + } + + //禁止名单信息 + public static class NET_VCA_BLOCKLIST_INFO extends HIKSDKStructure { + public int dwSize; //结构大小 + public int dwRegisterID; //名单注册ID号(只读) + public int dwGroupNo; //分组号 + public byte byType; //禁止/运行允许名单标志:0-全部,1-允许名单,2-禁止名单 + public byte byLevel; //禁止名单等级,0-全部,1-低,2-中,3-高 + public byte[] byRes1 = new byte[2]; //保留 + public NET_VCA_HUMAN_ATTRIBUTE struAttribute = new NET_VCA_HUMAN_ATTRIBUTE(); //人员信息 + public byte[] byRemark = new byte[NAME_LEN]; //备注信息 + public int dwFDDescriptionLen;//人脸库描述数据长度 + public Pointer pFDDescriptionBuffer;//人脸库描述数据指针 + public int dwFCAdditionInfoLen;//抓拍库附加信息长度 + public Pointer pFCAdditionInfoBuffer;//抓拍库附加信息数据指针(FCAdditionInfo中包含相机PTZ坐标) + public byte[] byRes2 = new byte[4]; + } + + + //禁止名单比对结果报警上传 + public static class NET_VCA_FACESNAP_MATCH_ALARM extends HIKSDKStructure { + public int dwSize; // 结构大小 + public float fSimilarity; //相似度,[0.001,1] + public NET_VCA_FACESNAP_INFO_ALARM struSnapInfo = new NET_VCA_FACESNAP_INFO_ALARM(); //抓拍信息 + public NET_VCA_BLOCKLIST_INFO_ALARM struBlockListInfo = new NET_VCA_BLOCKLIST_INFO_ALARM(); //禁止名单信息 + public byte[] sStorageIP = new byte[16]; //存储服务IP地址 + public short wStoragePort; //存储服务端口号 + public byte byMatchPicNum; //匹配图片的数量,0-保留(老设备这个值默认0,新设备这个值为0时表示后续没有匹配的图片信息) + public byte byPicTransType;//图片数据传输方式: 0-二进制;1-url + public int dwSnapPicLen;//设备识别抓拍图片长度 + public Pointer pSnapPicBuffer;//设备识别抓拍图片指针 + public NET_VCA_RECT struRegion = new NET_VCA_RECT();//目标边界框,设备识别抓拍图片中,人脸子图坐标 + public int dwModelDataLen;//建模数据长度 + public Pointer pModelDataBuffer;// 建模数据指针 + public byte byModelingStatus;// 建模状态 + public byte byLivenessDetectionStatus;//活体检测状态:0-保留,1-未知(检测失败),2-非真人人脸,3-真人人脸,4-未开启活体检测 + public byte cTimeDifferenceH; /*与UTC的时差(小时),-12 ... +14, +表示东区,0xff无效*/ + public byte cTimeDifferenceM; /*与UTC的时差(分钟),-30, 30, 45, +表示东区,0xff无效*/ + public byte byMask; //抓拍图是否戴口罩,0-保留,1-未知,2-不戴口罩,3-戴口罩 + public byte bySmile; //抓拍图是否微笑,0-保留,1-未知,2-不微笑,3-微笑 + public byte byContrastStatus; //比对结果,0-保留,1-比对成功,2-比对失败 + public byte byBrokenNetHttp; //断网续传标志位,0-不是重传数据,1-重传数据 + } + + //交通事件报警(扩展) + public static class NET_DVR_AID_ALARM_V41 extends HIKSDKStructure { + public int dwSize; //结构长度 + public int dwRelativeTime; //相对时标 + public int dwAbsTime; //绝对时标 + public NET_VCA_DEV_INFO struDevInfo = new NET_VCA_DEV_INFO(); //前端设备信息 + public NET_DVR_AID_INFO struAIDInfo = new NET_DVR_AID_INFO(); //交通事件信息 + public NET_DVR_SCENE_INFO struSceneInfo = new NET_DVR_SCENE_INFO(); //场景信息 + public int dwPicDataLen; //图片长度 + public Pointer pImage; //指向图片的指针 + // 0-数据直接上传; 1-云存储服务器URL(3.7Ver)原先的图片数据变成URL数据,图片长度变成URL长度 + public byte byDataType; + public byte byLaneNo; //关联车道号 + public short wMilliSecond; //时标毫秒 + //监测点编号(路口编号、内部编号) + public byte[] byMonitoringSiteID = new byte[MONITORSITE_ID_LEN/*48*/]; + public byte[] byDeviceID = new byte[DEVICE_ID_LEN/*48*/];//设备编号 + public int dwXmlLen;//XML报警信息长度 + public Pointer pXmlBuf;// XML报警信息指针,其XML对应到EventNotificationAlert XML Block + public byte byTargetType;// 检测的目标类型,0~未知,1~行人、2~二轮车、3~三轮车(行人检测中返回) + public byte byRuleID;//规则ID,1-4,当congestion事件配置了规则区域时返回 + public short wDevInfoIvmsChannelEx; //与NET_VCA_DEV_INFO里的byIvmsChannel含义相同,能表示更大的值。老客户端用byIvmsChannel能继续兼容,但是最大到255。新客户端版本请使用wDevInfoIvmsChannelEx。 + public byte byBrokenNetHttp; // 断网续传标志位,0-不重传数据,1-重传数据 + public byte[] byRes = new byte[3]; // 保留字节 + public int dwPlateSmallPicDataLen; //车牌小图图片长度 + public Pointer pPlateSmallImage; // //指向车牌小图的指针 + } + + + //交通统计信息报警(扩展) + public static class NET_DVR_TPS_ALARM_V41 extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public int dwRelativeTime; // 相对时标 + public int dwAbsTime; // 绝对时标 + public NET_VCA_DEV_INFO struDevInfo; // 前端设备信息 + public NET_DVR_TPS_INFO_V41 struTPSInfo; // 交通参数统计信息 + //监测点编号(路口编号、内部编号) + public byte[] byMonitoringSiteID = new byte[MONITORSITE_ID_LEN/*48*/]; + public byte[] byDeviceID = new byte[DEVICE_ID_LEN/*48*/];//设备编号 + public int dwStartTime; // 开始统计时间 + public int dwStopTime; // 结束统计时间 + public byte[] byRes = new byte[24]; // 保留 + } + + public static class NET_DVR_LANE_PARAM_V41 extends HIKSDKStructure { + public byte[] byRuleName = new byte[NAME_LEN]; // 车道规则名称 + public byte byRuleID; // 规则序号,为规则配置结构下标,0-7 + public byte byLaneType; // 车道上行或下行 + public byte byTrafficState; // 车道的交通状态,0-无效,1-畅通,2-拥挤,3-堵塞 + public byte byLaneNo; //车道号 + public int dwVaryType; // 车道交通参数变化类型参照 TRAFFIC_DATA_VARY_TYPE_EX_ENUM,按位区分 + public int dwTpsType; // 数据变化类型标志,表示当前上传的统计参数中,哪些数据有效,参照ITS_TPS_TYPE,按位区分 + public int dwLaneVolume; // 车道流量,统计有多少车子通过 + public int dwLaneVelocity; // 车道速度,公里计算 + public int dwTimeHeadway; // 车头时距,以秒计算 + public int dwSpaceHeadway; // 车头间距,以米来计算 + public float fSpaceOccupyRation; // 车道占有率,百分比计算(空间上) + public float fTimeOccupyRation; // 时间占有率,百分比计算 + public int dwLightVehicle; // 小型车数量 + public int dwMidVehicle; // 中型车数量 + public int dwHeavyVehicle; // 重型车数量 + public NET_DVR_LANE_QUEUE struLaneQueue; // 车道队列长度 + public NET_VCA_POINT struRuleLocation; // 规则位置虚拟线圈的中心 + public int dwOversizeVehicle; // 大型车数量 + public byte[] byRes2 = new byte[60]; // 保留 + } + + public int MAX_TPS_RULE = 8; // 最大参数规则数目 + + public static class NET_DVR_TPS_INFO_V41 extends HIKSDKStructure { + public int dwLanNum; // 交通参数的车道数目 + public NET_DVR_LANE_PARAM_V41[] struLaneParam = new NET_DVR_LANE_PARAM_V41[MAX_TPS_RULE]; + public int dwSceneID;//场景ID + public byte[] byRes = new byte[28]; //保留 + } + + // 车道队列结构体 + public static class NET_DVR_LANE_QUEUE extends HIKSDKStructure { + public NET_VCA_POINT struHead; //队列头 + public NET_VCA_POINT struTail; //队列尾 + public int dwLength; //实际队列长度 单位为米 [0-500] + } + + //TPS统计过车数据上传 + public static class NET_DVR_TPS_STATISTICS_INFO extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public int dwChan;//通道号 + public NET_DVR_TPS_STATISTICS_PARAM struTPSStatisticsInfo;// 交通参数统计信息 + public byte[] byRes = new byte[128]; // 保留 + } + + + // 交通参数统计信息 + public static class NET_DVR_TPS_STATISTICS_PARAM extends HIKSDKStructure { + public byte byStart; // 开始码 + public byte byCMD; // 命令号, 08-定时成组数据指令 + public byte[] byRes = new byte[2]; // 预留字节 + public short wDeviceID; // 设备ID + public short wDataLen; // 数据长度 + public byte byTotalLaneNum; // 有效车道总数 + public byte[] byRes1 = new byte[15]; + public NET_DVR_TIME_V30 struStartTime; //统计开始时间 + public int dwSamplePeriod; //统计时间,单位秒 + public NET_DVR_TPS_LANE_PARAM[] struLaneParam = new NET_DVR_TPS_LANE_PARAM[8]; + } + + //统计信息 + public static class NET_DVR_TPS_LANE_PARAM extends HIKSDKStructure { + public byte byLane; // 对应车道号 + public byte bySpeed; // 车道过车平均速度 + public byte[] byRes = new byte[2]; // 保留 + public int dwLightVehicle; // 小型车数量 + public int dwMidVehicle; // 中型车数量 + public int dwHeavyVehicle; // 重型车数量 + public int dwTimeHeadway; // 车头时距,以秒计算 + public int dwSpaceHeadway; // 车头间距,以米来计算 + public float fSpaceOccupyRation; // 空间占有率,百分比计算,浮点数*1000 + public float fTimeOccupyRation; // 时间占有率,百分比计算,浮点数*1000 + public byte[] byRes1 = new byte[16]; // 保留 + } + + //TPS实时过车数据上传 + public static class NET_DVR_TPS_REAL_TIME_INFO extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public int dwChan;//通道号 + public NET_DVR_TIME_V30 struTime; //检测时间 + public NET_DVR_TPS_PARAM struTPSRealTimeInfo;// 交通参数统计信息 + public Pointer pAddInfoBuffer; + /*附加信息标识(即是否有NET_DVR_TPS_ADDINFO结构体),0-无附加信息, 1-有附加信息。*/ + public byte byAddInfoFlag; + public byte[] byRes1 = new byte[3]; // 保留 + public int dwDeviceIDEx; // 设备ID扩展 + public byte[] byRes = new byte[8]; // 保留 + } + + //实时信息 + public static class NET_DVR_TPS_PARAM extends HIKSDKStructure { + public byte byStart; // 开始码 + public byte byCMD; // 命令号,01-进入指令,02-离开指令,03-拥堵状态指令(为03时,只有byLaneState和byQueueLen有效),04-多线圈状态(为04时,wLoopState和wStateMask有效,表示byLane车道上多个线圈的过车状态) + public short wSpaceHeadway; //车头间距,以米来计算 + public short wDeviceID; // 设备ID + public short wDataLen; // 数据长度 + public byte byLane; // 对应车道号 + public byte bySpeed; // 对应车速(KM/H) + public byte byLaneState; // 车道状态;0-无状态,1-畅通,2-拥挤,3-堵塞 + public byte byQueueLen; // 堵塞状态下排队长度(比如50米) + public short wLoopState; //线圈状态,第几位表示几号线圈状态。状态1-到达,0-离开,线圈编号从镜头由近到远依次增大,用户在解析时优先解析车道号,再解析线圈号,单个车道的线圈号是唯一的。 + public short wStateMask; //线圈状态掩码,掩码位为1对应wLoopState状态位有效,为0表示无效 + public int dwDownwardFlow; //当前车道 从上到下车流量 + public int dwUpwardFlow; //当前车道 从下到上车流量 + public byte byJamLevel; //拥堵等级,当byLaneState为3时有效,1-轻度,2-中度,3-重度 + public byte byVehicleDirection; //0-未知,1-由上而下,2-由下而上 + public byte byJamFlow; //拥堵新增流量,每新增一辆车就上报一次累计车辆的信息 + public byte byChannelizationLane; //渠化车道号(渠化表示,车道数量变化的情况,一般为路口车道的数目) + public byte byVehicleType; //车型识别:0- 未知,1- 客车(大型),2- 货车(大型),3- 轿车(小型),4- 非机动车 + public byte[] byRes1 = new byte[5]; //保留 + public short wTimeHeadway; // 车头时距,以秒计算 + } + + public static class NET_DVR_TIME_SEARCH_COND extends HIKSDKStructure { + public short wYear; //年 + public byte byMonth; //月 + public byte byDay; //日 + public byte byHour; //时 + public byte byMinute; //分 + public byte bySecond; //秒 + public byte byLocalOrUTC; //0-时差无效,设备本地时间,即设备OSD时间 1-时差有效 + public short wMillisecond; //毫秒,精度不够,默认为0 + public byte cTimeDifferenceH; //与UTC的时差(小时),-12 ... +14,+表示东区,byLocalOrUTC为1时有效 + public byte cTimeDifferenceM; //与UTC的时差(分钟),-30, 0, 30, 45,+表示东区,byLocalOrUTC为1时有效 + } + + //事件搜索条件 + public static class NET_DVR_SEARCH_EVENT_PARAM extends HIKSDKStructure { + public short wMajorType; //0-移动侦测,1-报警输入, 2-智能事件 5-pos录像 7-门禁事件, 8-非视频联动事件 + public short wMinorType; //搜索次类型- 根据主类型变化,0xffff表示全部 + public NET_DVR_TIME struStartTime = new NET_DVR_TIME(); //搜索的开始时间,停止时间: 同时为(0, 0) 表示从最早的时间开始,到最后,最前面的4000个事件 + public NET_DVR_TIME struEndTime = new NET_DVR_TIME(); //搜索的结束时间 + public byte byLockType; // 0xff-全部,0-未锁,1-锁定 + public byte byValue; //0-按位表示,1-按值表示 + public byte[] byRes = new byte[130]; // 保留 + public UNION_EVENT_PARAM uSeniorParam = new UNION_EVENT_PARAM(); + } + + public static class UNION_EVENT_PARAM extends Union { + public byte[] byLen = new byte[SEARCH_EVENT_INFO_LEN]; + public EVENT_INQUESTPARAM struInquestParam = new EVENT_INQUESTPARAM(); + } + + //审讯事件搜索条件 + public static class EVENT_INQUESTPARAM extends HIKSDKStructure { + public byte byRoomIndex; //审讯室编号,按值表示,从1开始 + public byte[] byRes1 = new byte[3]; + public byte[] sInquestInfo = new byte[INQUEST_CASE_LEN]; + public byte[] byRes2 = new byte[232]; //保留 + } + + //事件搜索条件 + public static class NET_DVR_SEARCH_EVENT_PARAM_V50 extends HIKSDKStructure { + public short wMajorType; //0-移动侦测,1-报警输入, 2-智能事件 5-pos录像 7-门禁事件, 8-非视频联动事件 + public short wMinorType; //搜索次类型- 根据主类型变化,0xffff表示全部 + public NET_DVR_TIME_SEARCH_COND struStartTime = new NET_DVR_TIME_SEARCH_COND(); //搜索的开始时间,停止时间: 同时为(0, 0) 表示从最早的时间开始,到最后,最前面的4000个事件 + public NET_DVR_TIME_SEARCH_COND struEndTime = new NET_DVR_TIME_SEARCH_COND(); //搜索的结束时间 + public byte byLockType; // 0xff-全部,0-未锁,1-锁定 + public byte byQuickSearch; // 是否启用快速查询,0-不启用,1-启用(快速查询不会返回文件大小,仅对设备数据库进行查询,避免频繁唤醒硬盘) + public byte[] byRes = new byte[254]; // 保留 + public UNION_EVENT_PARAM_V50 uSeniorParam = new UNION_EVENT_PARAM_V50(); + } + + public static class UNION_EVENT_PARAM_V50 extends Union { + public byte[] byLen = new byte[SEARCH_EVENT_INFO_LEN_V40/*800*/]; + public EVENT_ALARMPARAM_V50 struAlarmParam = new EVENT_ALARMPARAM_V50(); + public EVENT_MOTIONPARAM_V50 struMotionParam = new EVENT_MOTIONPARAM_V50(); + public EVENT_VCAPARAM_V50 struVcaParam = new EVENT_VCAPARAM_V50(); + public EVENT_INQUESTPARAM_V50 struInquestParam = new EVENT_INQUESTPARAM_V50(); + public EVENT_VCADETECTPARAM_V50 struVCADetect = new EVENT_VCADETECTPARAM_V50(); + public EVENT_STREAMIDPARAM_V50 struStreamIDParam = new EVENT_STREAMIDPARAM_V50(); + public EVENT_POSPARAM_V50 struPosAlarm = new EVENT_POSPARAM_V50(); + public EVENT_TRIALPARAM_V50 struTrialParam = new EVENT_TRIALPARAM_V50(); + public EVENT_ACSPARAM_V50 struACSAlarm = new EVENT_ACSPARAM_V50(); + public EVENT_IOTPARAM_V50 struIOTAlarm = new EVENT_IOTPARAM_V50(); + } + + public static class EVENT_ALARMPARAM_V50 extends HIKSDKStructure { + /*报警输入号,按值表示,采用紧凑型排列,0xffff表示后续无效*/ + public short[] wAlarmInNo = new short[128]; + public byte[] byRes = new byte[544]; //保留 + } + + //移动侦测 + public static class EVENT_MOTIONPARAM_V50 extends HIKSDKStructure { + /* 移动侦测通道,按值表示 ,采用紧凑型排列,0xffff表示后续无效*/ + public short[] wMotDetChanNo = new short[MAX_CHANNUM_V30]; + public byte[] byRes = new byte[672]; /*保留*/ + } + + //异常行为检测 + public static class EVENT_VCAPARAM_V50 extends HIKSDKStructure { + //异常行为检测对应的通道,按值表示,采用紧凑型排列,0xffff表示后续无效 + public short[] wChanNo = new short[MAX_CHANNUM_V30]; + public byte byRuleID; //异常行为检测类型,规则0xff表示全部,从0开始 + public byte byDriverBehaviortType; //司机驾驶行为类型:0-保留、1-抽烟、2-接打电话、3-疲劳驾驶、4-分神提醒、5-驾驶员异常、6-未系安全带、7-红外阻断墨镜 + public byte byADASType; //高级辅助驾驶类型:0-保留、1-前向碰撞、2-车道偏离、3-盲区检测、4-车距检测、5-行人防撞、6-急加速、7-急减速、8-急左转弯、9-急右转弯、10-车辆翻车、11-未礼让行人 + public byte byGSensorType; // G-Sensor事件:0-保留、1-急加速、2-急减速、3-急左转弯、4-急右转弯、5-车辆翻车、6-车辆碰撞 + public byte bySensorInType; // Sensor-In行为:0-保留、1-刹车、2-左转、3-右转、4-倒车 + public byte[] byRes = new byte[667]; /*保留*/ + } + + //审讯事件搜索条件 + public static class EVENT_INQUESTPARAM_V50 extends HIKSDKStructure { + public byte byRoomIndex; //审讯室编号,从1开始 + public byte[] byRes = new byte[799]; //保留 + } + + //智能侦测查找条件 ,通道号按值表示 + public static class EVENT_VCADETECTPARAM_V50 extends HIKSDKStructure { + public byte byAll; //查找全部通道,0-否,此时dwChanNo参数有效, + //1-查找全部通道,此时dwChanNo参数无效。 + public byte[] byRes1 = new byte[3]; + public short[] wChanNo = new short[MAX_CHANNUM_V30];// 触发通道号,按值表示,0xffff无效,且后续数据也表示无效值 + public byte[] byRes = new byte[668]; + } + + public static class EVENT_STREAMIDPARAM_V50 extends HIKSDKStructure { + public NET_DVR_STREAM_INFO struIDInfo = new NET_DVR_STREAM_INFO(); // 流id信息,72字节长 + public int dwCmdType; // 外部触发类型,NVR接入云存储使用 + public byte byBackupVolumeNum; //存档卷号,CVR使用 + public byte[] byRes1 = new byte[3]; + public byte[] byArchiveLabel = new byte[64]; //存档标签,CVR使用 + public byte[] byRes = new byte[656]; + } + + //pos录像 + public static class EVENT_POSPARAM_V50 extends HIKSDKStructure { + public short[] wChannel = new short[MAX_CHANNUM_V30]; //通道,按值表示,紧凑型排列,遇到0xffff时表示数组后续值无效 + public byte byAllChan; //是否查找全部通道,0-否,此时wChannel有效,1-全部通道,此时wChannel无效 + public byte byCaseSensitive; //0-不区分大小写, 1-区分大小写 + public byte byCombinateMode; //关键字组合方式,0-或,1-与 + public byte byRes1; //保留 + public byte[] sKeyWord = new byte[MAX_POS_KEYWORDS_NUM * MAX_POS_KEYWORD_LEN]; + //关键字查找时的条件 + public byte[] byRes = new byte[284]; //保留 + } + + public static class EVENT_TRIALPARAM_V50 extends HIKSDKStructure { + public byte[] byCaseNo = new byte[SEARCH_CASE_NO_LEN]; + public byte[] byCaseName = new byte[SEARCH_CASE_NAME_LEN]; + public byte[] byLitigant1 = new byte[SEARCH_LITIGANT_LEN]; + public byte[] byLitigant2 = new byte[SEARCH_LITIGANT_LEN]; + public byte[] byChiefJudge = new byte[SEARCH_CHIEF_JUDGE_LEN]; + public byte byCaseType; + public byte[] byRes = new byte[547]; + } + + //门禁事件搜索条件 + public static class EVENT_ACSPARAM_V50 extends HIKSDKStructure { + public int dwMajor; //报警主类型(与事件上传主类型一致,0代表全部) + public int dwMinor; //报警次类型(与事件上传主类型一致,0代表全部) + public byte[] byCardNo = new byte[ACS_CARD_NO_LEN]; //卡号 + public byte[] byName = new byte[NAME_LEN/*32*/]; //姓名 + public byte[] byMACAddr = new byte[MACADDR_LEN]; //物理MAC地址 + public byte[] byRes = new byte[722]; + } + + //非视频联动事件搜索条件 + public static class EVENT_IOTPARAM_V50 extends HIKSDKStructure { + public short wDeviceType; //设备类型,0-海康门禁主机,1-海康可视对讲设备, 2-海康报警主机(预留) 3-GJD报警主机 4-Luminite报警主机, 5-OPTEX报警主机,6-cameraDetector模拟相机传感器设备 + public short wEventType; //搜索次类型- 根据主类型变化,0xffff表示全部 + public short[] wChannel = new short[MAX_CHANNUM_V30/*64*/]; //通道号,按值表示,紧凑型排列,遇到0xffff时表示数组后续值无效 + public byte byAllChan; //是否查找全部通道,0-否,此时wChannel有效,1-全部通道,此时wChannel无效 + public byte byCaseSensitive; //0-不区分大小写, 1-区分大小写 + public byte byCombinateMode; //关键字组合方式,0-或,1-与 + public byte bySearchType; //搜索方式:0-按视频源搜索(此时通道号为视频通道号) + public byte[] sKeyWord = new byte[MAX_POS_KEYWORDS_NUM * MAX_POS_KEYWORD_LEN];//关键字查找时的条件 + public short wZoneNo; //防区号,仅当设备类型为海康报警主机,次类型为防区(wEventType为1)时有效 + public byte[] byRes = new byte[278]; //保留 + } + + //查找返回结果 + public static class NET_DVR_SEARCH_EVENT_RET extends HIKSDKStructure { + public short wMajorType; //主类型 + public short wMinorType; //次类型 + public NET_DVR_TIME struStartTime = new NET_DVR_TIME(); //事件开始的时间 + public NET_DVR_TIME struEndTime = new NET_DVR_TIME(); //事件停止的时间 + public byte[] byChan = new byte[MAX_CHANNUM_V30]; + public byte[] byChanEx = new byte[32]; //关联通道,按位表示,使用该字段后byChan可以不使用 + public byte[] byRes = new byte[4]; + public UNION_EVENT_RET uSeniorRet = new UNION_EVENT_RET(); + } + + public static class UNION_EVENT_RET extends Union { + public byte[] byLen = new byte[304]; + public EVENT_ALARMSTRET struAlarmRet = new EVENT_ALARMSTRET(); + public EVENT_INQUESTRET struInquestRet = new EVENT_INQUESTRET(); + } + + //报警输入结果 + public static class EVENT_ALARMSTRET extends HIKSDKStructure { + + public int dwAlarmInNo; //报警输入号 + public byte[] byRes = new byte[SEARCH_EVENT_INFO_LEN]; + } + + //审讯事件 + public static class EVENT_INQUESTRET extends HIKSDKStructure { + public byte byRoomIndex; //审讯室编号,从1开始 + public byte byDriveIndex; //刻录机编号,从1开始 + public byte[] byRes1 = new byte[6]; //保留 + public int dwSegmentNo; //本片断在本次审讯中的序号,从1开始 + public short wSegmetSize; //本片断的大小, 单位M + public short wSegmentState; //本片断状态 0 刻录正常,1 刻录异常,2 不刻录审讯 + public byte[] byRes2 = new byte[288]; //保留 + } + + //查找返回结果 + public static class NET_DVR_SEARCH_EVENT_RET_V50 extends HIKSDKStructure { + public short wMajorType; //主类型 + public short wMinorType; //次类型 + public NET_DVR_TIME_SEARCH struStartTime = new NET_DVR_TIME_SEARCH(); //事件开始的时间 + public NET_DVR_TIME_SEARCH struEndTime = new NET_DVR_TIME_SEARCH(); //事件停止的时间,脉冲事件时和开始时间一样 + public NET_DVR_ADDRESS struAddr = new NET_DVR_ADDRESS(); //片段所在的地址信息,集群回放时用到 + public short[] wChan = new short[MAX_CHANNUM_V40/*512*/]; //触发的通道号,0xffff表示后续无效 + public byte[] byRes = new byte[256]; + public UNION_EVENT_RET_V50 uSeniorRet = new UNION_EVENT_RET_V50(); + } + + public static class UNION_EVENT_RET_V50 extends Union { + public byte[] byLen = new byte[800]; + public EVENT_ALARMRET_V50 struAlarmRet = new EVENT_ALARMRET_V50(); + public EVENT_MOTIONRET_V50 struMotionRet = new EVENT_MOTIONRET_V50(); + public EVENT_VCARET_V50 struVcaRet = new EVENT_VCARET_V50(); + public EVENT_INQUESTRET_V50 struInquestRet = new EVENT_INQUESTRET_V50(); + public EVENT_STREAMIDRET_V50 struStreamIDRet = new EVENT_STREAMIDRET_V50(); + public EVENT_POSRET_V50 struPosRet = new EVENT_POSRET_V50(); + public EVENT_TRIALRET_V50 struTrialRet = new EVENT_TRIALRET_V50(); + public EVENT_IOTRET_V50 struIOTRet = new EVENT_IOTRET_V50(); + } + + //报警输入结果 + public static class EVENT_ALARMRET_V50 extends HIKSDKStructure { + public int dwAlarmInNo; //报警输入号 + public byte[] byRes = new byte[796]; + } + + //移动侦测结果 + public static class EVENT_MOTIONRET_V50 extends HIKSDKStructure { + public int dwMotDetNo; //移动侦测通道 + public byte[] byRes = new byte[796]; + } + + //异常行为检测结果 + public static class EVENT_VCARET_V50 extends HIKSDKStructure { + public int dwChanNo; //触发事件的通道号 + public byte byRuleID; //规则ID + public byte[] byRes1 = new byte[3]; //保留 + public byte[] byRuleName = new byte[NAME_LEN]; //规则名称 + public NET_VCA_EVENT_UNION uEvent = new NET_VCA_EVENT_UNION(); //行为事件参数 + public byte[] byRes = new byte[668]; //保留 + } + + //审讯事件 + public static class EVENT_INQUESTRET_V50 extends HIKSDKStructure { + public byte byRoomIndex; //审讯室编号,从1开始 + public byte byDriveIndex; //刻录机编号,从1开始 + public byte[] byRes1 = new byte[6]; //保留 + public int dwSegmentNo; //本片断在本次审讯中的序号,从1开始 + public short wSegmetSize; //本片断的大小, 单位M + public short wSegmentState; //本片断状态 0 刻录正常,1 刻录异常,2 不刻录审讯 + public byte[] byRes2 = new byte[784]; //保留 + } + + //流id录像查询结果 + public static class EVENT_STREAMIDRET_V50 extends HIKSDKStructure { + public int dwRecordType; //录像类型 0-定时录像 1-移动侦测 2-报警录像 3-报警|移动侦测 4-报警&移动侦测 5-命令触发 6-手动录像 7-震动报警 8-环境触发 9-智能报警 10-回传录像 + public int dwRecordLength; //录像大小 + public byte byLockFlag; // 锁定标志 0:没锁定 1:锁定 + public byte byDrawFrameType; // 0:非抽帧录像 1:抽帧录像 + public byte byPosition;// 文件所在存储位置:0-阵列上,1-带库机位上,可以直接下载,2-磁带库内,需要把磁盘切换到机位上,3-不在磁带库中,需要把磁盘插到磁带库中 + public byte byRes1; + public byte[] byFileName = new byte[NAME_LEN]; //文件名 + public int dwFileIndex; // 存档卷上的文件索引 + public byte[] byTapeIndex = new byte[NET_SDK_MAX_TAPE_INDEX_LEN]; //文件所在磁带编号 + public byte[] byFileNameEx = new byte[NET_SDK_MAX_FILE_LEN/*256*/]; //文件名扩展 + public byte[] byRes = new byte[464]; + } + + //POS录像查询结果 + public static class EVENT_POSRET_V50 extends HIKSDKStructure { + public int dwChanNo; //触发产生pos事件的通道 + public byte[] byRes = new byte[796]; + } + + public static class EVENT_TRIALRET_V50 extends HIKSDKStructure { + public byte byRoomIndex; //审讯室编号,从1开始 + public byte byDriveIndex; //刻录机编号,从1开始 + public short wSegmetSize; //本片断的大小, 单位M + public int dwSegmentNo; //本片断在本次审讯中的序号,从1开始 + public byte bySegmentState; //本片断状态,0-刻录正常,1-刻录异常,2-不刻录审讯 + public byte byCaseType; //案件类型;0-全部、1-刑事案件、2-民事案件 + public byte[] byRes = new byte[2]; + public byte[] byCaseNo = new byte[CASE_NO_RET_LEN]; //案件编号 + public byte[] byCaseName = new byte[CASE_NAME_RET_LEN]; //案件名称; + public byte[] byLitigant1 = new byte[LITIGANT_RET_LEN]; //当事人1; + public byte[] byLitigant2 = new byte[LITIGANT_RET_LEN]; //当事人2; + public byte[] byChiefJudge = new byte[CHIEF_JUDGE_RET_LEN];//审判长 + public byte[] byRes1 = new byte[600]; + } + + //非视频通道查询结果 + public static class EVENT_IOTRET_V50 extends HIKSDKStructure { + public int dwChanNo; //触发产生事件的通道号(事件源通道) + public byte[] byRes = new byte[796]; + } + + public static class NET_DVR_INQUEST_RESUME_SEGMENT extends HIKSDKStructure { + public NET_DVR_TIME struStartTime = new NET_DVR_TIME(); //事件起始时间 + public NET_DVR_TIME struStopTime = new NET_DVR_TIME(); //事件终止时间 + public byte byRoomIndex; //审讯室编号,从1开始 + public byte byDriveIndex; //刻录机编号,从1开始 + public short wSegmetSize; //本片断的大小, 单位M + public int dwSegmentNo; //本片断在本次审讯中的序号,从1开始 + public byte[] byRes = new byte[24]; //保留 + } + + public static class NET_DVR_INQUEST_RESUME_EVENT extends HIKSDKStructure { + public int dwResumeNum; //需恢复的事件个数 + public NET_DVR_INQUEST_RESUME_SEGMENT[] struResumeSegment = new NET_DVR_INQUEST_RESUME_SEGMENT[MAX_RESUME_SEGMENT]; + public byte byResumeMode; //恢复模式,0-单光盘恢复,1-双光盘恢复 + public byte[] byRes = new byte[199]; //保留 + } + + //报警信息查询条件结构体 + public static class NET_DVR_ALARM_SEARCH_COND extends HIKSDKStructure { + public int dwSize; + public NET_DVR_TIME_SEARCH_COND strStartTime; //开始时间,时间为空则代表不通过时间筛选。 + public NET_DVR_TIME_SEARCH_COND strStopTime; //结束时间, 时间为空则代表不通过时间筛选。 + /* + 报警命令,该字段值与报警布防类型相同,目前支持: + COMM_VCA_ALARM 0x4993 智能检测报警 + COMM_UPLOAD_FACESNAP_RESULT 0x1112 特征识别结果上传 + COMM_SNAP_MATCH_ALAR 0x2902 人脸比对结果上传 + */ + public int dwAlarmComm; //若该命令为空这代表不进行报警命令过滤。 + public byte[] sAlarmUID = new byte[64]; //UID标识(上传报警时设备返回的UID标识,64字节的长度,可以使用时间(精确到毫秒)加上随即数的方式组成),为空则代表不区分UID + public byte[] byRes = new byte[128]; + } + + //报警信息查询结果结构体 + public static class NET_DVR_ALARM_SEARCH_RESULT extends HIKSDKStructure { + public int dwSize; + /* + 报警命令,该字段值与报警布防类型相同,目前支持: + COMM_VCA_ALARM 0x4993 智能检测报警 + COMM_UPLOAD_FACESNAP_RESULT 0x1112 特征识别结果上传 + COMM_SNAP_MATCH_ALARM 0x2902 人脸比对结果上传 + */ + public int dwAlarmComm; + /* + 报警信息,该字段值与报警信息相同,目前支持: + 当COMM_VCA_ALARM时,该报警信息为JSON报文 + 当COMM_UPLOAD_FACESNAP_RESULT时,该报警信息为NET_VCA_FACESNAP_RESULT + 当COMM_SNAP_MATCH_ALARM—¶,该报警信息为NET_VCA_FACESNAP_MATCH_ALARM + */ + public int dwAlarmLen;//报警信息,即pAlarmInfo指针指向的数据长度 + public Pointer pAlarmInfo; + public NET_DVR_ALARMER struAlarmer = new NET_DVR_ALARMER(); + public byte[] byRes = new byte[128]; + } + + public static class NET_DVR_ALARM_ISAPI_INFO extends HIKSDKStructure { + public Pointer pAlarmData; // 报警数据(参见下表) + public int dwAlarmDataLen; // 报警数据长度 + public byte byDataType; // 0-invalid,1-xml,2-json + public byte byPicturesNumber; // 图片数量 + public byte[] byRes = new byte[2]; + public Pointer pPicPackData; // 图片变长部分 + //(byPicturesNumber个{NET_DVR_ALARM_ISAPI_PICDATA};) + public byte[] byRes1 = new byte[32]; + } + + public static class NET_DVR_LOCAL_GENERAL_CFG extends HIKSDKStructure { + public byte byExceptionCbDirectly; //0-通过线程池异常回调,1-直接异常回调给上层 + public byte byNotSplitRecordFile; //回放和预览中保存到本地录像文件不切片 0-默认切片,1-不切片 + public byte byResumeUpgradeEnable; //断网续传升级使能,0-关闭(默认),1-开启 + public byte byAlarmJsonPictureSeparate; //控制JSON透传报警数据和图片是否分离,0-不分离,1-分离(分离后走COMM_ISAPI_ALARM回调返回) + public byte[] byRes = new byte[4]; //保留 + public long i64FileSize; //单位:Byte + public int dwResumeUpgradeTimeout; //断网续传重连超时时间,单位毫秒 + public byte[] byRes1 = new byte[236]; //预留 + + } + + public static class NET_DVR_LOCAL_TCP_PORT_BIND_CFG extends HIKSDKStructure { + public short wLocalBindTcpMinPort; //本地绑定Tcp最小端口 + public short wLocalBindTcpMaxPort; //本地绑定Tcp最大端口 + public byte[] byRes = new byte[60]; //保留 + } + + + public static class NET_DVR_LOCAL_CHECK_DEV extends HIKSDKStructure { + public int dwCheckOnlineTimeout; //巡检时间间隔,单位ms 最小值为30s,最大值120s。为0时,表示用默认值(120s) + public int dwCheckOnlineNetFailMax; //由于网络原因失败的最大累加次数;超过该值SDK才回调用户异常,为0时,表示使用默认值1 + public byte[] byRes = new byte[256]; + @Override + protected List getFieldOrder() { + return Arrays.asList( + "dwCheckOnlineTimeout", + "dwCheckOnlineNetFailMax", + "byRes" + ); + } + } + + public static final int MAX_FILE_PATH_LEN = 256; //文件路径长度 + + public static class NET_DVR_ALARM_ISAPI_PICDATA extends HIKSDKStructure { + public int dwPicLen; + public byte byPicType; //图片格式: 1- jpg + public byte[] byRes = new byte[3]; + public byte[] szFilename = new byte[MAX_FILE_PATH_LEN]; + public Pointer pPicData; // 图片数据 + } + + public static class NET_DVR_FOCUSMODE_CFG extends HIKSDKStructure { + public int dwSize; + public byte byFocusMode; /* 聚焦模式,0-自动,1-手动,2-半自动 */ + public byte byAutoFocusMode; /* 自动聚焦模式,0-关,1-模式A,2-模式B,3-模式AB,4-模式C 自动聚焦模式,需要在聚焦模式为自动时才显示*/ + public short wMinFocusDistance; /* 最小聚焦距离,单位CM, 0-自动,0xffff-无穷远 */ + public byte byZoomSpeedLevel; /* 变倍速度,为实际取值,1-3 */ + public byte byFocusSpeedLevel; /* 聚焦速度,为实际取值,1-3 */ + public byte byOpticalZoom; /* 光学变倍,0-255 */ + public byte byDigtitalZoom; /* 数字变倍,0-255 */ + public float fOpticalZoomLevel; /* 光学变倍(倍率值) [1,32], 最小间隔0.5 ,内部设备交互的时候*1000 */ + public int dwFocusPos;/* dwFocusPos 是focus值(聚焦值),范围为[0x1000,0xC000],这个值是sony坐标值,使用这个值是为了对外统一,保证不同的镜头对外focus值都转换在这个范围内 (手动聚焦模式下下应用)*/ + public byte byFocusDefinitionDisplay;// 聚焦清晰度显示,0~不显示,1~显示, 开启会在码流上显示当前镜头目标的清晰度值,用于帮助客户调焦使相机抓拍能够达到最清晰的效果,该清晰度越大代表着越清晰,清晰度范围为:0~100.0000 + public byte byFocusSensitivity; //聚焦灵敏度,范围[0,2],聚焦模式为自动、半自动时生效 + public byte[] byRes1 = new byte[2]; + public int dwRelativeFocusPos;//相对focus值,其低16位表示聚焦值,0~4000;高16位代表当前聚焦值获取时的温度值 + public byte[] byRes = new byte[48]; + } + + public static class NET_DVR_SERIALSTART_V40 extends HIKSDKStructure { + public int dwSize; //结构体大小 + public int dwSerialType; //串口号(1-232串口,2-485串口) + public byte bySerialNum; //串口编号 + public byte[] byRes = new byte[255]; + + + } + + public static class NET_DVR_PRESET_NAME extends HIKSDKStructure { + public int dwSize; + public short wPresetNum; //预置点编号 + public byte[] byRes1 = new byte[2]; //字节对齐 + public byte[] byName = new byte[NAME_LEN]; + public short wPanPos; //水平参数 如果获取到的数据大于360默认减去360 + public short wTiltPos; //垂直参数 如果获取到的数据大于360默认减去360 + public short wZoomPos; //变倍参数如果获取到的数据大于360默认减去360 + public byte[] byRes = new byte[58]; + } + + //Sensor信息 + public static class NET_DVR_SENSOR_PARAM extends HIKSDKStructure { + public byte bySensorType;//SensorType:0-CCD,1-CMOS + public byte[] byRes = new byte[31]; + public float fHorWidth;//水平宽度 精确到小数点后两位 *10000 + public float fVerWidth;//垂直宽度 精确到小数点后两位 *10000 + public float fFold;//zoom=1没变时的焦距 精确到小数点后两位 *100 + } + + //球机位置信息 + public static class NET_DVR_PTZPOS_PARAM extends HIKSDKStructure { + public float fPanPos;//水平参数,精确到小数点后1位 + public float fTiltPos;//垂直参数,精确到小数点后1位 + public float fZoomPos;//变倍参数,精确到小数点后1位 + public byte[] byRes = new byte[16]; + } + + public static class NET_DVR_LLI_PARAM extends HIKSDKStructure { + public float fSec;//秒[0.000000,60.000000] + public byte byDegree;//度:纬度[0,90] 经度[0,180] + public byte byMinute;//分[0,59] + public byte[] byRes = new byte[6]; + } + + //GIS信息上传 + public static class NET_DVR_GIS_UPLOADINFO extends HIKSDKStructure { + public int dwSize;//结构体大小 + public int dwRelativeTime; //相对时标 + public int dwAbsTime; //绝对时标 + public NET_VCA_DEV_INFO struDevInfo = new NET_VCA_DEV_INFO();//前端设备 + public float fAzimuth;//电子罗盘的方位信息;方位角[0.00°,360.00°) + public byte byLatitudeType;//纬度类型,0-北纬,1-南纬 + public byte byLongitudeType;// 经度类型,0-东度,1-西度 + public byte[] byRes1 = new byte[2]; + public NET_DVR_LLI_PARAM struLatitude = new NET_DVR_LLI_PARAM(); /*纬度*/ + public NET_DVR_LLI_PARAM struLongitude = new NET_DVR_LLI_PARAM(); /*经度*/ + public float fHorizontalValue;//水平视场角,精确到小数点后面两位 + public float fVerticalValue;//垂直视场角,精确到小数点后面两位 + public float fVisibleRadius;//当前可视半径,精确到小数点后面两位 + public float fMaxViewRadius;//最大可视半径,精确到小数点后面0位(预留处理) + public NET_DVR_SENSOR_PARAM struSensorParam;//Sensor信息 + public NET_DVR_PTZPOS_PARAM struPtzPos; //ptz坐标 + public byte[] byRes = new byte[256]; + } + + public static class NET_DVR_DAYTIME extends HIKSDKStructure { + public byte byHour;//0~24 + public byte byMinute;//0~60 + public byte bySecond;//0~60 + public byte byRes; + public short wMilliSecond; //0~1000 + public byte[] byRes1 = new byte[2]; + } + + public static class NET_DVR_SCHEDULE_DAYTIME extends HIKSDKStructure { + public NET_DVR_DAYTIME struStartTime; //开始时间 + public NET_DVR_DAYTIME struStopTime; //结束时间 + } + + public static class NET_DVR_BUILTIN_SUPPLEMENTLIGHT extends HIKSDKStructure { + public int dwSize;//结构体大小 + public byte byMode;//补光灯模式 0-定时,1-开启,2-关闭,3-自动(非光敏,算法画面识别) + public byte byBrightnessLimit;//亮度限制[0,100] + public byte bySupplementLightMode;//补光灯类型,0~白光模式,1~混合模式 + public byte byMixedLightRegulatMode;//混合补光灯亮度调节模式,0~自动,1~手动,当bySupplementLightMode = 1时生效 + public byte byLrLightBrightness;//红外亮度控制[0,100],当byMixedLightRegulatMode = 1时生效。 + public byte byHighLrLightBrightness;// 远光红外光亮度配置[0,100],当byMixedLightRegulatMode = 1时生效 + public byte byHighBrightnessLimit;// 远光白光亮度配置[0,100],当byMixedLightRegulatMode = 1时生效 + public byte byLowLrLightBrightness;// 近光红外光亮度配置[0,100],当byMixedLightRegulatMode = 1时生效 + public NET_DVR_SCHEDULE_DAYTIME struSchedTime;//定时时间段 + public byte byLowBrightnessLimit;//近光白光亮度配置[0,100],当byMixedLightRegulatMode = 1时生效 + public byte byWhiteLightBrightness;// 白光灯亮度 + public byte[] byRes1 = new byte[254]; + } + + public static class NET_DVR_HANDLEEXCEPTION_V41 extends HIKSDKStructure { + public int dwHandleType; //异常处理,异常处理方式的"或"结果 + /*0x00: 无响应*/ + /*0x01: 布防器上警告*/ + /*0x02: 声音警告*/ + /*0x04: 上传中心*/ + /*0x08: 触发报警输出*/ + /*0x10: 触发JPRG抓图并上传Email*/ + /*0x20: 无线声光报警器联动*/ + /*0x40: 联动电子地图(目前只有PCNVR支持)*/ + /*0x200: 抓图并上传FTP*/ + /*0x400: 虚交侦测 联动 聚焦模式(提供可配置项,原先设备自动完成)IPC5.1.0*/ + /*0x800: PTZ(球机目标)*/ + /*0x4000:白光灯报警*/ + /*0x10000:短信报警*/ + public int dwMaxRelAlarmOutChanNum; //触发的报警输出通道数(只读)最大支持数 + public int[] dwRelAlarmOut = new int[MAX_ALARMOUT_V40]; //触发报警通道 + public byte[] byRes = new byte[64]; //保留 + } + + public static class NET_DVR_PRESETCHAN_INFO extends HIKSDKStructure { + public int dwEnablePresetChan; /*启用预置点的通道, 0xfffffff表示不调用预置点*/ + public int dwPresetPointNo; /*调用预置点通道对应的预置点序号, 0xfffffff表示不调用预置点。*/ + } + + public static class NET_DVR_CRUISECHAN_INFO extends HIKSDKStructure { + public int dwEnableCruiseChan; /*启用巡航的通道*/ + public int dwCruiseNo; /*巡航通道对应的巡航编号, 0xfffffff表示无效*/ + } + + public static class NET_DVR_PTZTRACKCHAN_INFO extends HIKSDKStructure { + public int dwEnablePtzTrackChan; /*启用云台的通道*/ + public int dwPtzTrackNo; /*云台通道对应的编号, 0xfffffff表示无效*/ + } + + public static class NET_DVR_EVENT_TRIGGER extends HIKSDKStructure { + public int dwSize;//结构体大小 + public NET_DVR_HANDLEEXCEPTION_V41 struHandleException; //异常处理方式 + public int[] dwRelRecordChan = new int[MAX_CHANNUM_V40]; //实际触发录像通道,按值表示,采用紧凑型排列,从下标0开始顺序读取,中间遇到0xffffffff则后续无效。 + public NET_DVR_PRESETCHAN_INFO[] struPresetChanInfo = new NET_DVR_PRESETCHAN_INFO[MAX_CHANNUM_V40]; //启用的预置点信息 + public NET_DVR_CRUISECHAN_INFO[] struCruiseChanInfo = new NET_DVR_CRUISECHAN_INFO[MAX_CHANNUM_V40]; //启用巡航功能通道的信息 + public NET_DVR_PTZTRACKCHAN_INFO[] struPtzTrackInfo = new NET_DVR_PTZTRACKCHAN_INFO[MAX_CHANNUM_V40]; //调用云台的通道信息 + public byte byDirection;//触发方向:0-保留;1-全部;2-正向;3-反向 + public byte[] byRes2 = new byte[255]; + } + + public static class NET_DVR_FACELIB_GUARD_COND extends HIKSDKStructure { + public int dwSize; + public int dwChannel; //通道号 + public byte[] szFDID = new byte[68];//人脸库的ID + public byte[] byRes = new byte[128]; + } + + //导入人脸数据条件 + public static class NET_DVR_FACELIB_COND extends HIKSDKStructure { + public int dwSize; + public byte[] szFDID = new byte[NET_SDK_MAX_FDID_LEN/*256*/];//人脸库ID + public byte byConcurrent;//设备并发处理 0-不开启,1-开始 + public byte byCover;//是否覆盖式导入 0-否,1-是 + public byte byCustomFaceLibID;//FDID是否是自定义,0-不是,1-是; + public byte byPictureSaveMode;//上传原图保存模式,0-保存,1-不保存; + public byte[] byIdentityKey = new byte[NET_SDK_MAX_INDENTITY_KEY_LEN/*64*/];//交互操作口令 + public byte[] byRes = new byte[60]; + } + + public static class NET_DVR_SEND_PARAM_IN extends HIKSDKStructure { + public Pointer pSendData; //发送的缓冲区,PicURL == 1 的时候,内存中存储的是 URL 字符串,byUploadModeling == 1 的时候,内存中存储的是 建模base64加密数据 + public int dwSendDataLen; //发送数据长度,PicURL == 1 的时候,表示的 URL 字符串的长度,byUploadModeling == 1 的时候,表示为建模数据base64后的加密长度 + public NET_DVR_TIME_V30 struTime = new NET_DVR_TIME_V30(); //图片时间 + public byte byPicType; //图片格式,1-jpg,2-bmp,3-png,4-SWF,5-GIF + public byte byPicURL; //图片数据采用URL方式 0-二进制图片数据,1-图片数据走URL方式 + /*是否上传建模数据; + 0- 二进制图片数据方式(pSendData指向二进制图片数据, dwPicDataLen为图片二进制数据长度), + 1- 直接上传建模数据(pSendData指向建模base64加密数据, dwPicDataLen为建模数据base64后的加密长度)。 + 注:建模数据采用base64加密方式,选择为建模数据上传后,byPicURL 无需。 + 当”/ISAPI/Intelligent/channels//faceContrast/capabilities”能力中返回isSupportUploadModeling能力节点时,支持上传建模数据. */ + public byte byUploadModeling; + public byte byRes1; + public int dwPicMangeNo; //图片管理号 + public byte[] sPicName = new byte[NAME_LEN]; //图片名称 + public int dwPicDisplayTime; //图片播放时长,单位秒 + public Pointer pSendAppendData; //发送图片的附加信息缓冲区,对应FaceAppendData 的XML描述; + public int dwSendAppendDataLen; //发送图片的附加信息数据长度 FaceAppendData XML的长度; + public byte[] byRes = new byte[192]; + } + + public static class NET_DVR_INQUEST_ROOM extends HIKSDKStructure { + public byte byRoomIndex; //审讯室编号 + public byte byFileType; //0-审讯文件,1-开庭上传文件 + public byte[] byRes = new byte[22]; //保留 + } + + public static class NET_DVR_INQUEST_CDRW_CFG extends HIKSDKStructure { + public int dwSize; + public int dwNum; //刻录机的数量 + public int[] dwRwSelectPara = new int[MAX_CHANNUM_V30];// 是否选中该光驱 + public int dwModeSelect; //0表示循环刻录模式 1表示并行刻录模式(默认模式) + public byte[] byRes = new byte[24]; //保留 + public int dwStartCDRW; //DVR 本地已经开始刻录 + public int dwHdExcp; //硬盘有异 常 + public int dwInterval; //时间间隔,10分钟(0)、20分钟(1)、30分钟(2) + public byte[] sLable = new byte[64]; //光盘名称 + } + + public static class NET_DVR_INQUEST_CDRW_STATUS extends HIKSDKStructure { + /*运行状态:0-审讯开始, + 1-审讯过程中刻录,2-审讯停止, + 3-刻录审讯文件, + 4-备份(事后备份和本地备份) + 5-空闲 + 6-初始化硬盘 + 7-恢复审讯*/ + public int dwType; + public NET_DVR_INQUEST_CDRW[] strCDRWNum = new NET_DVR_INQUEST_CDRW[MAX_INQUEST_CDRW_NUM]; //数组0表示刻录机1 + public NET_DVR_TIME_EX struInquestStartTime = new NET_DVR_TIME_EX(); //审讯开始的时间点 + public byte[] byRes = new byte[16]; //保留 + } + + public static class NET_DVR_INQUEST_CDRW extends HIKSDKStructure { + public int dwEnable; //刻录机状态是否有效,0-无效,1-有效 + public int dwStatus; /*当dwType=0时, 0-光盘正常,1-无光盘或光盘异常, + 当dwType=1或2时,0-刻录正常,1-无光盘或光盘异常,2-光盘已封盘(81不支持),3-光盘空间不足, 4-异常导致审讯终止(81不支持) + 当dwType=3时, 0-刻录正常,1-无光盘或光盘异常,2-光盘已封盘(81不支持),3-光盘空间不足 + 当dwType=4时,0-刻录正常,1-无光盘或光盘异常,2-光盘已封盘(81不支持),3-光盘空间不足 + 当dwType=5时,0-光盘正常, 1-无光盘或光盘异常,2-光盘已封盘(81不支持) + 当dwType=6或7时, 0-刻录正常, 1-无光盘或光盘异常, 2-光盘已封盘(81不支持), 3-光盘空间不足*/ + public int dwVolumn; //光盘容量,单位M + public int dwFreeSpace; //光盘剩余容量,单位M + public int dwTimeLeft; // 光盘剩余时间,单位秒 + public byte byCDType; // 光盘类型 + public byte[] byRes = new byte[3]; //保留字节 + } + + //实时温度检测条件参数 + public static class NET_DVR_REALTIME_THERMOMETRY_COND extends HIKSDKStructure { + public int dwSize; /*结构体大小*/ + public int dwChan; /*通道号,从1开始,0xffffffff代表获取全部通道*/ + public byte byRuleID;/*规则ID,0代表获取全部规则,具体规则ID从1开始*/ + public byte byMode; //长连接模式:0- 保留(兼容不支持该功能的老设备),1- 定时模式,2- 温差模式 + public short wInterval; //上传间隔(仅温差模式支持),取值范围:1-3600 秒,填0则默认3600S上传一次 + public byte[] byRes2 = new byte[60]; + } + + //点测温实时信息 + public static class NET_DVR_POINT_THERM_CFG extends HIKSDKStructure { + public float fTemperature; + public NET_VCA_POINT struPoint; + public byte[] byRes = new byte[120]; + } + + //框/线测温实时信息 + public static class NET_DVR_LINEPOLYGON_THERM_CFG extends HIKSDKStructure { + public float fMaxTemperature; + public float fMinTemperature; + public float fAverageTemperature; + public float fTemperatureDiff; + public NET_VCA_POLYGON struRegion; + public byte[] byRes = new byte[32]; + } + + //实时温度信息 + public static class NET_DVR_THERMOMETRY_UPLOAD extends HIKSDKStructure { + public int dwSize; /* 结构体大小 */ + public int dwRelativeTime; + public int dwAbsTime; + public byte[] szRuleName = new byte[NAME_LEN]; + public byte byRuleID;/* 规则ID,0代表获取全部规则,具体规则ID从1开始 */ + public byte byRuleCalibType; + public short wPresetNo; + public NET_DVR_POINT_THERM_CFG struPointThermCfg; + public NET_DVR_LINEPOLYGON_THERM_CFG struLinePolygonThermCfg; + public byte byThermometryUnit; + public byte byDataType; + public byte byRes1; + public byte bySpecialPointThermType; + public float fCenterPointTemperature; + public float fHighestPointTemperature; + public float fLowestPointTemperature; + public NET_VCA_POINT struHighestPoint; + public NET_VCA_POINT struLowestPoint; + public byte byIsFreezedata; + public byte[] byRes = new byte[95]; + } + + public static class NET_PTZ_INFO extends HIKSDKStructure { + public float fPan; + public float fTilt; + public float fZoom; + public int dwFocus;// 聚焦参数,聚焦范围:归一化0-100000 + public byte[] byRes = new byte[4]; + } + + //测温模式配置 + public static class NET_DVR_THERMOMETRY_MODE extends HIKSDKStructure { + public int dwSize;//结构体大小 + public byte byMode;//测温模式,0~普通模式,1~专家模式 + public byte byThermometryROIEnabled; //测温ROI使能 0-保留 1-不开启 2-开启(基于互斥兼容考虑) + public byte[] byRes = new byte[62]; + } + + public static class NET_DVR_THERMOMETRY_COND extends HIKSDKStructure { + public int dwSize;//结构体大小 + public int dwChannel; + public short wPresetNo;//0-保留 + public byte[] byRes = new byte[62]; + } + + public static class NET_DVR_THERMOMETRY_PRESETINFO_PARAM extends HIKSDKStructure { + public byte byEnabled; //是否使能:0- 否,1- 是 + public byte byRuleID;//规则ID 0-表示无效,从1开始 (list内部判断数据有效性) + public short wDistance;//距离(m)[0, 10000] + public float fEmissivity;//发射率(发射率 精确到小数点后两位)[0.01, 1.00](即:物体向外辐射能量的本领) + public byte byDistanceUnit;//距离单位: 0-米(m),1-英尺(feet),2-厘米(centimeter) + public byte[] byRes = new byte[2]; + public byte byReflectiveEnabled;//反射温度使能:0- 否,1- 是 + public float fReflectiveTemperature;//反射温度 精确到小数后2位 + public byte[] szRuleName = new byte[NAME_LEN/*32*/];//规则名称 + public byte byemissivityMode; //发射率配置类型 1-粗糙,2-较粗糙,3-较光滑, 4-光滑, 0xff-自定义 + public byte[] byRes1 = new byte[62]; + public byte byRuleCalibType;//规则标定类型 0-点,1-框,2-线 + public NET_VCA_POINT struPoint = new NET_VCA_POINT();//点测温坐标(当规则标定类型为"点"的时候生效) + public NET_VCA_POLYGON struRegion = new NET_VCA_POLYGON();//区域、线(当规则标定类型为"框"或者"线"的时候生效) + } + + public static class NET_DVR_THERMOMETRY_PRESETINFO extends HIKSDKStructure { + public int dwSize;//结构体大小 + public short wPresetNo;//0-保留 + public byte[] byRes = new byte[2]; + public NET_DVR_THERMOMETRY_PRESETINFO_PARAM[] struPresetInfo = new NET_DVR_THERMOMETRY_PRESETINFO_PARAM[40]; + } + + //温度报警(检测温度和配置温度比较报警) + public static class NET_DVR_THERMOMETRY_ALARM extends HIKSDKStructure { + public int dwSize; + public int dwChannel;//通道号 + public byte byRuleID;//规则ID + public byte byThermometryUnit;//测温单位: 0-摄氏度(℃),1-华氏度(℉),2-开尔文(K) + public short wPresetNo; //预置点号 + public NET_PTZ_INFO struPtzInfo = new NET_PTZ_INFO();//ptz坐标信息 + public byte byAlarmLevel;//0-预警 1-报警 + public byte byAlarmType;/*报警类型 0-最高温度 1-最低温度 2-平均温度 3-温差 4-温度突升 5-温度突降*/ + public byte byAlarmRule;//0-大于,1-小于 + public byte byRuleCalibType;//规则标定类型 0-点,1-框,2线 + public NET_VCA_POINT struPoint = new NET_VCA_POINT();//点测温坐标(当规则标定类型为点的时候生效) + public NET_VCA_POLYGON struRegion = new NET_VCA_POLYGON();//区域(当规则标定类型为框的时候生效) + public float fRuleTemperature;/*配置规则温度,精确到小数点后一位(-40-1000),(浮点数+100) */ + public float fCurrTemperature;/*当前温度,精确到小数点后一位(-40-1000),(浮点数+100) */ + public int dwPicLen;//可见光图片长度 + public int dwThermalPicLen;//热成像图片长度 + public int dwThermalInfoLen;//热成像附加信息长度 + public Pointer pPicBuff; ///可见光图片指针 + public Pointer pThermalPicBuff;// 热成像图片指针 + public Pointer pThermalInfoBuff; //热成像附加信息指针 + public NET_VCA_POINT struHighestPoint = new NET_VCA_POINT();//线、框测温最高温度位置坐标(当规则标定类型为线、框的时候生效) + public float fToleranceTemperature;/* 容差温度,精确到小数点后一位(-40-1000),(浮点数+100) */ + public int dwAlertFilteringTime;//温度预警等待时间 单位秒 范围为0-200秒,默认为0秒 + public int dwAlarmFilteringTime;//温度报警等待时间 单位秒 范围为0-200秒,默认为0秒 + public int dwTemperatureSuddenChangeCycle;//温度突变记录周期,单位秒 + public float fTemperatureSuddenChangeValue;//温度突变值,精确到小数点后一位(大于0) + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public byte[] byRes = new byte[39]; + } + + //温差报警 + public static class NET_DVR_THERMOMETRY_DIFF_ALARM extends HIKSDKStructure { + public int dwSize; + public int dwChannel;//通道号 + public byte byAlarmID1;//规则AlarmID1 + public byte byAlarmID2;//规则AlarmID2 + public short wPresetNo; //预置点号 + public byte byAlarmLevel;//0-预警 1-报警 + public byte byAlarmType;/*报警类型 0-最高温度 1-最低温度 2-平均温度*/ + public byte byAlarmRule;//0-大于,1-小于 + public byte byRuleCalibType;//规则标定类型 0-点,1-框,2线 + public NET_VCA_POINT[] struPoint = (NET_VCA_POINT[]) new NET_VCA_POINT().toArray(2);//点测温坐标(当规则标定类型为点的时候生效)数组下标0代表着AlarmID1,数组下标1代表着AlarmID2. + public NET_VCA_POLYGON[] struRegion = (NET_VCA_POLYGON[]) new NET_VCA_POLYGON().toArray(2);//区域(当规则标定类型为框的时候生效)数组下标0代表着AlarmID1,数组下标1代表着AlarmID2. + public float fRuleTemperatureDiff;/*配置规则温差,精确到小数点后一位(-40-1000))*/ + public float fCurTemperatureDiff;/*当前温差,精确到小数点后一位(-40-1000),(浮点数+100) */ + public NET_PTZ_INFO struPtzInfo;//ptz坐标信息 + public int dwPicLen;//可见光图片长度 + public int dwThermalPicLen;//热成像图片长度 + public int dwThermalInfoLen;//热成像附加信息长度 + public Pointer pPicBuff; ///可见光图片指针 + public Pointer pThermalPicBuff;// 热成像图片指针 + public Pointer pThermalInfoBuff; //热成像附加信息指针 + public byte byThermometryUnit;//测温单位: 0-摄氏度(℃),1-华氏度(℉),2-开尔文(K) + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public byte[] byRes1 = new byte[2]; + public float fToleranceTemperature;/*容差温度,精确到小数点后一位(-40-1000),(浮点数+100) */ + public int dwAlarmFilteringTime;//温度报警等待时间 单位秒 范围为0-200秒,默认为0秒 + public int dwVisibleChannel; //可见光通道通道号 + public byte[] byRes = new byte[48]; + } + + //船只检测报警上传 + public static class NET_DVR_SHIPSDETECTION_ALARM extends HIKSDKStructure { + public int dwSize; + public NET_VCA_DEV_INFO struDevInfo; //设备信息 + public int dwRelativeTime; //相对时标 + public int dwAbsTime; //绝对时标 + public byte byShipsNum; //船只数;(正跨越检测线的船只数) + public byte byShipsNumHead;//船只数;(船头检测船只数) + public byte byShipsNumEnd; //船只数;(船尾检测船只数) + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public NET_DVR_SHIPSINFO[] struShipInfo = (NET_DVR_SHIPSINFO[]) new NET_DVR_SHIPSINFO().toArray(MAX_SHIPS_NUM); /*20*///船只信息;最大支持20艘 + public int dwPicLen;//可见光图片长度 + public int dwThermalPicLen;//热成像图片长度 + public Pointer pPicBuffer; //可见光图片数据指针 + public Pointer pThermalPicBuffer; //热成像图片数据指针 + public short wDevInfoIvmsChannelEx; //与NET_VCA_DEV_INFO里的byIvmsChannel含义相同,能表示更大的值。老客户端用byIvmsChannel能继续兼容,但是最大到255。新客户端版本请使用wDevInfoIvmsChannelEx。 + public byte byTimeDiffFlag; /*时差字段是否有效 0-时差无效, 1-时差有效 */ + public byte cTimeDifferenceH; /*与UTC的时差(小时),-12 ... +14, +表示东区,,byTimeDiffFlag为1时有效*/ + public byte cTimeDifferenceM; /*与UTC的时差(分钟),-30, 30, 45, +表示东区,byTimeDiffFlag为1时有效*/ + public byte bySID;//场景ID + public byte[] byRes1 = new byte[2]; + public byte[] szSceneName = new byte[NAME_LEN];//场景名称,不超过32字符 + public byte[] byRes = new byte[216]; + } + + public static final int MAX_SHIPS_NUM = 20; //船只检测最大船只数 + + //船只信息 + public static class NET_DVR_SHIPSINFO extends HIKSDKStructure { + public float fShipsLength; //船只长度;1~1000.0m,精确到小数点后一位 + public float fShipsHeight; //船只高度;1~1000.0m,精确到小数点后一位 + public float fShipsWidth; //船只宽度;1~1000.0m,精确到小数点后一位 + public float fShipsSpeed; //船只速度;1~1000.0m/s,精确到小数点后一位 + public byte byShipsDirection;//船只方向;0~up,1~down,2~left,3~right + public byte byShipsDetState;//船只检测状态;0~正跨越检测线,1~船头检测,2~船尾检测 + public byte byTriggerLineID;//检测线ID + public byte[] byRes = new byte[61]; + public NET_VCA_POLYGON struShipsRect; //船只区域,归一化值,相对于大图(可见光图、热成像图)的分辨率 + } + + public static class NET_DVR_ARRAY_LIST extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public int dwCount; // 阵列个数 + public NET_DVR_ARRAY_INFO[] struArrayInfo = new NET_DVR_ARRAY_INFO[SUPPORT_ARRAY_NUM]; + } + + public static class NET_DVR_BGA_INFO extends HIKSDKStructure { + public byte byBga; // 后台任务及类型 + public byte byBgaState; /*函数返回值--后台任务状态*/ + public short wBgaPercentage; /*函数返回值--后台任务执行百分比*/ + public byte[] byRes = new byte[4]; // 保留字节 + } + + // 阵列信息 + public static class NET_DVR_ARRAY_INFO extends HIKSDKStructure { + public short wArrayID; // 阵列ID + public byte byRaidMode; // raid模式 参照RAID_MODE + public byte byStatus; // 0-在线 1-磁盘丢失 2-下线 3-降级 4-异常 5-次正常 6-外来盘 7-已删除 8-SMART状态异常 0xff-不存在 + public int dwHCapacity; // 阵列容量高32位 + public int dwLCapacity; // 阵列容量低32位 + public int dwHFreeSpace; // 阵列剩余空间高32位 + public int dwLFreeSpace; // 阵列剩余空间高32位 + public byte[] byArrayName = new byte[MAX_NAMELEN]; // 阵列名称 + public byte byPDCount; // 物理磁盘数目 + public byte bySpareCount; // 热备数目 + public byte[] byRes1 = new byte[2]; + public short[] wPDSlots = new short[SUPPORT_PD_NUM]; // 物理磁盘索引 + public short[] wSparePDSlots = new short[SUPPORT_PD_NUM]; // 热备磁盘索引 + public NET_DVR_BGA_INFO struBgaInfo; // 后台任务运行状态 + public short[] wPDSlotsPartTwo = new short[SUPPORT_PD_NUM_PARTTWO]; //物理磁盘索引扩展,0表示无效 + public short[] wSparePDSlotsPartTwo = new short[SUPPORT_PD_NUM_PARTTWO]; // 热备磁盘索引扩展,0表示无效 + public byte[] byRes2 = new byte[48]; // 保留字节 + } + + //物理磁盘 + public static class NET_DVR_PHY_DISK_INFO extends HIKSDKStructure { + public short wPhySlot; // 硬盘槽位 + public byte byType; // 硬盘信息;0 普通,1全局热备,2-阵列热备 3-阵列盘 + public byte byStatus; // 硬盘状态; 0-正常 1-降级 2-已删除 3-磁盘丢失 4-下线 5-次正常 6-外来 7-异常 8-SMART状态异常 9-休眠 10-有坏块 0xff-不存在 + public byte[] byMode = new byte[40]; // 硬盘类型 字符串 + public int dwHCapacity; // 磁盘总量高32位 单位kb + public int dwLCapacity; // 磁盘总量低32位 + public byte[] byArrrayName = new byte[MAX_NAMELEN]; + public short wArrayID; // 所属阵列ID + public byte byArrayInformation; // 是否含有阵列信息:0 否,1是 + public byte[] byRes = new byte[101]; // 保留字节 + } + + public static class NET_DVR_WORKSTATE_V40 extends HIKSDKStructure { + public int dwSize; //结构体大小 + public int dwDeviceStatic; //设备的状态,0-正常,1-CPU占用率太高,超过85%,2-硬件错误,例如串口死掉 + public NET_DVR_DISKSTATE[] struHardDiskStatic = new NET_DVR_DISKSTATE[MAX_DISKNUM_V30]; //硬盘状态,一次最多只能获取33个硬盘信息 + public NET_DVR_CHANNELSTATE_V30[] struChanStatic = new NET_DVR_CHANNELSTATE_V30[MAX_CHANNUM_V40/*512*/];//通道的状态,从前往后顺序排列 + public int[] dwHasAlarmInStatic = new int[MAX_ALARMIN_V40]; //有报警的报警输入口,按值表示,按下标值顺序排列,值为0xffffffff时当前及后续值无效 + public int[] dwHasAlarmOutStatic = new int[MAX_ALARMOUT_V40]; //有报警输出的报警输出口,按值表示,按下标值顺序排列,值为0xffffffff时当前及后续值无效 + public int dwLocalDisplay; //本地显示状态,0-正常,1-不正常 + public byte[] byAudioInChanStatus = new byte[MAX_AUDIO_V30/*2*/]; //按位表示语音通道的状态 0-未使用,1-使用中,第0位表示第1个语音通道 + public byte[] byRes1 = new byte[2]; + public float fHumidity; //传感器获知的湿度,范围:0.0 ~100.0 + public float fTemperature; //传感器获知的温度,范围:-20.0 ~ 90.0 + public byte[] byRes = new byte[116]; //保留 + } + + public static class NET_DVR_GETWORKSTATE_COND extends HIKSDKStructure { + public int dwSize; //结构体长度 + public byte byFindHardByCond; /*0-查找全部磁盘(但一次最多只能查找33个),此时dwFindHardStatusNum无效*/ + public byte byFindChanByCond; /*0-查找全部通道,此时dwFindChanNum无效*/ + public byte[] byRes1 = new byte[2];//保留 + public int[] dwFindHardStatus = new int[MAX_DISKNUM_V30/*33*/]; /*要查找的硬盘号,按值表示,该值采用顺序排列, 遇到0xffffffff则认为后续无效 */ + public int[] dwFindChanNo = new int[MAX_CHANNUM_V40/*512*/]; /*要查找的通道号,按值表示,该值采用顺序排列, 遇到0xffffffff则认为后续无效 */ + public byte[] byRes = new byte[64]; //保留 + } + + //多边型结构体 + public static class NET_ITC_POLYGON extends HIKSDKStructure { + public int dwPointNum; //有效点 大于等于3,若是3点在一条线上认为是无效区域,线交叉认为是无效区域 + public NET_VCA_POINT[] struPos = new NET_VCA_POINT[ITC_MAX_POLYGON_POINT_NUM]; //多边形边界点,最多20个 + } + + public static class CUSTOM_uRegion extends Union { + public NET_VCA_RECT struRect = new NET_VCA_RECT(); + public NET_ITC_POLYGON struPolygon = new NET_ITC_POLYGON(); + } + + public static class NET_ITC_PLATE_RECOG_REGION_PARAM extends HIKSDKStructure { + public byte byMode; //区域类型,0-矩形,1-多边形 + public byte[] byRes1 = new byte[3]; + public CUSTOM_uRegion uRegion = new CUSTOM_uRegion(); + public byte[] byRes = new byte[16]; //保留 + } + + //单组IO测速参数 + public static class NET_ITC_SINGLE_IOSPEED_PARAM extends HIKSDKStructure { + public byte byEnable; //是否启用,0-不启用,1-启用 + public byte byTrigCoil1; //第一线圈关联IO,0-IO1,1-IO2,2-IO3,3-IO4,4-IO5,5-IO6 + public byte byCoil1IOStatus;//第一线圈IO输入口状态,0-下降沿(默认),1-上升沿,2-上升沿和下降沿,3-高电平,4-低电平 + public byte byTrigCoil2; //第二线圈关联IO,0-IO1,1-IO2,2-IO3,3-IO4,4-IO5,5-IO6 + public byte byCoil2IOStatus;//第二线圈IO输入口状态,0-下降沿(默认),1-上升沿,2-上升沿和下降沿,3-高电平,4-低电平 + public byte byRelatedDriveWay;//关联的车道号 + public byte byTimeOut;//超时时间(默认10),单位s + public byte byRelatedIOOutEx;//第0位表示IO输出口1,以此类推,0-不关联,1-关联 支持关联到8个(兼容byRelatedIOOut字段) + public int dwDistance;//线圈距离(默认1000),单位:厘米 + public byte byCapSpeed;//起拍速度(默认30),单位km/h + public byte bySpeedLimit;//限速值(默认60),单位km/h + public byte bySpeedCapEn; //是否启用超速抓拍,0-否,1-是 + public byte bySnapTimes1; //线圈1抓拍次数(默认不抓拍),0-不抓拍,非0-连拍次数,最大5次 + public byte bySnapTimes2; //线圈2抓拍次数(默认1),0-不抓拍,非0-连拍次数,最大5次 + public byte byBigCarSpeedLimit; //大车车速限制值 + public byte byBigCarSignSpeed;//标志限速(大车),单位km/h(3.7Ver) + public byte byIntervalType; //间隔类型(默认按时间),0-时间起效,1-距离起效 + public short[] wInterval1 = new short[MAX_INTERVAL_NUM];//线圈1连拍间隔时间(单位ms)或连拍间隔距离(单位分米),当byIntervalType为0时,表示间隔时间,当byIntervalType为1时,表示距离 + public short[] wInterval2 = new short[MAX_INTERVAL_NUM];//线圈2连拍间隔时间(单位ms)或连拍间隔距离(单位分米),当byIntervalType为0时,表示间隔时间,当byIntervalType为1时,表示距离 + public byte[] byRelatedIOOut = new byte[MAX_IOOUT_NUM]; //关联的IO输出口(可以同时关联多个),数组0表示IO输出口1,数组1表示IO输出口2,以此类推,0-不关联,1-关联 + public byte byFlashMode; //闪光灯闪烁模式,0-同时闪,1-轮流闪 + public byte byLaneType; //车道类型,0-未配置、1-高速公路、2-城市快速路、0xff-其他道路 + public byte byCarSignSpeed;//标志限速,单位km/h(3.7Ver) + public byte byUseageType; //车道用途类型,详见ITC_LANE_USEAGE_TYPE + public NET_ITC_PLATE_RECOG_REGION_PARAM[] struPlateRecog = new NET_ITC_PLATE_RECOG_REGION_PARAM[MAX_LANEAREA_NUM]; //牌识参数(可用牌识区域1个,保留一个) + //关联车道方向类型,参考ITC_RELA_LANE_DIRECTION_TYPE + //该参数为车道方向参数,与关联车道号对应,确保车道唯一性。 + public byte byRelaLaneDirectionType; + public byte byLowSpeedLimit; //小车限底速值,单位km/h + public byte byBigCarLowSpeedLimit; //大车限底速值,单位km/h + public byte byLowSpeedCapEn; //是否启用低速抓拍,0-否,1-是 + public byte byEmergencyCapEn; //是否启用应急车道抓拍,0-否,1-是 + public byte[] byRes = new byte[27]; + } + + //牌识参数 + public static class NET_ITC_PLATE_RECOG_PARAM extends HIKSDKStructure { + public byte[] byDefaultCHN = new byte[MAX_CHJC_NUM]; /*设备运行省份的汉字简写*/ + public byte byEnable; //是否启用该区域牌识,0-否,1-是 + public int dwRecogMode; + /*识别的类型, + bit0-背向识别:0-正向车牌识别,1-背向识别(尾牌识别) ; + bit1-大车牌识别或小车牌识别:0-小车牌识别,1-大车牌识别 ; + bit2-车身颜色识别:0-不采用车身颜色识别,在背向识别或小车牌识别时禁止启用,1-车身颜色识别; + bit3-农用车识别:0-不采用农用车识别,1-农用车识别; + bit4-模糊识别:0-不采用模糊识别,1-模糊识别; + bit5-帧定位或场定位:0-帧定位,1-场定位; + bit6-帧识别或场识别:0-帧识别,1-场识别; + bit7-晚上或白天:0-白天,1-晚上 + bit8-摩托车识别:0-不采用摩托车识别,1-摩托车识别; + bit9-场景模式:0-电警/多帧,1-卡口; + bit10-微小车牌:0-不启用,1-启用微小车牌识别(像素60~80) + bit11-安全带检测:0-不启用,1-启用安全带检测 + bit12-民航车牌识别: 0-不启用,1-开启民航车牌识别 + bit13-车牌过渡倾斜处理: 0-不启用,1-开启过渡倾斜处理(PRS) + bit14-超大车牌识别: 0-不启用,1-开启超大车牌识别(PRS) + bit15-遮阳板检测:0-不启用,1-启用遮阳板检测 + bit16-黄标车检测:0-不启用,1-启用黄标车检测 + bit17-危险品车辆检测:0-不启用,1-启用危险品车辆检测 + bit18-使馆车牌识别:0-不启用,1-启用使馆车牌识别 + bit19-车辆子品牌识别:0-不启用,1-启用车辆子品牌识别 + bit20-打电话识别:0-不启用,1-启用 + bit21-车窗悬挂物识别:0-不启用,1-启用 + */ + public byte byVehicleLogoRecog;//车标识别 0-不启用,1-启用 + /* + 0-保留,1-澳,2-京,3-渝,4-闽,5-甘,6-粤,7-桂,8-贵,9-琼,10-冀,11-豫, + 12-黑,13-鄂,14-湘,15-吉,16-苏,17-赣,18-辽,19-蒙,20-宁,21-青,22-鲁, + 23-晋,24-陕,25-沪,26-川,27-台,28-津,29-藏,30-港,31-新,32-云,33-浙, + 34-皖,0xff-全部 + */ + public byte byProvince;//省份索引值 + public byte byRegion;// 区域索引值 0-保留,1-欧洲, 3-欧洲&(EU&CIS),4-中东(Middle East) + public byte byCountry;//国家索引,参照枚举COUNTRY_INDEX(不支持“COUNTRY_ALL = 0xff,//ALL 全部”) + public short wPlatePixelWidthMin;//车牌像素识别宽度最小值(单位是像素)当前推荐范围[130,500] + public short wPlatePixelWidthMax;//车牌像素识别宽度最大值(单位是像素)当前推荐范围[130,500] + public byte[] byRes = new byte[24]; + } + + //卡口IO测速参数 + public static class NET_ITC_POST_IOSPEED_PARAM extends HIKSDKStructure { + public NET_ITC_PLATE_RECOG_PARAM struPlateRecog; //牌识参数 + public NET_ITC_SINGLE_IOSPEED_PARAM[] struSingleIOSpeed = new NET_ITC_SINGLE_IOSPEED_PARAM[MAX_IOSPEED_GROUP_NUM]; //单个IO测速组参数 + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_GEOGLOCATION extends HIKSDKStructure { + public int[] iRes = new int[2]; /*保留*/ + public int dwCity; /*城市,详见PROVINCE_CITY_IDX */ + } + + public static class NET_ITC_INTERVAL_PARAM extends HIKSDKStructure { + public byte byIntervalType; //间隔类型(默认按时间),0-时间起效,1-距离起效 + public byte[] byRes1 = new byte[3]; + public short[] wInterval = new short[MAX_INTERVAL_NUM];//连拍间隔时间(单位ms)或连拍间隔距离(单位分米),当byIntervalType为0时,表示间隔时间,当byIntervalType为1时,表示距离 + public byte[] byRes = new byte[8]; + } + + public static class NET_ITC_VTLANE_PARAM extends HIKSDKStructure { + public byte byRelatedDriveWay;//关联的车道号 + public byte bySpeedCapEn; //是否启用超速抓拍,0-否,1-是 + public byte bySignSpeed;//标志限速,单位km/h + public byte bySpeedLimit;//限速值,单位km/h + public byte bySnapTimes; //抓拍次数(默认1),0-不抓拍,非0-连拍次数,最大5 + public byte byBigCarSignSpeed;///*大车标志限速,单位km/h*/ + public byte byBigCarSpeedLimit;/*大车限速值,单位km/h*/ + public byte byRelatedIOOutEx;//第0位表示IO输出口1,以此类推,0-不关联,1-关联 支持关联到8个(兼容byRelatedIOOut字段) + public NET_ITC_INTERVAL_PARAM struInterval = new NET_ITC_INTERVAL_PARAM(); //抓拍间隔参数 + public byte[] byRelatedIOOut = new byte[MAX_IOOUT_NUM]; //关联的IO输出口,可以同时关联多个 + public byte byFlashMode; //闪光灯闪烁模式,0-同时闪,1-轮流闪 + public byte byLowSpeedLimit;/*限低速,单位km/h*/ + public byte byBigCarLowSpeedLimit; /*大车限低速,单位km/h*/ + //关联车道方向类型,参考ITC_RELA_LANE_DIRECTION_TYPE + //该参数为车道方向参数,与关联车道号对应,确保车道唯一性。 + public byte byRelaLaneDirectionType; + public NET_ITC_PLATE_RECOG_REGION_PARAM[] struPlateRecog = new NET_ITC_PLATE_RECOG_REGION_PARAM[MAX_LANEAREA_NUM]; //车道牌识参数 + public NET_VCA_LINE struLine = new NET_VCA_LINE(); //车道线 + } + + public static class NET_ITC_VTCOIL_INFO extends HIKSDKStructure { + public NET_VCA_RECT struLaneRect = new NET_VCA_RECT(); /*虚拟线圈区域*/ + public byte byTrigFlag; //触发标志,0-车头触发;1-车尾触发;2-车头/车尾都触发 + public byte byTrigSensitive; //触发灵敏度,1-100 + public byte[] byRelatedIOOut = new byte[MAX_IOOUT_NUM]; //关联的IO输出口(可以同时关联多个),数组0表示IO输出口1,数组1表示IO输出口2,以此类推,0-不关联,1-关联 + public byte byFlashMode; //闪光灯闪烁模式,0-同时闪,1-轮流闪 + public byte byLaneType; //车道类型,0-未配置、1-高速公路、2-城市快速路、0xff-其他道路 + public byte byEnableRadar; //是否启用雷达测速,0-否,1-是 + public NET_ITC_VTLANE_PARAM struLane = new NET_ITC_VTLANE_PARAM(); //关联的车道参数 + //车道用途类型,详见ITC_LANE_USEAGE_TYPE,使用1和8两种类型(3.7Ver) + public byte byUseageType; + //车辆行驶方向,详见ITC_LANE_CAR_DRIVE_DIRECT(3.7Ver) + public byte byCarDriveDirect; + public byte[] byRes = new byte[30]; + } + + public static class NET_ITC_RADAR_PARAM extends HIKSDKStructure { + public byte byRadarType; //雷达类型,0-无雷达,1-安道雷雷达,2-奥利维亚,3-川速微波4,雷达接IO扩展盒(此参数在卡口虚拟线圈、混行卡口界面中使用,卡口RS485雷达不使用),0xff-其它类型 + public byte byLevelAngle; //与水平线所成角度,默认为25°(0到90度) + public short wRadarSensitivity; //雷达灵敏度 + public short wRadarSpeedValidTime;//雷达速度有效时间(0~2000] ,0表示不支持 + public byte[] byRes1 = new byte[2]; + public float fLineCorrectParam;//线性矫正参数[0.0~2.0] + public int iConstCorrectParam;//常量矫正参数[-100~100] + public byte[] byRes2 = new byte[8]; + } + + //卡口虚拟线圈触发参数 + public static class NET_ITC_POST_VTCOIL_PARAM extends HIKSDKStructure { + public byte byRelatedLaneNum;//关联的车道个数 + public byte byIsDisplay; //视频中是否显示虚拟线圈,0-不显示,1-显示 + public byte byLoopPos; //晚间触发线圈的偏向(默认10) + public byte byPolarLenType; /*偏振镜类型,0:不加偏振镜;1:加施耐德偏振镜。*/ + public byte byDayAuxLightMode; /*白天辅助照明模式,0:无辅助照明;1:LED灯照明;2:闪光灯照明*/ + public byte byVideoLaneNO; //视频参考亮度的参考车道号 + public byte byVideoLowTh; /*视†频参考亮度低阈值初始化值(默认40)*/ + public byte byVideoHighTh; /*视频参考亮度高阈值初始化值(默认55)*/ + public byte byRecordMode; //录像标志:0-不录像,1-录像 + public byte bySnapMode;//抓拍模式:0-频闪模式;1-爆闪模式 + /*测速方式:0-不测速,0x1-雷达测速,0x2-视频测速*/ + public byte bySpeedDetector; + public byte byRes2; + public short wResolutionX;/* 设备当前分辨率宽*/ + public short wResolutionY;/* 设备当前分辨率高*/ + public int dwDayInitExp; /*视频白天曝光时间的初始值2000*/ + public int dwDayMaxExp; /*视频白天曝光时间的最大值20000*/ + public int dwNightExp; /*晚间视频曝光时间的设置值3000*/ + public int dwSnapExp; /*抓拍曝光时间*/ + public byte byDayInitGain; /*视频白天增益的初始值200*/ + public byte byDayMaxGain; /*视频白天增益的最大值400*/ + public byte byNightGain; /*晚间视频增益*/ + public byte bySnapGain; /*抓拍增益*/ + public int dwSceneMode; //场景模式, 详见SCENE_MODE + public NET_DVR_GEOGLOCATION struGeogLocation = new NET_DVR_GEOGLOCATION(); //地址位置(默认浙江) + public NET_ITC_PLATE_RECOG_PARAM struPlateRecog = new NET_ITC_PLATE_RECOG_PARAM(); //牌识参数 + public NET_ITC_VTCOIL_INFO[] struVtCoil = new NET_ITC_VTCOIL_INFO[MAX_VL_NUM]; //虚拟线圈参数 + public NET_ITC_RADAR_PARAM struRadar = new NET_ITC_RADAR_PARAM(); //雷达参数 + public NET_VCA_LINE struLine = new NET_VCA_LINE(); //右车道线 + //违规检测类型,按位表示,详见ITC_VIOLATION_DETECT_TYPE,0-不启用,1-启用(3.7Ver) + public int dwVioDetectType; + public byte byDebugMode; /*调试模式,0-不启用,1-启用*/ + public byte[] byRes = new byte[11]; + } + + //车道属性参数结构 + public static class NET_ITC_LANE_LOGIC_PARAM extends HIKSDKStructure { + public byte byUseageType; //车道用途类型,详见ITC_LANE_USEAGE_TYPE + public byte byDirectionType; //车道方向类型,详见ITC_LANE_DIRECTION_TYPE + public byte byCarDriveDirect; //车辆行驶方向,详见ITC_LANE_CAR_DRIVE_DIRECT + public byte[] byRes = new byte[33]; //保留 + } + + //视频电警线结构 + public static class NET_ITC_LINE extends HIKSDKStructure { + public NET_VCA_LINE struLine = new NET_VCA_LINE(); //线参数 + public byte byLineType; //线类型,详见ITC_LINE_TYPE + public byte[] byRes = new byte[7]; + } + + public static class NET_ITC_SNAPMODE_PARAM extends HIKSDKStructure { + public byte byVehicleCapMode;//机动车抓拍模式,0-频闪模式;1-爆闪模式 + public byte byNoVehicleCapMode;//非机动车抓拍模式,0-频闪模式;1-爆闪模式 + public byte byPasserCapMode;//行人抓拍模式,0-频闪模式;1-爆闪模式 + public byte[] byRes = new byte[29]; + } + + //size = 128 + public static class NET_ITC_HVT_EC_PARAM extends HIKSDKStructure { + public int dwCapShutter; //抓拍快门0~65535 + public short wCapGain; //抓拍增益0~100 + public byte[] byRes = new byte[2]; + public int dwDayTimeVideoShutter; //白天曝光时间最大值 + public short wDayTimeVideoGain; //白天增益最大值 + public short wNightVideoGain; //晚上增益最大值 + public short wNightVideoShutter; //晚上曝光时间最大值 + public byte[] byRes1 = new byte[108]; + } + + public static class NET_ITC_LANE_HVT_PARAM extends HIKSDKStructure { + public byte byLaneNO; //关联的车道号 1~255(用于叠加和上传) + public byte bySignSpeed; //标志限速,单位km/h 0~255 70 + public byte bySpeedLimit; //限速值,单位km/h 0~255 80 实际起效 + public byte byBigCarSignSpeed;///*大车标志限速,单位km/h*/ + public byte byBigCarSpeedLimit;/*大车限速值,单位km/h*/ + public byte bySpeedCapEn; //是否启用超速抓拍,0-否,1-是 + public byte byCaptureCount;//抓拍张数1~5(正常) + public byte byRelatedIOOut; /*关联的IO输出口(可以同时关联多个),按位表示IO输出口,第0位表示IO输出口1,以此类推,0-不关联,1-关联*/ + public byte byFlashMode; /*闪光灯闪烁模式,0-同时闪,1-轮流闪*/ + public byte byEnableRadar; //是否启用雷达测速,0-否,1-是 + public byte byChangeLaneEnable; //违章变道抓拍使能,0-关闭,1-开启 + public byte byChangeLaneCapNo; //违章变道抓拍张数2-3 + public int dwCapTarget; //抓拍类型 bit0 表示机动车 bit1 表示非机动车 bit2 表示行人 0~表示不选择 1~表示选择 + public NET_ITC_INTERVAL_PARAM struInterval; //抓拍间隔参数 + public byte[] byRes3 = new byte[24]; + public NET_ITC_LANE_LOGIC_PARAM struLane; //车道属性,用byUseageType和byCarDriveDirect + public NET_ITC_LINE struLeftLaneLine; //左车道线,线类型为虚线、实线、单黄线和双黄线 + public NET_ITC_LINE struRightLaneLine; //右车道线,线类型为虚线、实线、单黄线和双黄线 + public NET_ITC_POLYGON struPlateRecog; //牌识区域参数 + public NET_ITC_POLYGON struTraceArea; //视频触发焦点区域 + public NET_VCA_LINE struForwardTrigLine; //正向触发线:一条线段,关心端点位置,目前只支持水平配置,接口按线段的两个端点保存。(一般配置为正向车辆的最佳触发位置) + public NET_VCA_LINE struBackwardTrigLine; //背向触发线:一条线段,关心端点位置,目前只支持水平配置,接口按线段的两个端点保存(一般配置为背向车辆的最佳触发位置) + public NET_VCA_LINE struLeftTrigLine; //左边触发线:一条线段,关心端点位置,目前只支持垂直配置,接口按线段的两个端点保存(一般配置为从左边进入车辆的最佳触发位置) + public NET_VCA_LINE struRightTrigLine; //右边触发线:一条线段,关心端点位置,目前只支持垂直配置,接口按线段的两个端点保存(一般配置为从右边进入车辆的最佳触发位置) + public byte[] byRes4 = new byte[60]; + } + + public static class NET_ITC_POST_HVT_PARAM extends HIKSDKStructure { + public byte byLaneNum;//识别的车道个数,1-6 + public byte bySceneMode;//0-未知1-城区道路;2-小区出入口 + public byte byRoadExpBright;//路面期望亮度(视频曝光参数调整的依据之一。在无机动车时,依据此亮度期望值,调整视频曝光参数) + public byte byPlateExpBright;//车牌期望亮度(视频曝光参数调整的依据之一。在有机动车通过并识别到车牌时,依据此亮度期望值,对视频曝光参数调整) + public NET_ITC_POLYGON struDetectArea; //视频检测区域 + public NET_ITC_SNAPMODE_PARAM struCapMode = new NET_ITC_SNAPMODE_PARAM();//抓拍模式 + public NET_ITC_HVT_EC_PARAM struEcParam = new NET_ITC_HVT_EC_PARAM(); //曝光控制参数 + public NET_ITC_LANE_HVT_PARAM[] struLaneParam = new NET_ITC_LANE_HVT_PARAM[MAX_ITC_LANE_NUM]; //单车道属性 + public NET_ITC_PLATE_RECOG_PARAM struPlateRecog = new NET_ITC_PLATE_RECOG_PARAM(); //牌识参数 + public NET_DVR_GEOGLOCATION struGeogLocation = new NET_DVR_GEOGLOCATION(); //地址位置(默认浙江) + public byte[] byRes = new byte[324]; + } + + //抓拍机4.0新增 + public static class NET_ITC_LANE_HVT_PARAM_V50 extends HIKSDKStructure { + public byte byLaneNO; //关联的车道号1~255(用于叠加和上传) + public byte byFlashMode; //闪光灯闪烁模式,0-同时闪,1-轮流闪 + public byte bySignSpeed; //小车标志限高速,单位km/h + public byte bySpeedLimit; //小车限高速值,单位km/h + public byte bySignLowSpeed; //小车标志限底速,单位km/h + public byte byLowSpeedLimit; //小车限底速值,单位km/h + public byte byBigCarSignSpeed; //大车标志限高速,单位km/h(新交规) + public byte byBigCarSpeedLimit; //大车限高速值,单位km/h(新交规) + public byte byBigCarSignLowSpeed; //大车标志限底速,单位km/h + public byte byBigCarLowSpeedLimit; //大车限底速值,单位km/h + public byte bySnapTimes; //卡口抓拍张数,1~3 + public byte byDriveLineSnapTime;// 压线抓拍张数 1~3 + public byte byHighSpeedSnapTime;// 超高速抓拍张数1~3 + public byte byLowSpeedSnapTime;// 超低速抓拍张数1~3 + public byte byBanSnapTime;// 违反禁令抓拍张数 1~3 + public byte byReverseSnapTime;//逆行抓拍张数 1~3 + public byte byRelatedDriveWay; //关联车道号,用于匹配车检器 + public byte byLaneType; //车道类型,0-未配置、1-高速公路、2-城市快速路、0xff-其他道路 + //关联车道方向类型,参考ITC_RELA_LANE_DIRECTION_TYPE + //该参数为车道方向参数,与关联车道号byRelatedDriveWay对应,确保车道唯一性。 + public byte byRelaLaneDirectionType; + public byte[] byRes1 = new byte[27]; + public byte byChangeLaneEnable; //违章变道抓拍使能,0-关闭,1-开启 + public byte byChangeLaneCapNo; //违章变道抓拍张数2-3 + //目前仅使用第一个车道的,以后可能会扩展为多车道分别配置 + //类型, 按位表示,0-不启用,1-启用参考 ITC_VIOLATION_DETECT_TYPE + public int dwVioDetectType; + public int dwRelatedIOOut; //关联的IO输出口(可以同时关联多个),按位表示IO输出口,第0位表示IO输出口1,以此类推,0-不关联,1-关联 + public NET_ITC_LINE struTrigLine; //触发线,目前仅使用第一个车道的,以后可能会扩展为多车道分别配置 + public NET_ITC_LINE struLineLeft; //左车道线 + public NET_ITC_POLYGON struPlateRecog; //牌识区域 + public NET_ITC_LANE_LOGIC_PARAM struLane; //车道属性,用byUseageType和byCarDriveDirect + public NET_ITC_INTERVAL_PARAM struInterval;//抓拍间隔参数(20byte) + public byte[] byRes2 = new byte[280]; + } + + public static class NET_ITC_POST_HVT_PARAM_V50 extends HIKSDKStructure { + public byte byLaneNum; //识别的车道个数,1-6 + public byte byCapType; //抓拍类型,0-机、非、人(默认),1-机动车 + public byte byCapMode; //抓拍方式,0-视频抽帧,1-打断抓拍,2-混合模式, + public byte bySecneMode; //场景模式,0-城区道路(默认),1-小区出入口,2-高速公路 + public byte bySpeedMode; //测速模式,0-无测速,1-雷达测速,2-视频测速 + public byte byLineRuleEffect; //触发规则线有效性,每一位代表一条触发线,0-无效;1-有效。bit0-左触发线;bit1-右触发线;bit2-视频检测区域 + public byte[] byRes1 = new byte[78]; + public NET_ITC_LINE struLeftTrigLine; //左触发线(一条垂直线) + public NET_ITC_LINE struRigtTrigLine; //右触发线(一条垂直线) + public NET_ITC_LINE struLaneBoundaryLine; //车道边界线(最右边车道的右车道线) + public NET_ITC_POLYGON struDetectArea; //视频检测区域 + public NET_DVR_GEOGLOCATION struGeogLocation; //地理位置(默认浙江省)计算时区 + public NET_ITC_LANE_HVT_PARAM_V50[] struLaneParam = new NET_ITC_LANE_HVT_PARAM_V50[MAX_ITC_LANE_NUM/*6*/]; //单车道属性 + public NET_ITC_PLATE_RECOG_PARAM struPlateRecog; //牌识参数 + public byte[] byRes2 = new byte[260]; + } + + + public static class NET_ITC_LANE_PARAM extends HIKSDKStructure { + public byte byEnable; //是否启用该车道,0-不启用,1-启用 + public byte byRelatedDriveWay;//关联的车道号 + public short wDistance; //线圈距离,计算速度 + public short wTrigDelayTime; //触发延迟时间(默认200),单位:毫秒 + public byte byTrigDelayDistance; //触发延迟距离(默认0),单位:分米 + public byte bySpeedCapEn; //是否启用超速抓拍,0-否,1-是 + public byte bySignSpeed;//标志限速,单位km/h + public byte bySpeedLimit;//限速值,单位km/h + public byte bySnapTimes; //抓拍次数(默认1),0-不抓拍,非0-连拍次数,最大5 + public byte byOverlayDriveWay; //OSD叠加的车道号 + public NET_ITC_INTERVAL_PARAM struInterval; //抓拍间隔参数 + public byte[] byRelatedIOOut = new byte[MAX_IOOUT_NUM]; //关联的IO输出口,可以同时关联多个 + public byte byFlashMode; //闪光灯闪烁模式,0-同时闪,1-轮流闪 + public byte byCartSignSpeed;//标志限速(大车),单位km/h + public byte byCartSpeedLimit;//限速值(大车),单位km/h + public byte byRelatedIOOutEx;//第0位表示IO输出口1,以此类推,0-不关联,1-关联 支持关联到8个(兼容byRelatedIOOut字段) + public NET_ITC_PLATE_RECOG_REGION_PARAM[] struPlateRecog = new NET_ITC_PLATE_RECOG_REGION_PARAM[MAX_LANEAREA_NUM]; //车道牌识参数 + public byte byLaneType; //车道类型,0-未配置、1-高速公路、2-城市快速路、0xff-其他道路 + public byte byUseageType; //车道用途类型,详见ITC_LANE_USEAGE_TYPE + //关联车道方向类型,参考ITC_RELA_LANE_DIRECTION_TYPE + //该参数为车道方向参数,与关联车道号对应,确保车道唯一性。 + public byte byRelaLaneDirectionType; + public byte byLowSpeedLimit; //小车限底速值,单位km/h + public byte byBigCarLowSpeedLimit; //大车限底速值,单位km/h + public byte byLowSpeedCapEn; //是否启用低速抓拍,0-否,1-是 + public byte byEmergencyCapEn; //是否启用应急车道抓拍,0-否,1-是 + public byte[] byRes = new byte[9]; + } + + //卡口RS485车检器触发参数 + public static class NET_ITC_POST_RS485_PARAM extends HIKSDKStructure { + public byte byRelatedLaneNum;//关联的车道个数 + public byte byTriggerSpareMode; //触发备用模式,0-默认,1-卡口虚拟线圈模式,2-卡口混合车道模式 + public byte byFaultToleranceTime;//容错时间(单位:分钟),用于检测车检器是否正常的最大时间 + public byte byRes1; + public NET_ITC_PLATE_RECOG_PARAM struPlateRecog = new NET_ITC_PLATE_RECOG_PARAM(); //牌识参数 + public NET_ITC_LANE_PARAM[] struLane = new NET_ITC_LANE_PARAM[MAX_ITC_LANE_NUM]; //关联的车道参数 + public byte[] byRes = new byte[32]; + } + + //卡口RS485雷达触发参数 + public static class NET_ITC_POST_RS485_RADAR_PARAM extends HIKSDKStructure { + public byte byRelatedLaneNum;//关联的车道个数 + public byte[] byRes1 = new byte[3]; + public NET_ITC_PLATE_RECOG_PARAM struPlateRecog = new NET_ITC_PLATE_RECOG_PARAM(); //牌识参数 + public NET_ITC_LANE_PARAM[] struLane = new NET_ITC_LANE_PARAM[MAX_ITC_LANE_NUM]; //关联的车道参数 + public NET_ITC_RADAR_PARAM struRadar = new NET_ITC_RADAR_PARAM(); //雷达参数 + public byte[] byRes = new byte[32]; + } + + public static class NET_ITC_TRIGGER_PARAM_UNION extends Union { + public int[] uLen = new int[1070]; //参数 + public NET_ITC_POST_IOSPEED_PARAM struIOSpeed = new NET_ITC_POST_IOSPEED_PARAM(); //(卡口)IO测速参数 + // public NET_ITC_POST_SINGLEIO_PARAM struSingleIO = new NET_ITC_POST_SINGLEIO_PARAM(); //(卡口)单IO参数 + public NET_ITC_POST_RS485_PARAM struPostRs485 = new NET_ITC_POST_RS485_PARAM(); //(卡口)RS485车检器参数 + public NET_ITC_POST_RS485_RADAR_PARAM struPostRadar = new NET_ITC_POST_RS485_RADAR_PARAM(); //(卡口)RS485雷达参数 + public NET_ITC_POST_VTCOIL_PARAM struVtCoil = new NET_ITC_POST_VTCOIL_PARAM(); //(卡口)虚拟线圈参数 + public NET_ITC_POST_HVT_PARAM struHvt = new NET_ITC_POST_HVT_PARAM(); //(卡口)混行卡口参数 + // public NET_ITC_EPOLICE_IOTL_PARAM struIOTL = new NET_ITC_EPOLICE_IOTL_PARAM(); //(电警)IO红绿灯参数 +// public NET_ITC_EPOLICE_RS485_PARAM struEpoliceRs485 = new NET_ITC_EPOLICE_RS485_PARAM(); //(电警)RS485车检器触发参数 +// public NET_ITC_EPOLICE_RS485_PARAM struPERs485 = new NET_ITC_EPOLICE_RS485_PARAM(); //(卡式电警)RS485车检器触发参数 +// public NET_ITC_POST_MPR_PARAM struPostMpr = new NET_ITC_POST_MPR_PARAM(); //多帧检测触发(MPR) +// public NET_DVR_VIA_VTCOIL_PARAM struViaVtCoil = new NET_DVR_VIA_VTCOIL_PARAM(); //(VIA)视频检测参数 +// public NET_ITC_POST_IMT_PARAM struPostImt = new NET_ITC_POST_IMT_PARAM();//智慧布防触发 +// public NET_ITC_POST_PRS_PARAM struPostPrs = new NET_ITC_POST_PRS_PARAM();//视频检测触发 +// public NET_IPC_POST_HVT_PARAM struIpcHvt = new NET_IPC_POST_HVT_PARAM();//(IPC) 混行卡口参数 + public NET_ITC_POST_HVT_PARAM_V50 struHvtV50 = new NET_ITC_POST_HVT_PARAM_V50(); /*(卡口)混行卡口参数V50*/ +// public NET_ITC_POST_MOBILE_PARAM struPostMobile = new NET_ITC_POST_MOBILE_PARAM();// 移动交通触发模式 +// public NET_ITC_NOCOMITY_PEDESTRIAN_PARAM struNoComityPed = new NET_ITC_NOCOMITY_PEDESTRIAN_PARAM();//不礼让行人参数 +// public NET_ITC_REDLIGHT_PEDESTRIAN_PARAM struRedLightPed = new NET_ITC_REDLIGHT_PEDESTRIAN_PARAM();//行人闯红灯参数 + } + + //单个触发参数结构 + public static class NET_ITC_SINGLE_TRIGGERCFG extends HIKSDKStructure { + public byte byEnable; //是否启用该触发模式,0-否,1-是 + public byte[] byRes1 = new byte[3]; + public int dwTriggerType; //触发类型,详见ITC_TRIGGERMODE_TYPE + public NET_ITC_TRIGGER_PARAM_UNION uTriggerParam = new NET_ITC_TRIGGER_PARAM_UNION(); //触发参数 + public byte[] byRes = new byte[64]; + } + + //触发参数结构 + public static class NET_ITC_TRIGGERCFG extends HIKSDKStructure { + public int dwSize; //结构长度 + public NET_ITC_SINGLE_TRIGGERCFG struTriggerParam; //单个触发参数 + public byte[] byRes = new byte[32]; + } + + //单个IO接入信号灯参数 + public static class NET_ITC_SINGLE_IO_LIGHT_PARAM extends HIKSDKStructure { + public byte byLightType; //交通灯导向类型,0-左转灯,1-直行灯,2-右转灯 + public byte byRelatedIO; //关联的IO口号 + public byte byRedLightState; //红灯电平状态,0-高电平红灯,1-低电平红灯 + public byte[] byRes = new byte[17]; + } + + //IO接入信号灯参数 + public static class NET_ITC_IO_LIGHT_PARAM extends HIKSDKStructure { + public NET_ITC_SINGLE_IO_LIGHT_PARAM[] struIOLight = new NET_ITC_SINGLE_IO_LIGHT_PARAM[MAX_LIGHT_NUM]; //单个IO接入信号灯参数 + public byte[] byRes = new byte[8]; + } + + //单个485接入信号灯参数 + public static class NET_ITC_SINGLE_RS485_LIGHT_PARAM extends HIKSDKStructure { + public byte byLightType; //交通灯导向类型,0-左转灯,1-直行灯,2-右转灯 + public byte byRelatedLightChan; //关联的红绿灯检测器通道号 + public byte byInputLight; //接入的信号灯类型,0-接红灯,1-接绿灯 + public byte byRelatedYLightChan; //关联的黄灯检测器通道号 + public byte[] byRes = new byte[16]; + } + + //485接入信号灯参数 + public static class NET_ITC_RS485_LIGHT_PARAM extends HIKSDKStructure { + public NET_ITC_SINGLE_RS485_LIGHT_PARAM[] struRS485Light = new NET_ITC_SINGLE_RS485_LIGHT_PARAM[MAX_LIGHT_NUM]; //单个485接入信号灯参数 + public byte[] byRes = new byte[8]; + } + + public static class NET_POS_PARAM extends HIKSDKStructure { + public short wLeft; + public short wTop; + public short wRight; + public short wBottom; + } + + //单组视频检测交通信号灯参数结构 + public static class NET_ITC_SINGLE_VIDEO_DETECT_LIGHT_PARAM extends HIKSDKStructure { + public byte byLightNum; //交通灯个数 + public byte byStraightLight; //是否有直行标志灯,0-否 ,1-是 + public byte byLeftLight; //是否有左转标志灯,0-否,1-是 + public byte byRightLight; //是否有右转标志灯,0-否,1-是 + public byte byRedLight;//是否有红灯,0-否,1-是 + public byte byGreenLight; //是否有绿灯,0-否,1-是 + public byte byYellowLight; //是否有黄灯,0-否,1-是 + public byte byYellowLightTime;//取值范围(0~10s)(ITC3.7Ver) + public NET_POS_PARAM struLightRect; //交通灯区域 + public byte[] byRes = new byte[24]; + } + + //视频检测交通信号灯参数结构(最大可有12个区域检测,488字节) + public static class NET_ITC_VIDEO_DETECT_LIGHT_PARAM extends HIKSDKStructure { + public NET_ITC_SINGLE_VIDEO_DETECT_LIGHT_PARAM[] struTrafficLight = new NET_ITC_SINGLE_VIDEO_DETECT_LIGHT_PARAM[MAX_VIDEO_DETECT_LIGHT_NUM]; //单个视频检测信号灯参数 + public byte[] byRes = new byte[8]; + } + + //交通信号灯接入参数 + public static class NET_ITC_LIGHT_ACCESSPARAM_UNION extends Union { + public int[] uLen = new int[122]; + public NET_ITC_IO_LIGHT_PARAM struIOLight; //IO接入信号灯参数 + public NET_ITC_RS485_LIGHT_PARAM struRS485Light; //485接入信号灯参数 + public NET_ITC_VIDEO_DETECT_LIGHT_PARAM struVideoDelectLight; //视频检测信号灯参数 + } + + //交通信号灯参数结构 + public static class NET_ITC_TRAFFIC_LIGHT_PARAM extends HIKSDKStructure { + public byte bySource; //交通信号灯接入源,0-IO接入,1-RS485接入 + public byte[] byRes1 = new byte[3]; + public NET_ITC_LIGHT_ACCESSPARAM_UNION struLightAccess = new NET_ITC_LIGHT_ACCESSPARAM_UNION();//信号灯接入参数 + public byte[] byRes = new byte[32]; + } + + //违规检测参数结构 + public static class NET_ITC_VIOLATION_DETECT_PARAM extends HIKSDKStructure { + public int dwVioDetectType; //违规检测类型, 按位表示, 详见ITC_VIOLATION_DETECT_TYPE ,0-不启用,1-启用 + public byte byDriveLineSnapTimes; //压车道线抓拍张数,2-3 + public byte byReverseSnapTimes; //逆行抓拍,2-3 + public short wStayTime; //机占非停留时间(该时间后抓拍),单位s + public byte byNonDriveSnapTimes;//机占非抓拍张数2-3 + public byte byChangeLaneTimes;//违法变道抓拍张数 2-3 + public byte bybanTimes;//违法禁令抓拍张数2-3 + public byte byDriveLineSnapSen;// 压线灵敏度(0~100)(3.7Ver) + public short wSnapPosFixPixel; //第2,3张抓拍位置最小偏移(违反信号灯时起效)(单位:像素) 命名需改进 + public byte bySpeedTimes;//违法超速抓拍张数2-3(3.8Ver) + public byte byTurnAroundEnable;//违章掉头使能 0~关闭 1~开启 + public byte byThirdPlateRecogTime;//第三张牌识时间 0~180s + public byte byPostSnapTimes;//卡口抓拍张数,1-2张 + public byte[] byRes1 = new byte[18]; + public short wStopLineDis; //电警第2张违规图片与停止线的最短距离,[0,300]单位(像素) + public byte[] byRes = new byte[14]; + } + + //违规检测线参数结构 + public static class NET_ITC_VIOLATION_DETECT_LINE extends HIKSDKStructure { + public NET_ITC_LINE struLaneLine = new NET_ITC_LINE(); //车道线参数 + public NET_ITC_LINE struStopLine = new NET_ITC_LINE(); //停止线参数 + public NET_ITC_LINE struRedLightLine = new NET_ITC_LINE(); //闯红灯触发线参数 + public NET_ITC_LINE struCancelLine = new NET_ITC_LINE(); //直行触发位置取消线 + public NET_ITC_LINE struWaitLine = new NET_ITC_LINE(); //待行区停止线参数 + public NET_ITC_LINE[] struRes = new NET_ITC_LINE[8]; + } + + //单个车道视频电警触发参数结构 + public static class NET_ITC_LANE_VIDEO_EPOLICE_PARAM extends HIKSDKStructure { + public byte byLaneNO; //关联的车道号 + public byte bySensitivity; //线圈灵敏度,[1,100] + public byte byEnableRadar;//启用雷达测试0-不启用,1-启用 + //关联车道方向类型,参考ITC_RELA_LANE_DIRECTION_TYPE + //该参数为车道方向参数,与关联车道号对应,确保车道唯一性。 + public byte byRelaLaneDirectionType; + public NET_ITC_LANE_LOGIC_PARAM struLane; //车道参数 + public NET_ITC_VIOLATION_DETECT_PARAM struVioDetect; //违规检测参数 + public NET_ITC_VIOLATION_DETECT_LINE struLine; //违规检测线 + public NET_ITC_POLYGON struPlateRecog; //牌识区域参数 + public byte byRecordEnable;//闯红灯周期录像标志,0-不录像,1-录像 + public byte byRecordType;//闯红灯录像类型,0-预录,1-延时录像 + public byte byPreRecordTime;//闯红灯录像片段预录时间(默认0),单位:秒 + public byte byRecordDelayTime;//闯红灯录像片段延时时间(默认0),单位:秒 + public byte byRecordTimeOut;//闯红灯周期录像超时时间(秒) + public byte byCarSpeedLimit; //车速限制值,单位km/h + public byte byCarSignSpeed;//标志限速,单位km/h + public byte bySnapPicPreRecord; //抓拍图片预录时间点;0-默认值(第二张图片),1-第一张图片,2-第二张图片,3-第三张图片 + public NET_ITC_INTERVAL_PARAM struInterval;//抓拍间隔参数(20byte) + public byte[] byRes = new byte[36]; + } + + //视频电警触发参数结构 + public static class NET_ITC_VIDEO_EPOLICE_PARAM extends HIKSDKStructure { + public byte byEnable; //是否启用,0-不启用,1-启用 + public byte byLaneNum; //识别的车道个数 + public byte byLogicJudge;//闯红灯违规判断逻辑,设置值为:0-按方向,1-按车道 + public byte byRes1; + public NET_ITC_PLATE_RECOG_PARAM struPlateRecog; //牌识参数 + public NET_ITC_TRAFFIC_LIGHT_PARAM struTrafficLight; //交通信号灯参数 + public NET_ITC_LANE_VIDEO_EPOLICE_PARAM[] struLaneParam = new NET_ITC_LANE_VIDEO_EPOLICE_PARAM[MAX_ITC_LANE_NUM]; //单车道参数 + public NET_ITC_LINE struLaneBoundaryLine; //车道边界线(最右边车道的边界线) + public NET_ITC_LINE struLeftLine; //左转弯分界线 + public NET_ITC_LINE struRightLine; //右转弯分界线 + public NET_ITC_LINE struTopZebraLine; //上部斑马线 + public NET_ITC_LINE struBotZebraLine; //下部斑马线 + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_CURTRIGGERMODE extends HIKSDKStructure { + public int dwSize; + public int dwTriggerType; //触发类型,详见ITC_TRIGGERMODE_TYPE + public byte[] byRes = new byte[24]; + } + + public static class NET_ITC_VIDEO_TRIGGER_COND extends HIKSDKStructure { + public int dwSize; + public int dwChannel; + public int dwTriggerMode; //视频触发模式类型,详见ITC_TRIGGERMODE_TYPE + public byte[] byRes = new byte[16]; + } + + public static class NET_ITC_VIDEO_TRIGGER_PARAM_UNION extends Union { + public int[] uLen = new int[1150]; + public NET_ITC_VIDEO_EPOLICE_PARAM struVideoEP = new NET_ITC_VIDEO_EPOLICE_PARAM(); //视频电警参数 + } + + public static class NET_ITC_VIDEO_TRIGGER_PARAM extends HIKSDKStructure { + public int dwSize; + public int dwMode; //触发模式,详见ITC_TRIGGERMODE_TYPE + public NET_ITC_VIDEO_TRIGGER_PARAM_UNION uVideoTrigger = new NET_ITC_VIDEO_TRIGGER_PARAM_UNION(); //触发模式参数 + public byte[] byRes = new byte[32]; + } + + public static class NET_DVR_CMS_PARAM extends HIKSDKStructure { + public int dwSize; + public NET_DVR_IPADDR struAddr = new NET_DVR_IPADDR(); // 平台服务器IP + public short wServerPort; // 平台服务器侦听端口, + public byte bySeverProtocolType; //平台协议类型 1-私有,2-Ehome + public byte byStatus; //设备注册到该平台的状态,1-未注册,2-已注册 + public byte[] sDeviceId = new byte[NAME_LEN/*32*/]; //设备ID,由平台提供 + public byte[] sPassWord = new byte[PASSWD_LEN]; //密码 + /********* + * IPC5.1.7 新增参数 Begin 2014-03-21 + ***********/ + public byte[] sPlatformEhomeVersion = new byte[NAME_LEN];//平台EHOME协议版本 + /********* + * IPC5.1.7 新增参数 end 2014-03-21 + ***********/ + public byte byNetWork; //网络类型:0- 无意义,1-自动,2-有线网络优先,3-有线网络,4-3G网络(无线网络),5-有线网络1,6-有线网络2 + public byte byAddressType; //0 - 无意义, 1 - ipv4/ipv6地址,2 - 域名 + public byte byProtocolVersion; //协议版本 0 - 无意义, 1 – v2.0,2 – v4.0,3-v2.6 + public byte byRes1; + public byte[] sDomainName = new byte[MAX_DOMAIN_NAME/*64*/]; //平台服务器域名,byAddressType为2时有效 + public byte byEnable; //0-关闭,1-开启 + public byte[] byRes = new byte[139]; // 保留字节 + } + + //设置完全获取出厂值 + public static class NET_DVR_COMPLETE_RESTORE_INFO extends HIKSDKStructure { + public int dwSize; //结构体长度 + public int dwChannel; //通道号 + public byte[] byRes = new byte[64]; + } + + public static class NET_DVR_STD_ABILITY extends HIKSDKStructure { + public Pointer lpCondBuffer; //[in]条件参数(码字格式),例如通道号等.可以为NULL + public int dwCondSize; //[in] dwCondSize指向的内存大小 + public Pointer lpOutBuffer; //[out]输出参数(XML格式),不为NULL + public int dwOutSize; //[in] lpOutBuffer指向的内存大小 + public Pointer lpStatusBuffer; //[out]返回的状态参数(XML格式),获取成功时不会赋值,如果不需要,可以置NULL + public int dwStatusSize; //[in] lpStatusBuffer指向的内存大小 + public int dwRetSize; //[out]获取到的数据长度(lpOutBuffer或者lpStatusBuffer指向的实际数据长度) + public byte[] byRes = new byte[32]; //保留字节 + } + + public static class NET_DVR_STD_CONFIG extends HIKSDKStructure { + public Pointer lpCondBuffer; //[in]条件参数(结构体格式),例如通道号等.可以为NULL + public int dwCondSize; //[in] lpCondBuffer指向的内存大小 + public Pointer lpInBuffer; //[in]输入参数(结构体格式),设置时不为NULL,获取时为NULL + public int dwInSize; //[in] lpInBuffer指向的内存大小 + public Pointer lpOutBuffer; //[out]输出参数(结构体格式),获取时不为NULL,设置时为NULL + public int dwOutSize; //[in] lpOutBuffer指向的内存大小 + public Pointer lpStatusBuffer; //[out]返回的状态参数(XML格式),获取成功时不会赋值,如果不需要,可以置NULL + public int dwStatusSize; //[in] lpStatusBuffer指向的内存大小 + public Pointer lpXmlBuffer; //[in/out]byDataType = 1时有效,xml格式数据 + public int dwXmlSize; //[in/out]lpXmlBuffer指向的内存大小,获取时同时作为输入和输出参数,获取成功后会修改会实际长度,设置时表示实际长度,而不是整个内存大小 + public byte byDataType; //[in]输入/输出参数类型,0-使用结构体类型lpInBuffer/lpOutBuffer有效,1-使用XML类型lpXmlBuffer有效 + public byte[] byRes = new byte[23]; + } + + public static final int NET_SDK_MAX_FILE_PATH = 256;//路径长度 + + public static class NET_DVR_LOCAL_SDK_PATH extends HIKSDKStructure { + public byte[] sPath = new byte[NET_SDK_MAX_FILE_PATH];//组件库地址 + public byte[] byRes = new byte[128]; + } + + public static class BYTE_ARRAY extends HIKSDKStructure { + public byte[] byValue; + + public BYTE_ARRAY(int iLen) { + byValue = new byte[iLen]; + } + } + + public static class INT_ARRAY extends HIKSDKStructure { + public int[] intValue; + + public INT_ARRAY(int iLen) { + intValue = new int[iLen]; + } + } + + public static class INTRef_ARRAY extends HIKSDKStructure { + public IntByReference[] intValue; + + public INTRef_ARRAY(int iLen) { + intValue = new IntByReference[iLen]; + } + } + + + public static class NET_DVR_JSON_DATA_CFG extends HIKSDKStructure { + public int dwSize; //结构体大小 + public Pointer lpJsonData; //JSON报文 + public int dwJsonDataSize; //JSON报文大小 + public Pointer lpPicData; //图片内容 + public int dwPicDataSize; //图片内容大小 + public int lpInfraredFacePicBuffer; //红外人脸图片数据缓存 + public Pointer dwInfraredFacePicSize; //红外人脸图片数据大小,等于0时,代表无人脸图片数据(当JSON报文为当ResponseStatus(JSON)报文时,该字段无意义;当Inbound Data(JSON)报文中没有infraredFaceURL时,该字段需要带上二进制图片内容) + public byte[] byRes = new byte[248]; + } + + public static class CallBack_USER extends HIKSDKStructure { + public byte[] byDeviceID = new byte[16]; + public byte[] byCardNo = new byte[32]; + public byte[] byDevIP = new byte[16]; + } + + + public static class NET_DVR_CAMERAPARAMCFG_EX extends HIKSDKStructure { + public int dwSize; + public NET_DVR_VIDEOEFFECT struVideoEffect = new NET_DVR_VIDEOEFFECT();/*亮度、对比度、饱和度、锐度、色调配置*/ + public NET_DVR_GAIN struGain = new NET_DVR_GAIN();/*自动增益*/ + public NET_DVR_WHITEBALANCE struWhiteBalance = new NET_DVR_WHITEBALANCE();/*白平衡*/ + public NET_DVR_EXPOSURE struExposure = new NET_DVR_EXPOSURE(); /*曝光控制*/ + public NET_DVR_GAMMACORRECT struGammaCorrect = new NET_DVR_GAMMACORRECT();/*Gamma校正*/ + public NET_DVR_WDR struWdr = new NET_DVR_WDR();/*宽动态*/ + public NET_DVR_DAYNIGHT struDayNight = new NET_DVR_DAYNIGHT();/*日夜转换*/ + public NET_DVR_BACKLIGHT struBackLight = new NET_DVR_BACKLIGHT();/*背光补偿*/ + public NET_DVR_NOISEREMOVE struNoiseRemove = new NET_DVR_NOISEREMOVE();/*数字降噪*/ + public byte byPowerLineFrequencyMode; /*0-50HZ; 1-60HZ*/ + /* + 0-自动光圈, + 1-手动光圈, + 2-P-Iris1, + 3-Union 3-9mm F1.6-2.7 (T5280-PQ1) [IPC5.1.7] + 4-Union 2.8-12mm F1.6-2.7 (T5289-PQ1) [IPC5.1.7] + 5-HIK 3.8-16mm F1.5(HV3816P-8MPIR) + 6-HIK 11-40mm F1.7 (HV1140P-8MPIR) + 7-HIK 2.7-12mm F1.2(TV2712P-MPIR) + */ + public byte byIrisMode; + public byte byMirror; /* 镜像:0 off,1- leftright,2- updown,3-center 4-Auto*/ + public byte byDigitalZoom; /*数字缩放:0 dsibale 1 enable*/ + public byte byDeadPixelDetect; /*坏点检测,0 dsibale 1 enable*/ + public byte byBlackPwl;/*黑电平补偿 , 0-255*/ + public byte byEptzGate;// EPTZ开关变量:0-不启用电子云台,1-启用电子云台 + public byte byLocalOutputGate;//本地输出开关变量0-本地输出关闭1-本地BNC输出打开 2-HDMI输出关闭 + //20-HDMI_720P50输出开 + //21-HDMI_720P60输出开 + //22-HDMI_1080I60输出开 + //23-HDMI_1080I50输出开 + //24-HDMI_1080P24输出开 + //25-HDMI_1080P25输出开 + //26-HDMI_1080P30输出开 + //27-HDMI_1080P50输出开 + //28-HDMI_1080P60输出开 + public byte byCoderOutputMode;//编码器fpga输出模式0直通3像素搬家 + public byte byLineCoding; //是否开启行编码:0-否,1-是 + public byte byDimmerMode; //调光模式:0-半自动,1-自动 + public byte byPaletteMode; //调色板:0-白热,1-黑热,2-调色板2,…,8-调色板8, 9-融合1,10-彩虹,11-融合2,12-铁红1,13-铁红2,14-深褐色,15-色彩1,16-色彩2,17-冰火,18-雨,19-红热,20-绿热,21-深蓝,22-色彩3 + public byte byEnhancedMode; //增强方式(探测物体周边):0-不增强,1-1,2-2,3-3,4-4 + public byte byDynamicContrastEN; //动态对比度增强 0-1 + public byte byDynamicContrast; //动态对比度 0-100 + public byte byJPEGQuality; //JPEG图像质量 0-100 + public NET_DVR_CMOSMODECFG struCmosModeCfg = new NET_DVR_CMOSMODECFG();//CMOS模式下前端参数配置,镜头模式从能力集获取 + public byte byFilterSwitch; //滤波开关:0-不启用,1-启用 + public byte byFocusSpeed; //镜头调焦速度:0-10 + public byte byAutoCompensationInterval; //定时自动快门补偿:1-120,单位:分钟 + public byte bySceneMode; //场景模式:0-室外,1-室内,2-默认,3-弱光 + public NET_DVR_DEFOGCFG struDefogCfg = new NET_DVR_DEFOGCFG();//透雾参数 + public NET_DVR_ELECTRONICSTABILIZATION struElectronicStabilization = new NET_DVR_ELECTRONICSTABILIZATION();//电子防抖 + public NET_DVR_CORRIDOR_MODE_CCD struCorridorMode = new NET_DVR_CORRIDOR_MODE_CCD();//走廊模式 + public byte byExposureSegmentEnable; //0~不启用,1~启用 曝光时间和增益呈阶梯状调整,比如曝光往上调整时,先提高曝光时间到中间值,然后提高增益到中间值,再提高曝光到最大值,最后提高增益到最大值 + public byte byBrightCompensate;//亮度增强 [0~100] + /* + 0-关闭、1-640*480@25fps、2-640*480@30ps、3-704*576@25fps、4-704*480@30fps、5-1280*720@25fps、6-1280*720@30fps、 + 7-1280*720@50fps、8-1280*720@60fps、9-1280*960@15fps、10-1280*960@25fps、11-1280*960@30fps、 + 12-1280*1024@25fps、13--1280*1024@30fps、14-1600*900@15fps、15-1600*1200@15fps、16-1920*1080@15fps、 + 17-1920*1080@25fps、18-1920*1080@30fps、19-1920*1080@50fps、20-1920*1080@60fps、21-2048*1536@15fps、22-2048*1536@20fps、 + 23-2048*1536@24fps、24-2048*1536@25fps、25-2048*1536@30fps、26-2560*2048@25fps、27-2560*2048@30fps、 + 28-2560*1920@7.5fps、29-3072*2048@25fps、30-3072*2048@30fps、31-2048*1536@12.5、32-2560*1920@6.25、 + 33-1600*1200@25、34-1600*1200@30、35-1600*1200@12.5、36-1600*900@12.5、37-1280*960@12.5fps、38-800*600@25fps、39-800*600@30fps40、 + 4000*3000@12.5fps、41-4000*3000@15fps、42-4096*2160@20fps、43-3840*2160@20fps 、44-960*576@25fps、45-960*480@30fps、46-752*582@25fps、 + 47-768*494@30fps、48-2560*1440@25fps、49-2560*1440@30fps 、50-720P@100fps、51-720P@120fps、52-2048*1536@50fps、53-2048*1536@60fps、 + 54-3840*2160@25fps、55-3840*2160@30fps、56-4096*2160@25fps、57-4096*2160@30fps 、58-1280*1024@50fps、59-1280*1024@60fps、 + 60-3072*2048@50fps、61-3072*2048@60fps、62-3072*1728@25fps、63-3072*1728@30fps、64-3072*1728@50fps、65-3072*1728@60fps、66-336*256@50fps、67-336*256@60fps、 + 68-384*288@50fps、69-384*288@60fps 、70- 640 * 512@50fps 、71- 640 * 512@60fps、72-2592*1944@25fps、73-2592*1944@30fps、74-2688*1536@25fps、75-2688*1536@30fps + 76-2592*1944@20fps、77-2592*1944@15fps、78-2688*1520@20fps、79-2688*1520@15fps、80-2688*1520@25fps、81-2688*1520@30fps、82- 2720*2048@25fps、 83- 2720*2048@30fps、 + 84-336*256@25fps、85- 384*288@25fps、86-640*512@25fps、87-1280*960@50fps、88-1280*960@60fps、89-1280*960@100fps、90-1280*960@120fps、91-4000*3000@20fps、 + 92-1920*1200@25fps、93-1920*1200@30fps、94-2560*1920@25fps、95-2560*1920@20fps、96-2560*1920@30fps、97-1280*1920@25fps、98-1280*1920@30fps + 99-4000*3000@24fps、100-4000*3000@25fps、101-4000*3000@10fps、102- 384*288@30fps、103-2560*1920@15fps、104-2400*3840@25fps、105-1200*1920@25fps + 106-4096*1800@30fps、107-3840*1680@30fps、108-2560*1120@30fps、109-704*320@30fps、110-1280*560@30fps、111-4096*1800@25fps、112-3840*1680@25fps + 113-2560*1120@25fps、114-704*320@25fps、115-1280*560@25fps、116-2400*3840@24fps、117-3840*2400@24fps、118-3840*2400@25fps、119-2560*1920@12.5fps + 120-2560*2048@12fps、121-2560*2048@15fps、122-2560*1536@25fps、123-2560*1536@30fps、124-2256*2048@25fps、125-2256*2048@30fps、126-2592*2592@12.5fps、127-2592*2592@15fps、 + 128 - 640*512@30fps、129-2048*1520@30fps、130-2048*1520@25fps、131-3840*2160@24fps、132-2592*1520@25fps、133-2592*1520@30fps、134-2592*1536@25fps、135-2592*1536@30fps + 136-640*960@25fps、137-640*960@24fps、142-2992*2192@25fps、143-2992*2192@30fps、144-3008*2160@25fps、145-3008*2160@30fps、146-3072*1728@20fps、147-2560*1440@20fps、 + 148-2160*3840@25fps、149-2160*3840@30fps、150-7008*1080@25fps、151-7008*1080@30fps、152-3072*2048@20fps、153-1536*864@25fps、154-2560*1920@24fps、155-2400*3840@30fps、 + 156-3840*2400@30fps、157-3840*2160@15fps + 158-384*288@8.3fps、159-640*512@8.3fps、160-160*120@8.3fps、161-1024*768@8.3fps、162-640*480@8.3fps、163-3840*2160@12.5fps、164-2304*1296@30fps、165-2304*1296@25fps、 + 166-2560*1440@24fps、167-2688*1512@25fps、168-2688*1512@30fps、169-2688*1512@50fps、170-2688*1512@60fps、171-1536*864@30fps、172-2560*1440@50fps、173-2560*1440@60fps、 + 174-2048*2048@25fps、175-2048*2048@30fps、176-4000*3060@20fps、177-3060*3060@25fps、178-3060*3060@30fps、179-3000*3000@25fps、180-3000*3000@30fps、181-8160*3616@30fps、 + 182-8160*3616@25fps、183-3000*3000@20fps、184-3000*3000@15fps、185-3000*3000@12.5fps、186-5472*3648@25fps、187-5472*3648@30fps、188-7680*4320@25fps、189-7680*4320@30fps、 + 190-8160*2400@25fps、191-8160*2400@30fps、192-5520*2400@25fps、193-5520*2400@30fps、194-2560*1440@15fps、195-1944*1212@24fps、196-1944*1212@25fps、197-3456*1920@30fps、 + 198-4800*2688@25fps、199-4800*2688@30fps、200-6480*1080@25fps、201-6480*1080@30fps、202-8640*1440@25fps、203-8640*1440@30fps、204-3456*1920@25fps、205-2688*1520@50fps、 + 206-2688*1520@60fps、207-4976*1452@25fps、208-4976*1452@30fps、 209-3200*1800@25fps、210-3200*1800@30fps、211-5472*3648@24fps、212-1920*1080@12.5fps、213-2944*1656@20fps、 + 214-1920*1080@24fps、215-4800*1600@25fps、216-4800*1600@30fps、217-2560*1440@12.5fps、218-6560*3690@1fps、219-5120*1400@20fps*/ + public byte byCaptureModeN; //视频输入模式(N制) + public byte byCaptureModeP; //视频输入模式(P制) + public NET_DVR_SMARTIR_PARAM struSmartIRParam = new NET_DVR_SMARTIR_PARAM(); //红外放过爆配置信息 + public NET_DVR_PIRIS_PARAM struPIrisParam = new NET_DVR_PIRIS_PARAM();//PIris配置信息对应byIrisMode字段从2-PIris1开始生效 + //2014-02-25 新增参数 + public NET_DVR_LASER_PARAM_CFG struLaserParam = new NET_DVR_LASER_PARAM_CFG(); //激光参数 + public NET_DVR_FFC_PARAM struFFCParam = new NET_DVR_FFC_PARAM(); + public NET_DVR_DDE_PARAM struDDEParam = new NET_DVR_DDE_PARAM(); + public NET_DVR_AGC_PARAM struAGCParam = new NET_DVR_AGC_PARAM(); + public byte byLensDistortionCorrection;//镜头畸变校正 0-关闭,1-开启 + public byte byDistortionCorrectionLevel;//畸变校正等级:0-保留;1-等级一;2-等级二;3-等级三;255-自定义 + public byte byCalibrationAccurateLevel;// 畸变校正强度[0-100] + public byte byZoomedInDistantViewLevel;//远端放大等级[0-100] + public NET_DVR_SNAP_CAMERAPARAMCFG struSnapCCD = new NET_DVR_SNAP_CAMERAPARAMCFG(); //抓拍机CCD参数,只用于抓拍机 + public NET_DVR_OPTICAL_DEHAZE struOpticalDehaze = new NET_DVR_OPTICAL_DEHAZE();//光学透雾参数 + public NET_DVR_THERMOMETRY_AGC struThermAGC = new NET_DVR_THERMOMETRY_AGC();//测温AGC配置 + public byte byFusionMode;//双光谱视频融合模式,0~热成像模式,1~融合模式,2~画中画模式,3~可见光模式, 4~融合黑白模式, 5~融合彩色模式-草地,6~融合彩色模式-荒地,7~融合彩色模式-雪地,8~融合彩色模式-海洋,9~融合彩色模式-城市 + public byte byHorizontalFOV;//水平视场角[0-100] + public byte byVerticalFOV;//垂直视场角[0-100] + public byte byBrightnessSuddenChangeSuppression;//亮度突变抑制0-关闭,1-开启 + public byte byGPSEnabled;//GPS开关使能,0-关,1-开 + public byte[] byRes2 = new byte[155]; + } + + + public static class NET_DVR_VIDEOEFFECT extends HIKSDKStructure { + public byte byBrightnessLevel; /*0-100*/ + public byte byContrastLevel; /*0-100*/ + public byte bySharpnessLevel; /*0-100*/ + public byte bySaturationLevel; /*0-100*/ + public byte byHueLevel; /*0-100,(保留)*/ + public byte byEnableFunc; //使能,按位表示,bit0-SMART IR(防过曝),bit1-低照度,bit2-强光抑制使能,0-否,1-是 + public byte byLightInhibitLevel; //强光抑制等级,[1-3]表示等级 + public byte byGrayLevel; //灰度值域,0-[0-255],1-[16-235] + } + + + public static class NET_DVR_GAIN extends HIKSDKStructure { + public byte byGainLevel; /*增益:0-100*/ + public byte byGainUserSet; /*用户自定义增益;0-100,对于抓拍机,是CCD模式下的抓拍增益*/ + public byte[] byRes = new byte[2]; + public int dwMaxGainValue;/*最大增益值,单位dB*/ + } + + public static class NET_DVR_WHITEBALANCE extends HIKSDKStructure { + public byte byWhiteBalanceMode; /*0-手动白平衡(MWB),1-自动白平衡1(AWB1),2-自动白平衡2 (AWB2),3-自动控制改名为锁定白平衡(Locked WB), + 4-室外(Indoor),5-室内(Outdoor)6-日光灯(Fluorescent Lamp),7-钠灯(Sodium Lamp), + 8-自动(Auto-Track)9-一次白平衡(One Push),10-室外自动(Auto-Outdoor), + 11-钠灯自动 (Auto-Sodiumlight),12-水银灯(Mercury Lamp),13-自动白平衡(Auto), +14-白炽灯 (IncandescentLamp),15-暖光灯(Warm Light Lamp),16-自然光(Natural Light) */ + public byte byWhiteBalanceModeRGain; /*手动白平衡时有效,手动白平衡 R增益*/ + public byte byWhiteBalanceModeBGain; /*手动白平衡时有效,手动白平衡 B增益*/ + public byte[] byRes = new byte[5]; + } + + public static class NET_DVR_EXPOSURE extends HIKSDKStructure { + public byte byExposureMode; /*0 手动曝光 1自动曝光*/ + public byte byAutoApertureLevel; /* 自动光圈灵敏度, 0-10 */ + public byte[] byRes = new byte[2]; + public int dwVideoExposureSet; /* 自定义视频曝光时间(单位us)*//*注:自动曝光时该值为曝光最慢值 新增20-1s(1000000us)*/ + public int dwExposureUserSet; /* 自定义曝光时间,在抓拍机上应用时,CCD模式时是抓拍快门速度*/ + public int dwRes; + } + + public static class NET_DVR_GAMMACORRECT extends HIKSDKStructure { + public byte byGammaCorrectionEnabled; /*0 dsibale 1 enable*/ + public byte byGammaCorrectionLevel; /*0-100*/ + public byte[] byRes = new byte[6]; + } + + + public static class NET_DVR_WDR extends HIKSDKStructure { + public byte byWDREnabled; /*宽动态:0 dsibale 1 enable 2 auto*/ + public byte byWDRLevel1; /*0-F*/ + public byte byWDRLevel2; /*0-F*/ + public byte byWDRContrastLevel; /*0-100*/ + public byte[] byRes = new byte[16]; + } + + public static class NET_DVR_DAYNIGHT extends HIKSDKStructure { + public byte byDayNightFilterType; /*日夜切换:0-白天,1-夜晚,2-自动,3-定时,4-报警输入触发, 5-自动模式2(无光敏),6-黑光,7-黑光自动,8-黑光定时*/ + public byte bySwitchScheduleEnabled; /*0 dsibale 1 enable,(保留)*/ + //定时模式参数 + public byte byBeginTime; /*开始时间(小时),0-23*/ + public byte byEndTime; /*结束时间(小时),0-23*/ + //模式2 + public byte byDayToNightFilterLevel; //0-7 + public byte byNightToDayFilterLevel; //0-7 + public byte byDayNightFilterTime;//(60秒) + //定时模式参数 + public byte byBeginTimeMin; //开始时间(分),0-59 + public byte byBeginTimeSec; //开始时间(秒),0-59 + public byte byEndTimeMin; //结束时间(分),0-59 + public byte byEndTimeSec; //结束时间(秒),0-59 + //报警输入触发模式参数 + public byte byAlarmTrigState; //报警输入触发状态,0-白天,1-夜晚 + } + + public static class NET_DVR_BACKLIGHT extends HIKSDKStructure { + public byte byBacklightMode; /*背光补偿:0 off 1 UP、2 DOWN、3 LEFT、4 RIGHT、5MIDDLE、6自定义,10-开,11-自动,12-多区域背光补偿*/ + public byte byBacklightLevel; /*0x0-0xF*/ + public byte[] byRes1 = new byte[2]; + public int dwPositionX1; //(X坐标1) + public int dwPositionY1; //(Y坐标1) + public int dwPositionX2; //(X坐标2) + public int dwPositionY2; //(Y坐标2) + public byte[] byRes2 = new byte[4]; + } + + + public static class NET_DVR_NOISEREMOVE extends HIKSDKStructure { + public byte byDigitalNoiseRemoveEnable; /*0-不启用,1-普通模式数字降噪,2-专家模式数字降噪*/ + public byte byDigitalNoiseRemoveLevel; /*普通模式数字降噪级别:0x0-0xF*/ + public byte bySpectralLevel; /*专家模式下空域强度:0-100*/ + public byte byTemporalLevel; /*专家模式下时域强度:0-100*/ + public byte byDigitalNoiseRemove2DEnable; /* 抓拍帧2D降噪,0-不启用,1-启用 */ + public byte byDigitalNoiseRemove2DLevel; /* 抓拍帧2D降噪级别,0-100 */ + public byte[] byRes = new byte[2]; + } + + + public static class NET_DVR_CMOSMODECFG extends HIKSDKStructure { + public byte byCaptureMod; //抓拍模式:0-抓拍模式1;1-抓拍模式2 + public byte byBrightnessGate;//亮度阈值 + public byte byCaptureGain1; //抓拍增益1,0-100 + public byte byCaptureGain2; //抓拍增益2,0-100 + public int dwCaptureShutterSpeed1;//抓拍快门速度1 + public int dwCaptureShutterSpeed2;//抓拍快门速度2 + public byte[] byRes = new byte[4]; + } + + public static class NET_DVR_DEFOGCFG extends HIKSDKStructure { + public byte byMode; //模式,0-不启用,1-自动模式,2-常开模式 + public byte byLevel; //等级,0-100 + public byte[] byRes = new byte[6]; + } + + public static class NET_DVR_CMOSMODCFG extends HIKSDKStructure { + public byte byCaptureMod; //抓拍模式:0-抓拍模式1;1-抓拍模式2 + public byte byBrightnessGate;//亮度阈值 + public byte byCaptureGain1; //抓拍增益1,0-100 + public byte byCaptureGain2; //抓拍增益2,0-100 + public int dwCaptureShutterSpeed1;//抓拍快门速度1 + public int dwCaptureShutterSpeed2;//抓拍快门速度2 + public byte[] byRes = new byte[4]; + } + + public static class NET_DVR_ELECTRONICSTABILIZATION extends HIKSDKStructure { + public byte byEnable;//使能 0- 不启用,1- 启用 + public byte byLevel; //等级,0-100 + public byte[] byRes = new byte[6]; + } + + public static class NET_DVR_CORRIDOR_MODE_CCD extends HIKSDKStructure { + public byte byEnableCorridorMode; //是否启用走廊模式 0~不启用, 1~启用 + public byte[] byRes = new byte[11]; + } + + public static class NET_DVR_SMARTIR_PARAM extends HIKSDKStructure { + public byte byMode;//0~手动,1~自动 + public byte byIRDistance;//红外距离等级(等级,距离正比例)level:1~100 默认:50(手动模式下增加) + public byte byShortIRDistance;// 近光灯距离等级(1~100) + public byte byLongIRDistance;// 远光灯距离等级(1~100) + } + + public static class NET_DVR_PIRIS_PARAM extends HIKSDKStructure { + public byte byMode;//0-自动,1-手动 + public byte byPIrisAperture;//红外光圈大小等级(等级,光圈大小正比例)level:1~100 默认:50(手动模式下增加) + public byte[] byRes = new byte[6]; + } + + public static class NET_DVR_LASER_PARAM_CFG extends HIKSDKStructure { + public byte byControlMode; //控制模式 0-无效,1-自动,2-手动 默认自动 + public byte bySensitivity; //激光灯灵敏度 0-100 默认50 + public byte byTriggerMode; //激光灯触发模式 0-无效,1-机芯触发,2-光敏触发 默认机芯触发 + public byte byBrightness; //控制模式为手动模式下有效;激光灯亮度 0-255 默认100 + public byte byAngle; //激光灯角度 0-无效,范围1-36 默认12,激光灯照射范围为一个圆圈,调节激光角度是调节这个圆的半径的大小 + public byte byLimitBrightness; //控制模式为自动模式下有效;激光灯亮度限制 0~100 (新增)2014-01-26 + public byte byEnabled; //手动控制激光灯使能 0-关闭,1-启动 + public byte byIllumination; //激光灯强度配置0~100 + public byte byLightAngle; //补光角度 0~100 + public byte[] byRes = new byte[7]; //保留 + } + + public static class NET_DVR_FFC_PARAM extends HIKSDKStructure { + //1-Schedule Mode,2-Temperature Mode, 3-Off + public byte byMode; + //(时间:按能力显示,单位分钟,选项有10,20,30,40,50,60,120,180,240) + public byte byRes1; + public short wCompensateTime; //定时模式下生效 + public byte[] byRes2 = new byte[4]; + } + + public static class NET_DVR_DDE_PARAM extends HIKSDKStructure { + public byte byMode;//1-Off,2-Normal Mode,3-Expert Mode + public byte byNormalLevel;//普通模式等级范围[1,100],普通模式下生效 + public byte byExpertLevel;//专家模式等级范围[1,100],专家模式下生效 + public byte[] byRes = new byte[5]; + } + + public static class NET_DVR_AGC_PARAM extends HIKSDKStructure { + public byte bySceneType;//1-Normal Sence,2-Highlight Sence,3-Manual Sence + public byte byLightLevel;//亮度等级[1,100];手动模式下生效 + public byte byGainLevel; //增益等级[1,100];手动模式下生效 + public byte[] byRes = new byte[5]; + } + + public static class NET_DVR_SNAP_CAMERAPARAMCFG extends HIKSDKStructure { + public byte byWDRMode; // 宽动态模式;0~关闭,1~数字宽动态 2~宽动态 + public byte byWDRType; // 宽动态切换模式; 0~强制启用,1~按时间启用,2~按亮度启用 + public byte byWDRLevel; // 宽动态等级,0~6索引对应1-7,默认索引2(即3级); + public byte byRes1; + public NET_DVR_TIME_EX struStartTime = new NET_DVR_TIME_EX(); //开始宽动态时间 + public NET_DVR_TIME_EX struEndTime = new NET_DVR_TIME_EX(); //结束宽动态时间 + public byte byDayNightBrightness; //日夜转换亮度阈值,0-100,默认50; + //记忆色增强 + public byte byMCEEnabled;//记忆色增强使能,true:开启,false:关闭 + public byte byMCELevel;//记忆色增强强度,0~100,默认值50 + //自动对比度 + public byte byAutoContrastEnabled;//自动对比度使能,true:开启,false:关闭 + public byte byAutoContrastLevel;//自动对比等级(0-100),默认50 + //细节增强 + public byte byLSEDetailEnabled;//细节增强使能,true:开启,false:关闭 + public byte byLSEDetailLevel;//细节增强等级(0-100),默认50 + // License Plate Definition Enhancement车牌增强 + public byte byLPDEEnabled;//车牌增强使能,true:开启,false:关闭 + public byte byLPDELevel;//车牌增强等级(0-100),默认50 + //对比度增强 + public byte byLseEnabled; //对比度增强使能,true:开启,false:关闭 + public byte byLseLevel; //对比度增强等级(0-100),默认0 + public byte byLSEHaloLevel;//光晕抑制等级。范围 0-100,默认0 + public byte byLseType; //对比度增强切换模式; 0~强制启用,1~按时间启用,2~按亮度启用(该字段可同时控制byLseLevel、byLSEHaloLevel两个参数) + public byte[] byRes2 = new byte[3]; + public NET_DVR_TIME_EX struLSEStartTime = new NET_DVR_TIME_EX(); //开始对比度增强时间(当byLseType为1时生效) + public NET_DVR_TIME_EX struLSEEndTime = new NET_DVR_TIME_EX(); //结束对比度增强时间(当byLseType为1时生效) + public byte byLightLevel;//为亮度等级参数(0-100),默认0,(当byLseType为2时生效) + //车牌对比度 + public byte byPlateContrastLevel;//车牌对比度等级,0~100,默认0 + //车牌饱和度 + public byte byPlateSaturationLevel;//车牌饱和度等级,0~100,默认0 + public byte[] byRes = new byte[9]; + } + + public static class NET_DVR_OPTICAL_DEHAZE extends HIKSDKStructure { + public byte byEnable; //0~不启用光学透雾,1~启用光学透雾 + public byte[] byRes = new byte[7]; + } + + public static class NET_DVR_THERMOMETRY_AGC extends HIKSDKStructure { + public byte byMode;//AGC模式,0~无效,1~自动,2~手动 + public byte byRes1[] = new byte[3]; + public int iHighTemperature;//最高温度,范围为:-273~9999摄氏度(1~手动模式下生效) + public int iLowTemperature;//最低温度,范围为:-273~9999摄氏度(1~手动模式下生效) + public byte[] byRes = new byte[8]; + } + + public static class NET_DVR_CHECK_DEV_STATE extends HIKSDKStructure { + public int dwTimeout; //定时检测设备工作状态,单位ms,为0时,表示使用默认值(30000)。最小值为1000 + public DEV_WORK_STATE_CB fnStateCB; + Pointer pUserData; + public byte[] byRes = new byte[60]; + } + + public static class NET_DVR_FLOW_INFO extends HIKSDKStructure { + public int dwSize; //结构大小 + public int dwSendFlowSize; //发送流量大小,单位kbps + public int dwRecvFlowSize; //接收流量大小,单位kbps + public byte[] byRes = new byte[20]; //保留 + } + + public static class NET_DVR_AES_KEY_INFO extends HIKSDKStructure { + public byte[] sAESKey = new byte[16]; /*码流加密密钥*/ + public byte[] byRes = new byte[64]; /*保留字节*/ + } + + public static class NET_DVR_ALARM_RS485CFG extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public byte[] sDeviceName = new byte[NAME_LEN]; // 前端设备名称 + public short wDeviceType; // 前端设备类型,通过NET_DVR_GetDeviceTypeList获取 + public short wDeviceProtocol; // 前端设备协议 通过获取协议列表获取 + public int dwBaudRate; //波特率(bps),0-50,1-75,2-110,3-150,4-300,5-600,6-1200,7-2400,8-4800,9-9600,10-19200,11-38400,12-57600,13-76800,14-115.2k + public byte byDataBit; // 数据有几位:0-5位,1-6位,2-7位,3-8位 + public byte byStopBit; // 停止位:0-1位,1-2位 + public byte byParity; //是否校验:0-无校验,1-奇校验,2-偶校验 + public byte byFlowcontrol; // 是否流控:0-无,1-软流控,2-硬流控 + public byte byDuplex; // 0 - 半双工1- 全双工 只有通道1可以是全双工其他都只能是半双工 + public byte byWorkMode; // 工作模式 0-控制台 1-透明通道,2-梯控,3-读卡器,4-门禁安全模块,0xfe-自定义,0xff-禁用 + public byte byChannel; //485通道号 + public byte bySerialType; //串口类型: 0--485, 1--232 + public byte byMode; //模式 0-连接读卡器 1-连接客户端 2-连接扩展模块 3-连接门禁主机 4-连接梯控主机 0xff-禁用 + public byte byOutputDataType; //0-无效,1-输出卡号,2-输出工号 + public byte byAddress; //串口地址 + public byte[] byRes = new byte[33]; // 保留字节 + } + + public static class NET_DVR_ALARMHOST_RS485_SLOT_CFG extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public byte[] sDeviceName = new byte[NAME_LEN]; // 前端设备名称 + public short wDeviceType; // 前端设备类型ALARM_FRONT_DEVICE _TYPE + public byte wDeviceProtocol; // 前端设备协议 通过获取协议列表获取 + public short wAddress; //设备地址 + public byte byChannel; //485通道号 + public byte bySlotChan; //槽位号 + public byte[] byRes = new byte[60]; // 保留字节 + } + + + public static class NET_DVR_VIDEOWALLDISPLAYPOSITION extends HIKSDKStructure { + public int dwSize; + public byte byEnable; + public byte byCoordinateType;//坐标类型。0-基准坐标,1-实际坐标 + public byte[] byRes1 = new byte[2]; + //墙号,1字节墙号(高字节,对于合码器设备,为合码通道号)+3字节保留 + public int dwVideoWallNo; + public int dwDisplayNo;//显示输出号 + //坐标须为基准坐标的整数倍(1920*1920),宽度和高度值不用设置,即为基准值 + public NET_DVR_RECTCFG_EX struRectCfg; + public byte[] byRes2 = new byte[64]; + } + + public static final int MAX_DISPLAY_NUM = 512; //最大显示输出个数 + + public static class NET_DVR_DISPLAYCFG extends HIKSDKStructure { + public int dwSize; + public NET_DVR_DISPLAYPARAM[] struDisplayParam = new NET_DVR_DISPLAYPARAM[MAX_DISPLAY_NUM]; + public byte[] byRes2 = new byte[128]; + } + + public static class NET_DVR_DISPLAYPARAM extends HIKSDKStructure { + public int dwDisplayNo; + public byte byDispChanType; + public byte[] byRes = new byte[11]; + } + + public static class NET_DVR_WALLOUTPUTPARAM extends HIKSDKStructure { + public int dwSize; + public int dwResolution; //分辨率 + public NET_DVR_VIDEOEFFECT struRes; + public byte byVideoFormat; //视频制式,见VIDEO_STANDARD + public byte byDisplayMode;/*输出连接模式,1-BNC,2-VGA,3-HDMI,4-DVI,5-SDI, 6-FIBER, 7-RGB, 8-YPrPb, 9-VGA/HDMI/DVI自适应,0xff-无效*/ + public byte byBackgroundColor; //背景色,0-无效,不支持背景色,1-红,2-绿,3-蓝,4-黄,5-紫,6-青,7-黑,8-白,0xff-自定义 + public byte byUseEDIDResolution; //是否使用EDID分辨率,0-不使用,1-使用 + public short wLEDWidth; //LED屏输出分辨率宽 + public short wLEDHeight; //LED屏输出分辨率高 + public NET_DVR_RGB_COLOR struBackColor;//背景色,byBackgroundColor为0xff时有效 + public byte byLinkStatus;//输出口连接状态,0-无效,1-接入显示器,2-未接入显示器 + public byte[] byRes2 = new byte[51]; + } + + public static class WALLOUTPUTPARAM_ARRAY extends HIKSDKStructure { + public NET_DVR_WALLOUTPUTPARAM[] strWalloutputParm; + + public WALLOUTPUTPARAM_ARRAY(int iLen) { + strWalloutputParm = new NET_DVR_WALLOUTPUTPARAM[iLen]; + } + + } + + public static class NET_DVR_VIDEO_CALL_COND extends HIKSDKStructure { + public int dwSize; + public byte[] byRes=new byte[128]; + } + + + /*** + * API函数声明,详细说明见API手册 + ***/ + public static interface FRealDataCallBack_V30 extends Callback { + public void invoke(int lRealHandle, int dwDataType, + Pointer pBuffer, int dwBufSize, Pointer pUser); + } + + public static interface FMSGCallBack extends Callback { + public void invoke(int lCommand, NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser); + } + + public static interface FMSGCallBack_V31 extends Callback { + public boolean invoke(int lCommand, NET_DVR_ALARMER pAlarmer, Pointer pAlarmInfo, int dwBufLen, Pointer pUser); + } + + public static interface FMessCallBack extends Callback { + public boolean invoke(int lCommand, String sDVRIP, String pBuf, int dwBufLen); + } + + public static interface FMessCallBack_EX extends Callback { + public boolean invoke(int lCommand, int lUserID, String pBuf, int dwBufLen); + } + + public static interface FMessCallBack_NEW extends Callback { + public boolean invoke(int lCommand, String sDVRIP, String pBuf, int dwBufLen, short dwLinkDVRPort); + } + + public static interface FMessageCallBack extends Callback { + public boolean invoke(int lCommand, String sDVRIP, String pBuf, int dwBufLen, int dwUser); + } + + public static interface FExceptionCallBack extends Callback { + public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser); + } + + public static interface FDrawFun extends Callback { + public void invoke(int lRealHandle, W32API.HDC hDc, int dwUser); + } + + public static interface FStdDataCallBack extends Callback { + public void invoke(int lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, int dwUser); + } + + public static interface FPlayDataCallBack extends Callback { + public void invoke(int lPlayHandle, int dwDataType, Pointer pBuffer, int dwBufSize, int dwUser); + } + public static interface FPlayESCallBack extends Callback { + public void invoke(int lPlayHandle, NET_DVR_PACKET_INFO_EX struPackInfo, Pointer pUser); + } + + public static interface FVoiceDataCallBack extends Callback { + public void invoke(int lVoiceComHandle, Pointer pRecvDataBuffer, int dwBufSize, byte byAudioFlag, int dwUser); + } + + public static interface FVoiceDataCallBack_V30 extends Callback { + public void invoke(int lVoiceComHandle, Pointer pRecvDataBuffer, int dwBufSize, byte byAudioFlag, int pUser); + } + + public static interface FVoiceDataCallBack_MR extends Callback { + public void invoke(int lVoiceComHandle, Pointer pRecvDataBuffer, int dwBufSize, byte byAudioFlag, int dwUser); + } + + public static interface FVoiceDataCallback_MR_V30 extends Callback { + public void invoke(int lVoiceComHandle, Pointer pRecvDataBuffer, int dwBufSize, byte byAudioFlag, Pointer pUser); + } + + public static interface FVoiceDataCallBack2 extends Callback { + public void invoke(String pRecvDataBuffer, int dwBufSize, Pointer pUser); + } + + public static interface FSerialDataCallBack extends Callback { + public void invoke(int lSerialHandle, String pRecvDataBuffer, int dwBufSize, int dwUser); + } + + public static interface FRowDataCallBack extends Callback { + public void invoke(int lUserID, String sIPAddr, int lRowAmout, String pRecvDataBuffer, int dwBufSize, int dwUser); + } + + public static interface FColLocalDataCallBack extends Callback { + public void invoke(int lUserID, String sIPAddr, int lColumnAmout, String pRecvDataBuffer, int dwBufSize, int dwUser); + } + + public static interface FColGlobalDataCallBack extends Callback { + public void invoke(int lUserID, String sIPAddr, int lColumnAmout, String pRecvDataBuffer, int dwBufSize, int dwUser); + } + + public static interface FJpegdataCallBack extends Callback { + public int invoke(int lCommand, int lUserID, String sDVRIP, String sJpegName, String pJpegBuf, int dwBufLen, int dwUser); + } + + public static interface FPostMessageCallBack extends Callback { + public int invoke(int dwType, int lIndex); + } + + public static interface DEV_WORK_STATE_CB extends Callback { + public boolean invoke(Pointer pUserdata, int iUserID, NET_DVR_WORKSTATE_V40 lpWorkState); + } + + public static interface FLOWTESTCALLBACK extends Callback { + public void invoke(int lFlowHandle, NET_DVR_FLOW_INFO pFlowInfo, + Pointer pUser); + } + + + boolean NET_DVR_Init(); + + boolean NET_DVR_Cleanup(); + + boolean NET_DVR_SetSDKInitCfg(int enumType, Pointer lpInBuff); + + boolean NET_DVR_SetSDKLocalCfg(int enumType, Pointer lpInBuff); + + boolean NET_DVR_GetSDKLocalCfg(int enumType, Pointer lpOutBuff); + + boolean NET_DVR_SetDVRMessage(int nMessage, int hWnd); + + //NET_DVR_SetDVRMessage的扩展 + boolean NET_DVR_SetExceptionCallBack_V30(int nMessage, int hWnd, FExceptionCallBack fExceptionCallBack, Pointer pUser); + + boolean NET_DVR_SetDVRMessCallBack(FMessCallBack fMessCallBack); + + boolean NET_DVR_SetDVRMessCallBack_EX(FMessCallBack_EX fMessCallBack_EX); + + + //2007-04-16增加查询结果带卡号的文件查找 + int NET_DVR_FindNextFile_Card(int lFindHandle, NET_DVR_FINDDATA_CARD lpFindData); + + int NET_DVR_FindFile_Card(int lUserID, int lChannel, int dwFileType, NET_DVR_TIME lpStartTime, NET_DVR_TIME lpStopTime); + + boolean NET_DVR_LockFileByName(int lUserID, String sLockFileName); + + boolean NET_DVR_UnlockFileByName(int lUserID, String sUnlockFileName); + + int NET_DVR_PlayBackByName(int lUserID, String sPlayBackFileName, HWND hWnd); + + int NET_DVR_PlayBackByTime(int lUserID, int lChannel, NET_DVR_TIME lpStartTime, NET_DVR_TIME lpStopTime, HWND hWnd); + + int NET_DVR_PlayBackByTime_V40(int lUserID, NET_DVR_VOD_PARA pVodPara); + + boolean NET_DVR_PlayBackControl(int lPlayHandle, int dwControlCode, int dwInValue, IntByReference LPOutValue); + + boolean NET_DVR_PlayBackControl_V40(int lPlayHandle, int dwControlCode, Pointer lpInBuffer, int dwInLen, Pointer lpOutBuffer, IntByReference lpOutLen); + + boolean NET_DVR_StopPlayBack(int lPlayHandle); + + boolean NET_DVR_SetPlayDataCallBack(int lPlayHandle, FPlayDataCallBack fPlayDataCallBack, int dwUser); + boolean NET_DVR_SetPlayDataCallBack_V40(int lPlayHandle, FPlayDataCallBack fPlayDataCallBack, Pointer dwUser); + boolean NET_DVR_SetPlayBackESCallBack(int lPlayHandle, FPlayESCallBack fPlayESCallBack, Pointer pUser); + + boolean NET_DVR_PlayBackSaveData(int lPlayHandle, String sFileName); + + boolean NET_DVR_StopPlayBackSave(int lPlayHandle); + + boolean NET_DVR_GetPlayBackOsdTime(int lPlayHandle, NET_DVR_TIME lpOsdTime); + + boolean NET_DVR_PlayBackCaptureFile(int lPlayHandle, String sFileName); + + int NET_DVR_GetFileByName(int lUserID, String sDVRFileName, byte[] sSavedFileName); + + int NET_DVR_GetFileByTime(int lUserID, int lChannel, NET_DVR_TIME lpStartTime, NET_DVR_TIME lpStopTime, String sSavedFileName); + + int NET_DVR_GetFileByTime_V40(int lUserID, String sSavedFileName, NET_DVR_PLAYCOND pDownloadCond); + + boolean NET_DVR_StopGetFile(int lFileHandle); + + int NET_DVR_GetDownloadPos(int lFileHandle); + + int NET_DVR_GetPlayBackPos(int lPlayHandle); + + //图片查找 + int NET_DVR_FindPicture(int lUserID, NET_DVR_FIND_PICTURE_PARAM pFindParam); + + int NET_DVR_FindNextPicture_V50(int lFindHandle, NET_DVR_FIND_PICTURE_V50 lpFindData); + + int NET_DVR_FindNextPicture(int lFindHandle, NET_DVR_FIND_PICTURE lpFindData); + + boolean NET_DVR_CloseFindPicture(int lFindHandle); + + boolean NET_DVR_GetPicture_V50(int lUserID, NET_DVR_PIC_PARAM lpPicParam); + + boolean NET_DVR_SetDVRMessCallBack_NEW(FMessCallBack_NEW fMessCallBack_NEW); + + + boolean NET_DVR_SetDVRMessageCallBack(FMessageCallBack fMessageCallBack, int dwUser); + + boolean NET_DVR_SetDVRMessageCallBack_V30(FMSGCallBack fMessageCallBack, Pointer pUser); + + boolean NET_DVR_SetDVRMessageCallBack_V31(FMSGCallBack_V31 fMessageCallBack, Pointer pUser); + + boolean NET_DVR_SetDVRMessageCallBack_V50(int iIndex, FMSGCallBack_V31 fMessageCallBack, Pointer pUser); + + boolean NET_DVR_SetConnectTime(int dwWaitTime, int dwTryTimes); + + boolean NET_DVR_SetReconnect(int dwInterval, boolean bEnableRecon); + + int NET_DVR_GetSDKVersion(); + + int NET_DVR_GetSDKBuildVersion(); + + int NET_DVR_IsSupport(); + + boolean NET_DVR_StartListen(String sLocalIP, short wLocalPort); + + boolean NET_DVR_StopListen(); + + int NET_DVR_StartListen_V30(String sLocalIP, short wLocalPort, FMSGCallBack DataCallBack, Pointer pUserData); + + boolean NET_DVR_StopListen_V30(int lListenHandle); + + int NET_DVR_Login(String sDVRIP, short wDVRPort, String sUserName, String sPassword, NET_DVR_DEVICEINFO lpDeviceInfo); + + int NET_DVR_Login_V30(String sDVRIP, short wDVRPort, String sUserName, String sPassword, NET_DVR_DEVICEINFO_V30 lpDeviceInfo); + + int NET_DVR_Login_V40(NET_DVR_USER_LOGIN_INFO pLoginInfo, NET_DVR_DEVICEINFO_V40 lpDeviceInfo); + + boolean NET_DVR_Logout(int lUserID); + + boolean NET_DVR_Logout_V30(int lUserID); + + int NET_DVR_GetLastError(); + + String NET_DVR_GetErrorMsg(IntByReference pErrorNo); + + boolean NET_DVR_SetShowMode(int dwShowType, int colorKey); + + boolean NET_DVR_GetDVRIPByResolveSvr(String sServerIP, short wServerPort, String sDVRName, short wDVRNameLen, String sDVRSerialNumber, short wDVRSerialLen, String sGetIP); + + boolean NET_DVR_GetDVRIPByResolveSvr_EX(String sServerIP, short wServerPort, String sDVRName, short wDVRNameLen, String sDVRSerialNumber, short wDVRSerialLen, String sGetIP, IntByReference dwPort); + + //预览相关接口 + int NET_DVR_RealPlay(int lUserID, NET_DVR_CLIENTINFO lpClientInfo); + + int NET_DVR_RealPlay_V30(int lUserID, NET_DVR_CLIENTINFO lpClientInfo, FRealDataCallBack_V30 fRealDataCallBack_V30, Pointer pUser, boolean bBlocked); + + int NET_DVR_RealPlay_V40(int lUserID, NET_DVR_PREVIEWINFO lpPreviewInfo, FRealDataCallBack_V30 fRealDataCallBack_V30, Pointer pUser); + + boolean NET_DVR_StopRealPlay(int lRealHandle); + + boolean NET_DVR_RigisterDrawFun(int lRealHandle, FDrawFun fDrawFun, int dwUser); + + boolean NET_DVR_SetPlayerBufNumber(int lRealHandle, int dwBufNum); + + boolean NET_DVR_ThrowBFrame(int lRealHandle, int dwNum); + + boolean NET_DVR_SetAudioMode(int dwMode); + + boolean NET_DVR_OpenSound(int lRealHandle); + + boolean NET_DVR_CloseSound(); + + boolean NET_DVR_OpenSoundShare(int lRealHandle); + + boolean NET_DVR_CloseSoundShare(int lRealHandle); + + boolean NET_DVR_Volume(int lRealHandle, short wVolume); + + boolean NET_DVR_SaveRealData(int lRealHandle, String sFileName); + + boolean NET_DVR_SaveRealData_V30(int lRealHandle, int dwTransType, String sFileName); + + boolean NET_DVR_StopSaveRealData(int lRealHandle); + + boolean NET_DVR_SetRealDataCallBack(int lRealHandle, FRowDataCallBack fRealDataCallBack, int dwUser); + + boolean NET_DVR_SetStandardDataCallBack(int lRealHandle, FStdDataCallBack fStdDataCallBack, int dwUser); + + boolean NET_DVR_CapturePicture(int lRealHandle, String sPicFileName);//bmp + + //动态生成I帧 + boolean NET_DVR_MakeKeyFrame(int lUserID, int lChannel);//主码流 + + boolean NET_DVR_MakeKeyFrameSub(int lUserID, int lChannel);//子码流 + + //云台控制相关接口 + boolean NET_DVR_PTZControl(int lRealHandle, int dwPTZCommand, int dwStop); + + boolean NET_DVR_PTZControl_Other(int lUserID, int lChannel, int dwPTZCommand, int dwStop); + + boolean NET_DVR_TransPTZ(int lRealHandle, String pPTZCodeBuf, int dwBufSize); + + boolean NET_DVR_TransPTZ_Other(int lUserID, int lChannel, String pPTZCodeBuf, int dwBufSize); + + boolean NET_DVR_PTZPreset(int lRealHandle, int dwPTZPresetCmd, int dwPresetIndex); + + boolean NET_DVR_PTZPreset_Other(int lUserID, int lChannel, int dwPTZPresetCmd, int dwPresetIndex); + + boolean NET_DVR_TransPTZ_EX(int lRealHandle, String pPTZCodeBuf, int dwBufSize); + + boolean NET_DVR_PTZControl_EX(int lRealHandle, int dwPTZCommand, int dwStop); + + boolean NET_DVR_PTZPreset_EX(int lRealHandle, int dwPTZPresetCmd, int dwPresetIndex); + + boolean NET_DVR_PTZCruise(int lRealHandle, int dwPTZCruiseCmd, byte byCruiseRoute, byte byCruisePoint, short wInput); + + boolean NET_DVR_PTZCruise_Other(int lUserID, int lChannel, int dwPTZCruiseCmd, byte byCruiseRoute, byte byCruisePoint, short wInput); + + boolean NET_DVR_PTZCruise_EX(int lRealHandle, int dwPTZCruiseCmd, byte byCruiseRoute, byte byCruisePoint, short wInput); + + boolean NET_DVR_PTZTrack(int lRealHandle, int dwPTZTrackCmd); + + boolean NET_DVR_PTZTrack_Other(int lUserID, int lChannel, int dwPTZTrackCmd); + + boolean NET_DVR_PTZTrack_EX(int lRealHandle, int dwPTZTrackCmd); + + boolean NET_DVR_PTZControlWithSpeed(int lRealHandle, int dwPTZCommand, int dwStop, int dwSpeed); + + boolean NET_DVR_PTZControlWithSpeed_Other(int lUserID, int lChannel, int dwPTZCommand, int dwStop, int dwSpeed); + + boolean NET_DVR_PTZControlWithSpeed_EX(int lRealHandle, int dwPTZCommand, int dwStop, int dwSpeed); + + boolean NET_DVR_GetPTZCruise(int lUserID, int lChannel, int lCruiseRoute, NET_DVR_CRUISE_RET lpCruiseRet); + + boolean NET_DVR_PTZMltTrack(int lRealHandle, int dwPTZTrackCmd, int dwTrackIndex); + + boolean NET_DVR_PTZMltTrack_Other(int lUserID, int lChannel, int dwPTZTrackCmd, int dwTrackIndex); + + boolean NET_DVR_PTZMltTrack_EX(int lRealHandle, int dwPTZTrackCmd, int dwTrackIndex); + + //文件查找与回放 + int NET_DVR_FindFile(int lUserID, int lChannel, int dwFileType, NET_DVR_TIME lpStartTime, NET_DVR_TIME lpStopTime); + + int NET_DVR_FindNextFile(int lFindHandle, NET_DVR_FIND_DATA lpFindData); + + boolean NET_DVR_FindClose(int lFindHandle); + + int NET_DVR_FindNextFile_V30(int lFindHandle, NET_DVR_FINDDATA_V30 lpFindData); + + int NET_DVR_FindFile_V30(int lUserID, NET_DVR_FILECOND pFindCond); + + int NET_DVR_FindFile_V40(int lUserID, NET_DVR_FILECOND_V40 pFindCond); + + int NET_DVR_FindNextFile_V40(int lFindHandle, NET_DVR_FINDDATA_V40 lpFindData); + + int NET_DVR_FindFile_V50(int lUserID, NET_DVR_FILECOND_V50 pFindCond); + + int NET_DVR_FindNextFile_V50(int lFindHandle, NET_DVR_FINDDATA_V50 lpFindData); + + boolean NET_DVR_FindClose_V30(int lFindHandle); + + //按事件查找 + int NET_DVR_FindFileByEvent(int lUserID, NET_DVR_SEARCH_EVENT_PARAM lpSearchEventParam); + + int NET_DVR_FindNextEvent(int lSearchHandle, NET_DVR_SEARCH_EVENT_RET lpSearchEventRet); + + int NET_DVR_FindFileByEvent_V50(int lUserID, NET_DVR_SEARCH_EVENT_PARAM_V50 lpSearchEventParam); + + int NET_DVR_FindNextEvent_V50(int lFindHandle, NET_DVR_SEARCH_EVENT_RET_V50 lpSearchEventRet); + + + //升级 + int NET_DVR_Upgrade(int lUserID, String sFileName); + + int NET_DVR_GetUpgradeState(int lUpgradeHandle); + + int NET_DVR_GetUpgradeProgress(int lUpgradeHandle); + + boolean NET_DVR_CloseUpgradeHandle(int lUpgradeHandle); + + boolean NET_DVR_SetNetworkEnvironment(int dwEnvironmentLevel); + + //远程格式化硬盘 + int NET_DVR_FormatDisk(int lUserID, int lDiskNumber); + + boolean NET_DVR_GetFormatProgress(int lFormatHandle, IntByReference pCurrentFormatDisk, IntByReference pCurrentDiskPos, IntByReference pFormatStatic); + + boolean NET_DVR_CloseFormatHandle(int lFormatHandle); + + //报警 + int NET_DVR_SetupAlarmChan(int lUserID); + + boolean NET_DVR_CloseAlarmChan(int lAlarmHandle); + + int NET_DVR_SetupAlarmChan_V30(int lUserID); + + int NET_DVR_SetupAlarmChan_V41(int lUserID, NET_DVR_SETUPALARM_PARAM lpSetupParam); + + int NET_DVR_SetupAlarmChan_V50(int iUserID, NET_DVR_SETUPALARM_PARAM_V50 lpSetupParam, Pointer pSub, int dwSubSize); + + boolean NET_DVR_CloseAlarmChan_V30(int lAlarmHandle); + + //语音对讲 + int NET_DVR_StartVoiceCom(int lUserID, FVoiceDataCallBack fVoiceDataCallBack, int dwUser); + + int NET_DVR_StartVoiceCom_V30(int lUserID, int dwVoiceChan, boolean bNeedCBNoEncData, FVoiceDataCallBack_V30 fVoiceDataCallBack, Pointer pUser); + + boolean NET_DVR_SetVoiceComClientVolume(int lVoiceComHandle, short wVolume); + + boolean NET_DVR_StopVoiceCom(int lVoiceComHandle); + + //语音转发 + + boolean NET_DVR_GetCurrentAudioCompress(int lUserID, NET_DVR_COMPRESSION_AUDIO lpCompressAudio); + int NET_DVR_StartVoiceCom_MR(int lUserID, FVoiceDataCallBack_MR fVoiceDataCallBack, int dwUser); + + int NET_DVR_StartVoiceCom_MR_V30(int lUserID, int dwVoiceChan, FVoiceDataCallback_MR_V30 fVoiceDataCallBack, Pointer pUser); + + boolean NET_DVR_VoiceComSendData(int lVoiceComHandle, byte[] pSendBuf, int dwBufSize); + + //语音广播 + boolean NET_DVR_ClientAudioStart(); + + boolean NET_DVR_ClientAudioStart_V30(FVoiceDataCallBack2 fVoiceDataCallBack2, Pointer pUser); + + boolean NET_DVR_ClientAudioStop(); + + boolean NET_DVR_AddDVR(int lUserID); + + int NET_DVR_AddDVR_V30(int lUserID, int dwVoiceChan); + + boolean NET_DVR_DelDVR(int lUserID); + + boolean NET_DVR_DelDVR_V30(int lVoiceHandle); + + //////////////////////////////////////////////////////////// +//透明通道设置 + int NET_DVR_SerialStart(int lUserID, int lSerialPort, FSerialDataCallBack fSerialDataCallBack, int dwUser); + + public static interface FSerialDataCallBack_V40 extends Callback { + public void invoke(int lSerialHandle, int lCHannel, byte[] pRecvDataBuffer, int dwBufSize, Pointer pUser); + } + + int NET_DVR_SerialStart_V40(int lUserID, Pointer lpInBuffer, int dwInBufferSize, FSerialDataCallBack_V40 fSerialDataCallBack_V40, Pointer pUser); + + //485作为透明通道时,需要指明通道号,因为不同通道号485的设置可以不同(比如波特率) + boolean NET_DVR_SerialSend(int lSerialHandle, int lChannel, byte[] pSendBuf, int dwBufSize); + + boolean NET_DVR_SerialStop(int lSerialHandle); + + boolean NET_DVR_SendTo232Port(int lUserID, String pSendBuf, int dwBufSize); + + boolean NET_DVR_SendToSerialPort(int lUserID, int dwSerialPort, int dwSerialIndex, String pSendBuf, int dwBufSize); + + //Win64、Linux32、Linux64 + Pointer NET_DVR_InitG722Encoder(NET_DVR_AUDIOENC_INFO enc_info); + + boolean NET_DVR_EncodeG722Frame(Pointer handle, NET_DVR_AUDIOENC_PROCESS_PARAM param); + + void NET_DVR_ReleaseG722Encoder(Pointer pEncodeHandle); + + Pointer NET_DVR_InitG722Decoder(); + + boolean NET_DVR_DecodeG722Frame(Pointer handle, NET_DVR_AUDIODEC_PROCESS_PARAM param); + + void NET_DVR_ReleaseG722Decoder(Pointer pDecHandle); + + //G711: Win64、Linux32、Linux64 + Pointer NET_DVR_InitG711Encoder(NET_DVR_AUDIOENC_INFO enc_info);//NET_DVR_AUDIOENC_INFO//NET_DVR_AUDIOENC_INFO + + boolean NET_DVR_EncodeG711Frame(Pointer handle, NET_DVR_AUDIOENC_PROCESS_PARAM p_enc_proc_param); + + boolean NET_DVR_ReleaseG711Encoder(Pointer pEncodeHandle); + + Pointer NET_DVR_InitG711Decoder(); + + boolean NET_DVR_DecodeG711Frame(Pointer handle, NET_DVR_AUDIODEC_PROCESS_PARAM p_dec_proc_param); + + boolean NET_DVR_ReleaseG711Decoder(Pointer pDecHandle); + + //远程控制本地显示 + boolean NET_DVR_ClickKey(int lUserID, int lKeyIndex); + + //远程控制设备端手动录像 + boolean NET_DVR_StartDVRRecord(int lUserID, int lChannel, int lRecordType); + + boolean NET_DVR_StopDVRRecord(int lUserID, int lChannel); + + //解码卡 + boolean NET_DVR_InitDevice_Card(IntByReference pDeviceTotalChan); + + boolean NET_DVR_ReleaseDevice_Card(); + + boolean NET_DVR_InitDDraw_Card(int hParent, int colorKey); + + boolean NET_DVR_ReleaseDDraw_Card(); + + int NET_DVR_RealPlay_Card(int lUserID, NET_DVR_CARDINFO lpCardInfo, int lChannelNum); + + boolean NET_DVR_ResetPara_Card(int lRealHandle, NET_DVR_DISPLAY_PARA lpDisplayPara); + + boolean NET_DVR_RefreshSurface_Card(); + + boolean NET_DVR_ClearSurface_Card(); + + boolean NET_DVR_RestoreSurface_Card(); + + boolean NET_DVR_OpenSound_Card(int lRealHandle); + + boolean NET_DVR_CloseSound_Card(int lRealHandle); + + boolean NET_DVR_SetVolume_Card(int lRealHandle, short wVolume); + + boolean NET_DVR_AudioPreview_Card(int lRealHandle, boolean bEnable); + + int NET_DVR_GetCardLastError_Card(); + + Pointer NET_DVR_GetChanHandle_Card(int lRealHandle); + + boolean NET_DVR_CapturePicture_Card(int lRealHandle, String sPicFileName); + + //获取解码卡序列号此接口无效,改用GetBoardDetail接口获得(2005-12-08支持) + boolean NET_DVR_GetSerialNum_Card(int lChannelNum, IntByReference pDeviceSerialNo); + + //日志 + int NET_DVR_FindDVRLog(int lUserID, int lSelectMode, int dwMajorType, int dwMinorType, NET_DVR_TIME lpStartTime, NET_DVR_TIME lpStopTime); + + int NET_DVR_FindNextLog(int lLogHandle, NET_DVR_LOG lpLogData); + + boolean NET_DVR_FindLogClose(int lLogHandle); + + int NET_DVR_FindDVRLog_V30(int lUserID, int lSelectMode, int dwMajorType, int dwMinorType, NET_DVR_TIME lpStartTime, NET_DVR_TIME lpStopTime, boolean bOnlySmart); + + int NET_DVR_FindNextLog_V30(int lLogHandle, NET_DVR_LOG_V30 lpLogData); + + boolean NET_DVR_FindLogClose_V30(int lLogHandle); + + //截止2004年8月5日,共113个接口 +//ATM DVR + int NET_DVR_FindFileByCard(int lUserID, int lChannel, int dwFileType, int nFindType, String sCardNumber, NET_DVR_TIME lpStartTime, NET_DVR_TIME lpStopTime); +//截止2004年10月5日,共116个接口 + + //2005-09-15 + boolean NET_DVR_CaptureJPEGPicture(int lUserID, int lChannel, NET_DVR_JPEGPARA lpJpegPara, byte[] sPicFileName); + + //JPEG抓图到内存 + boolean NET_DVR_CaptureJPEGPicture_NEW(int lUserID, int lChannel, NET_DVR_JPEGPARA lpJpegPara, Pointer sJpegPicBuffer, int dwPicSize, IntByReference lpSizeReturned); + + //带全屏测温数据的设备抓图 + boolean NET_DVR_CaptureJPEGPicture_WithAppendData(int lUserID, int iChannelNum, NET_DVR_JPEGPICTURE_WITH_APPENDDATA m_strJpegWithAppendData); + + //2006-02-16 + int NET_DVR_GetRealPlayerIndex(int lRealHandle); + + int NET_DVR_GetPlayBackPlayerIndex(int lPlayHandle); + + //2006-08-28 704-640 缩放配置 + boolean NET_DVR_SetScaleCFG(int lUserID, int dwScale); + + boolean NET_DVR_GetScaleCFG(int lUserID, IntByReference lpOutScale); + + boolean NET_DVR_SetScaleCFG_V30(int lUserID, NET_DVR_SCALECFG pScalecfg); + + boolean NET_DVR_GetScaleCFG_V30(int lUserID, NET_DVR_SCALECFG pScalecfg); + + //2006-08-28 ATM机端口设置 + boolean NET_DVR_SetATMPortCFG(int lUserID, short wATMPort); + + boolean NET_DVR_GetATMPortCFG(int lUserID, ShortByReference LPOutATMPort); + + //2006-11-10 支持显卡辅助输出 + boolean NET_DVR_InitDDrawDevice(); + + boolean NET_DVR_ReleaseDDrawDevice(); + + int NET_DVR_GetDDrawDeviceTotalNums(); + + boolean NET_DVR_SetDDrawDevice(int lPlayPort, int nDeviceNum); + + boolean NET_DVR_PTZSelZoomIn(int lRealHandle, NET_DVR_POINT_FRAME pStruPointFrame); + + boolean NET_DVR_PTZSelZoomIn_EX(int lUserID, int lChannel, NET_DVR_POINT_FRAME pStruPointFrame); + + boolean NET_DVR_FocusOnePush(int lUserID, int lChannel); + + //解码设备DS-6001D/DS-6001F + boolean NET_DVR_StartDecode(int lUserID, int lChannel, NET_DVR_DECODERINFO lpDecoderinfo); + + boolean NET_DVR_StopDecode(int lUserID, int lChannel); + + boolean NET_DVR_GetDecoderState(int lUserID, int lChannel, NET_DVR_DECODERSTATE lpDecoderState); + + //2005-08-01 + boolean NET_DVR_SetDecInfo(int lUserID, int lChannel, NET_DVR_DECCFG lpDecoderinfo); + + boolean NET_DVR_GetDecInfo(int lUserID, int lChannel, NET_DVR_DECCFG lpDecoderinfo); + + boolean NET_DVR_SetDecTransPort(int lUserID, NET_DVR_PORTCFG lpTransPort); + + boolean NET_DVR_GetDecTransPort(int lUserID, NET_DVR_PORTCFG lpTransPort); + + boolean NET_DVR_DecPlayBackCtrl(int lUserID, int lChannel, int dwControlCode, int dwInValue, IntByReference LPOutValue, NET_DVR_PLAYREMOTEFILE lpRemoteFileInfo); + + boolean NET_DVR_StartDecSpecialCon(int lUserID, int lChannel, NET_DVR_DECCHANINFO lpDecChanInfo); + + boolean NET_DVR_StopDecSpecialCon(int lUserID, int lChannel, NET_DVR_DECCHANINFO lpDecChanInfo); + + boolean NET_DVR_DecCtrlDec(int lUserID, int lChannel, int dwControlCode); + + boolean NET_DVR_DecCtrlScreen(int lUserID, int lChannel, int dwControl); + + boolean NET_DVR_GetDecCurLinkStatus(int lUserID, int lChannel, NET_DVR_DECSTATUS lpDecStatus); + + //多路解码器 +//2007-11-30 V211支持以下接口 //11 + boolean NET_DVR_MatrixStartDynamic(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_DYNAMIC_DEC lpDynamicInfo); + + boolean NET_DVR_MatrixStopDynamic(int lUserID, int dwDecChanNum); + + boolean NET_DVR_MatrixGetDecChanInfo(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_DEC_CHAN_INFO lpInter); + + boolean NET_DVR_MatrixSetLoopDecChanInfo(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_LOOP_DECINFO lpInter); + + boolean NET_DVR_MatrixGetLoopDecChanInfo(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_LOOP_DECINFO lpInter); + + boolean NET_DVR_MatrixSetLoopDecChanEnable(int lUserID, int dwDecChanNum, int dwEnable); + + boolean NET_DVR_MatrixGetLoopDecChanEnable(int lUserID, int dwDecChanNum, IntByReference lpdwEnable); + + boolean NET_DVR_MatrixGetLoopDecEnable(int lUserID, IntByReference lpdwEnable); + + boolean NET_DVR_MatrixSetDecChanEnable(int lUserID, int dwDecChanNum, int dwEnable); + + boolean NET_DVR_MatrixGetDecChanEnable(int lUserID, int dwDecChanNum, IntByReference lpdwEnable); + + boolean NET_DVR_MatrixGetDecChanStatus(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_DEC_CHAN_STATUS lpInter); + + boolean NET_DVR_MatrixStartDynamic_V41(int lUserID, int dwDecChanNum, Pointer lpDynamicInfo); + + boolean NET_DVR_MatrixGetLoopDecChanInfo_V41(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_LOOP_DECINFO_V41 lpOuter); + + boolean NET_DVR_MatrixSetLoopDecChanInfo_V41(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_LOOP_DECINFO_V41 lpInter); + + int NET_DVR_MatrixStartPassiveDecode(int lUserID, int dwDecChanNum, Pointer lpPassiveMode); + + boolean NET_DVR_MatrixSendData(int lPassiveHandle, Pointer pSendBuf, int dwBufSize); + + boolean NET_DVR_MatrixStopPassiveDecode(int lPassiveHandle); + + //2007-12-22 增加支持接口 //18 + boolean NET_DVR_MatrixSetTranInfo(int lUserID, NET_DVR_MATRIX_TRAN_CHAN_CONFIG lpTranInfo); + + boolean NET_DVR_MatrixGetTranInfo(int lUserID, NET_DVR_MATRIX_TRAN_CHAN_CONFIG lpTranInfo); + + boolean NET_DVR_MatrixSetRemotePlay(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_DEC_REMOTE_PLAY lpInter); + + boolean NET_DVR_MatrixSetRemotePlayControl(int lUserID, int dwDecChanNum, int dwControlCode, int dwInValue, IntByReference LPOutValue); + + boolean NET_DVR_MatrixGetRemotePlayStatus(int lUserID, int dwDecChanNum, NET_DVR_MATRIX_DEC_REMOTE_PLAY_STATUS lpOuter); + + //end + boolean NET_DVR_RefreshPlay(int lPlayHandle); + + //恢复默认值 + boolean NET_DVR_RestoreConfig(int lUserID); + + //保存参数 + boolean NET_DVR_SaveConfig(int lUserID); + + //重启 + boolean NET_DVR_RebootDVR(int lUserID); + + //关闭DVR + boolean NET_DVR_ShutDownDVR(int lUserID); + + //参数配置 begin + boolean NET_DVR_GetDeviceConfig(int lUserID, int dwCommand, int dwCount, Pointer lpInBuffer, int dwInBufferSize, Pointer lpStatusList, Pointer lpOutBuffer, int dwOutBufferSize); + + boolean NET_DVR_SetDeviceConfig(int lUserID, int dwCommand, int dwCount, Pointer lpInBuffer, int dwInBufferSize, Pointer lpStatusList, Pointer lpInParamBuffer, int dwInParamBufferSize); + + boolean NET_DVR_SetDeviceConfigEx(int lUserID, int dwCommand, int dwCount, Pointer lpInParam, Pointer lpOutParam); + + boolean NET_DVR_GetDVRConfig(int lUserID, int dwCommand, int lChannel, Pointer lpOutBuffer, int dwOutBufferSize, IntByReference lpBytesReturned); + + boolean NET_DVR_SetDVRConfig(int lUserID, int dwCommand, int lChannel, Pointer lpInBuffer, int dwInBufferSize); + + boolean NET_DVR_GetSTDConfig(int lUserID, int dwCommand, NET_DVR_STD_CONFIG lpConfigParam); + + boolean NET_DVR_SetSTDConfig(int lUserID, int dwCommand, NET_DVR_STD_CONFIG lpConfigParam); + + boolean NET_DVR_GetDVRWorkState_V30(int lUserID, NET_DVR_WORKSTATE_V30 lpWorkState); + + boolean NET_DVR_GetDVRWorkState(int lUserID, NET_DVR_WORKSTATE lpWorkState); + + boolean NET_DVR_SetVideoEffect(int lUserID, int lChannel, int dwBrightValue, int dwContrastValue, int dwSaturationValue, int dwHueValue); + + boolean NET_DVR_GetVideoEffect(int lUserID, int lChannel, IntByReference pBrightValue, IntByReference pContrastValue, IntByReference pSaturationValue, IntByReference pHueValue); + + boolean NET_DVR_ClientGetframeformat(int lUserID, NET_DVR_FRAMEFORMAT lpFrameFormat); + + boolean NET_DVR_ClientSetframeformat(int lUserID, NET_DVR_FRAMEFORMAT lpFrameFormat); + + boolean NET_DVR_ClientGetframeformat_V30(int lUserID, NET_DVR_FRAMEFORMAT_V30 lpFrameFormat); + + boolean NET_DVR_ClientSetframeformat_V30(int lUserID, NET_DVR_FRAMEFORMAT_V30 lpFrameFormat); + + boolean NET_DVR_GetAlarmOut_V30(int lUserID, NET_DVR_ALARMOUTSTATUS_V30 lpAlarmOutState); + + boolean NET_DVR_GetAlarmOut(int lUserID, NET_DVR_ALARMOUTSTATUS lpAlarmOutState); + + boolean NET_DVR_SetAlarmOut(int lUserID, int lAlarmOutPort, int lAlarmOutStatic); + + //视频参数调节 + boolean NET_DVR_ClientSetVideoEffect(int lRealHandle, int dwBrightValue, int dwContrastValue, int dwSaturationValue, int dwHueValue); + + boolean NET_DVR_ClientGetVideoEffect(int lRealHandle, IntByReference pBrightValue, IntByReference pContrastValue, IntByReference pSaturationValue, IntByReference pHueValue); + + //配置文件 + boolean NET_DVR_GetConfigFile(int lUserID, String sFileName); + + boolean NET_DVR_SetConfigFile(int lUserID, String sFileName); + + boolean NET_DVR_GetConfigFile_V30(int lUserID, String sOutBuffer, int dwOutSize, IntByReference pReturnSize); + + boolean NET_DVR_GetConfigFile_EX(int lUserID, String sOutBuffer, int dwOutSize); + + boolean NET_DVR_SetConfigFile_EX(int lUserID, String sInBuffer, int dwInSize); + + //启用日志文件写入接口 + boolean NET_DVR_SetLogToFile(int bLogEnable, String strLogDir, boolean bAutoDel); + + boolean NET_DVR_GetSDKState(NET_DVR_SDKSTATE pSDKState); + + boolean NET_DVR_GetSDKAbility(NET_DVR_SDKABL pSDKAbl); + + boolean NET_DVR_GetPTZProtocol(int lUserID, NET_DVR_PTZCFG pPtzcfg); + + boolean NET_DVR_GetPTZPos(int lUserID, int lChannel, NET_DVR_PTZPOS lpPTZPos); + //前面板锁定 + boolean NET_DVR_LockPanel(int lUserID); + + boolean NET_DVR_UnLockPanel(int lUserID); + + boolean NET_DVR_SetRtspConfig(int lUserID, int dwCommand, NET_DVR_RTSPCFG lpInBuffer, int dwInBufferSize); + + boolean NET_DVR_GetRtspConfig(int lUserID, int dwCommand, NET_DVR_RTSPCFG lpOutBuffer, int dwOutBufferSize); + + boolean NET_DVR_ContinuousShoot(int lUserID, NET_DVR_SNAPCFG lpInter); + + boolean NET_DVR_ManualSnap(int lUserID, NET_DVR_MANUALSNAP lpInter, NET_DVR_PLATE_RESULT lpOuter); + + public static interface FRemoteConfigCallBack extends Callback { + public void invoke(int dwType, Pointer lpBuffer, int dwBufLen, Pointer pUserData); + } + + int NET_DVR_StartRemoteConfig(int lUserID, int dwCommand, Pointer lpInBuffer, int dwInBufferLen, FRemoteConfigCallBack cbStateCallBack, Pointer pUserData); + + boolean NET_DVR_SendRemoteConfig(int lHandle, int dwDataType, Pointer pSendBuf, int dwBufSize); + + int NET_DVR_GetNextRemoteConfig(int lHandle, Pointer lpOutBuff, int dwOutBuffSize); + + int NET_DVR_SendWithRecvRemoteConfig(int lHandle, Pointer lpInBuff, int dwInBuffSize, Pointer lpOutBuff, int dwOutBuffSize, IntByReference dwOutDataLen); + + boolean NET_DVR_StopRemoteConfig(int lHandle); + + boolean NET_DVR_RemoteControl(int lUserID, int dwCommand, Pointer lpInBuffer, int dwInBufferSize); + + boolean NET_DVR_STDXMLConfig(int lUserID, NET_DVR_XML_CONFIG_INPUT lpInputParam, NET_DVR_XML_CONFIG_OUTPUT lpOutputParam); + + boolean NET_DVR_GetSTDAbility(int lUserID, int dwAbilityType, NET_DVR_STD_ABILITY lpAbilityParam); + + boolean NET_DVR_GetDeviceAbility(int lUserID, int dwAbilityType, Pointer pInBuf, int dwInLength, Pointer pOutBuf, int dwOutLength); + + boolean NET_DVR_ControlGateway(int lUserID, int lGatewayIndex, int dwStaic); + + boolean NET_DVR_InquestStartCDW_V30(int lUserID, NET_DVR_INQUEST_ROOM lpInquestRoom, boolean bNotBurn); + + boolean NET_DVR_InquestStopCDW_V30(int lUserID, NET_DVR_INQUEST_ROOM lpInquestRoom, boolean bCancelWrite); + + boolean NET_DVR_GetArrayList(int lUserID, NET_DVR_ARRAY_LIST lpArrayList); + + int NET_DVR_InquestResumeEvent(int lUserID, NET_DVR_INQUEST_RESUME_EVENT lpResumeEvent); + + boolean NET_DVR_InquestGetResumeProgress(int lHandle, IntByReference pState); + + boolean NET_DVR_InquestStopResume(int lHandle); + + boolean NET_DVR_GetLocalIP(BYTE_TWODIM[] strIP, IntByReference pValidNum, boolean pEnableBind); + + boolean NET_DVR_SetValidIP(int dwIPIndex, boolean bEnableBind); + + boolean NET_DVR_AlarmHostAssistantControl(int lUserID, int dwType, int dwNumber, int dwCmdParam); + + boolean NET_DVR_GetPlanList(int lUserID, int dwDevNum, NET_DVR_PLAN_LIST lpPlanList); + + int NET_DVR_UploadFile_V40(int lUserID, int dwUploadType, Pointer lpInBuffer, int dwInBufferSize, String sFileName, Pointer lpOutBuffer, int dwOutBufferSize); + + int NET_DVR_UploadSend(int lUploadHandle, NET_DVR_SEND_PARAM_IN pstruSendParamIN, Pointer lpOutBuffer); + + int NET_DVR_GetUploadState(int lUploadHandle, Pointer pProgress); + + boolean NET_DVR_GetUploadResult(int lUploadHandle, Pointer lpOutBuffer, int dwOutBufferSize); + + boolean NET_DVR_UploadClose(int lUploadHandle); + + int NET_DVR_StartNetworkFlowTest(int lUserID, NET_DVR_FLOW_TEST_PARAM pFlowTest, FLOWTESTCALLBACK fFlowTestCallback, Pointer pUser); + + boolean NET_DVR_StopNetworkFlowTest(int lHandle); + + boolean NET_DVR_InquiryRecordTimeSpan(int lUserID, int dwChannel, NET_DVR_RECORD_TIME_SPAN_INQUIRY lpInquiry, NET_DVR_RECORD_TIME_SPAN lpResult); + + boolean NET_DVR_StartGetDevState(NET_DVR_CHECK_DEV_STATE pParams); + + //gps相关结构定义 + public static class TimeSegParam extends HIKSDKStructure { + //GPS数据查找起始时间 + public NET_DVR_TIME struBeginTime; + //GPS数据查找结束时间 + public NET_DVR_TIME struEndTime; + //GPS点时间间隔,单位:秒 + public int dwInterval; + //保留 + public byte[] byRes = new byte[76]; + } + + //按时间点查询 + public static class TimePointParam extends HIKSDKStructure { + //GPS数据查找时间点 + public NET_DVR_TIME struTimePoint; + //保留 + public byte[] byRes = new byte[104]; + } + + public static class GpsDataParamUion extends Union { + //按时间段查询 + public TimeSegParam timeSeg = new TimeSegParam(); + //按时间点查询 + public TimePointParam timePoint = new TimePointParam(); + } + + //gps查询参数定义 + public static class NET_DVR_GET_GPS_DATA_PARAM extends HIKSDKStructure { + //查找方式:0- 按时间段查找GPS数据,1- 按时间点查找GPS数据 + public int dwCmdType; + public GpsDataParamUion gpsDataParam; + + public void read() { + super.read(); + switch (dwCmdType) { + case 0: + gpsDataParam.setType(TimeSegParam.class); + break; + case 1: + gpsDataParam.setType(TimePointParam.class); + break; + default: + break; + } + gpsDataParam.read(); + } + + public void write() { + super.write(); + gpsDataParam.write(); + } + } + + //gps数据结构定义 + public static class NET_DVR_GPS_INFO extends HIKSDKStructure { + public byte[] byDirection = new byte[2]; + public byte bySvs; + public byte byLocateMode; + public short wHDOP; + public short wHeight; + public int dwLatitude; + public int dwLongitude; + public int dwVehicleSpeed; + public int dwVehicleDirection; + public byte[] byRes = new byte[8]; + } + + //gps返回数据结构定义 + public static class NET_DVR_GPS_DATA extends HIKSDKStructure { + public NET_DVR_GPS_INFO struGPSInfo; + public NET_DVR_TIME struTime; + public byte[] byRes = new byte[12]; + } + + public static interface fGPSDataCallback extends Callback { + public void invoke(int nHandle, int dwState, Pointer lpBuffer, int dwBufLen, Pointer pUser); + } + + int NET_DVR_GetVehicleGpsInfo(int lUserID, NET_DVR_GET_GPS_DATA_PARAM lpGPSDataParam, fGPSDataCallback cbGPSDataCallBack, Pointer pUser); + + /** + * 热成像相关 + */ + //设备抓图附加全屏测温数据结构体 + public static class NET_DVR_JPEGPICTURE_WITH_APPENDDATA extends HIKSDKStructure { + public int dwSize; + public int dwChannel;//通道号 + public int dwJpegPicLen;//Jpeg图片长度 + public Pointer pJpegPicBuff;//Jpeg图片指针 + public int dwJpegPicWidth; // 图像宽度 + public int dwJpegPicHeight; //图像高度 + public int dwP2PDataLen;//全屏测温数据长度 + public Pointer pP2PDataBuff; //全屏测温数据指针 + public byte byIsFreezedata;//是否数据冻结 0-否 1-是 + public byte[] byRes = new byte[255]; + @Override + protected List getFieldOrder() { + return Arrays.asList( + "dwSize", + "dwChannel", + "dwJpegPicLen", + "pJpegPicBuff", + "dwJpegPicWidth", + "dwJpegPicHeight", + "dwP2PDataLen", + "pP2PDataBuff", + "byIsFreezedata", + "byRes" + ); + } + } + + + public static class DATE_TIME extends HIKSDKStructure { + public short year; /*APP->DSP 年*/ + public short month; /*APP->DSP 月*/ + public short dayOfWeek; /*APP->DSP 0:星期日-6:星期六*/ + public short day; /*APP->DSP 日*/ + public short hour; /*APP->DSP 小时*/ + public short minute; /*APP->DSP 分钟*/ + public short second; /*APP->DSP 秒*/ + public short milliSecond; /*APP->DSP 毫秒*/ + } + + //全屏测温数据解析 + public static class STREAM_RT_DATA_INFO_S extends HIKSDKStructure { + public int u32RTDataType; // 1-14bit裸数据; 2-全屏测温结果数据; 3-YUV数据 + public int u32FrmNum; + public int u32StdStamp; //DSP相对时间戳 + public DATE_TIME stTime; //绝对时间戳 + public int u32Width; + public int u32Height; + public int u32Len; + public int u32Fps; + public int u32Chan; + } + + public static class STREAM_FS_SUPPLE_INFO_TEMP extends HIKSDKStructure { + public int u32TmDataMode; /* 0为4字节,1为2字节 */ + public int u32TmScale; /* 测温缩放比例 */ + public int u32TmOffset; /* 测温偏移量,当前固定为0 */ + public int byIsFreezedata; /*是否是冻结数据,1:冻结,0:非冻结*/ + } + + public static class STREAM_FARME_INFO_TEMP extends HIKSDKStructure { + public int u32MagicNo; //0x70827773 "FRMI"的ascii码 + public int u32HeaderSize; //结构体长度 + public int u32StreamType; //数据类型: h264/h265, JPEG, Audio, MetaData, RTData: 参见 STREAM_TYPE_E + public int u32StreamLen; //数据长度 + public STREAM_RT_DATA_INFO_S stRTDataInfo; + public STREAM_FS_SUPPLE_INFO_TEMP stFsSuppleInfo; + public int[] res = new int[12]; + public int u32CrcVal; //结构体校验码 对结构体前面数据进行校验 + } + + //测温规则温度信息 + public static class NET_DVR_THERMOMETRYRULE_TEMPERATURE_INFO extends HIKSDKStructure { + public float fMaxTemperature; + public float fMinTemperature; + public float fAverageTemperature; + public NET_VCA_POINT struHighestPoint; + public NET_VCA_POINT struLowestPoint; + public byte byIsFreezedata; + public byte[] byRes = new byte[15]; + } + + public static class REMOTECONFIGSTATUS_THERMOMETRY extends HIKSDKStructure { + public byte[] byStatus = new byte[4]; + public byte[] byErrorCode = new byte[4]; + } + + public static class NET_DVR_FIREDETECTION_ALARM extends HIKSDKStructure { + public int dwSize; //结构体大小 + public int dwRelativeTime; //相对时标 + public int dwAbsTime; //绝对时标 + public NET_VCA_DEV_INFO struDevInfo; //前端设备信息 + public short wPanPos; + public short wTiltPos; + public short wZoomPos; + public byte byPicTransType; //图片数据传输方式: 0-二进制;1-url + public byte byRes1; + public int dwPicDataLen; //报警抓拍图片长度 + public Pointer pBuffer; //数据指针 + public NET_VCA_RECT struRect; //火点框 + public NET_VCA_POINT struPoint; //火点框内最高温度点坐标 + public short wFireMaxTemperature; //火点最高温度[300℃~4000℃] + public short wTargetDistance; //目标距离[100m ~ 10000m] + public byte byStrategyType; //策略类型;0~任意报警,1~协同报警,2~多系统报警,3~指定火点报警,4~指定烟雾报警 + public byte byAlarmSubType; //报警子类型。0~火点检测报警,1~烟雾检测报警,2~烟火报警 + /*是否启用PTZ坐标扩展, + 0~不启用,PTZ坐标值以wPanPos、wTiltPos、wZoomPos为准。 + 1~启用,PTZ坐标值以struPtzPosEx为准。但是新老PTZ都需返回。struPtzPosEx的值需转化为wPanPos、wTiltPos、wZoomPos值。 + */ + public byte byPTZPosExEnable; + public byte byRes2; + public NET_PTZ_INFO struPtzPosEx; // ptz坐标扩展(支持高精度PTZ值,精确到小数点后三位) + public int dwVisiblePicLen; // 可见光图片长度 + public Pointer pVisiblePicBuf; // 可见光图片数据指针 + // pSmokeBuf参数当byAlarmSubType报警子类型为1(烟雾检测报警)、2(烟火报警)时生效。 + public Pointer pSmokeBuf; //烟雾检测报警数据指针,指向一个NET_DVR_SMOKEDETECTION_ALARM结构体 + public short wDevInfoIvmsChannelEx; //与NET_VCA_DEV_INFO里的byIvmsChannel含义相同,能表示更大的值。老客户端用byIvmsChannel能继续兼容,但是最大到255。新客户端版本请使用wDevInfoIvmsChannelEx。 + public byte byRes3; + public byte byFireScanWaitMode; //火点扫描等待模式 0-自动 1-手动 + public int dwVisibleChannel; //可见光通道通道号 + public byte byTimeDiffFlag; //时差字段是否有效 0-时差无效, 1-时差有效 + public char cTimeDifferenceH; //与UTC的时差(小时),-12 ... +14, +表示东区,,byTimeDiffFlag为1时有效 + public char cTimeDifferenceM; //与UTC的时差(分钟),-30, 30, 45, +表示东区,byTimeDiffFlag为1时有效 + public byte[] byRes = new byte[49]; + } + + //模块服务配置结构体 + public static class NET_DVR_DEVSERVER_CFG extends HIKSDKStructure { + public int dwSize; //结构体大小 + public byte byIrLampServer; //红外灯设置:0- 禁用,1- 启用 + public byte bytelnetServer; //telnet设置:0- 禁用,1- 启用 + public byte byABFServer; //ABF设置:0- 启用,1- 禁用,请注意此处参数取值0、1和其他参数取值含义不同 + public byte byEnableLEDStatus; //状态指示灯控制:0- 禁用,1- 启用 + public byte byEnableAutoDefog; //自动除雾控制:0- 启用,1- 禁用,请注意此处参数取值0、1和其他参数取值含义不同 + public byte byEnableSupplementLight; //补光灯控制:0- 启用,1- 禁用,请注意此处参数取值0、1和其他参数取值含义不同 + public byte byEnableDeicing; //除冰功能:0- 关闭,1- 开启 + public byte byEnableVisibleMovementPower; //可见光机芯电源开关(低功耗模式下有效):0- 关闭,1- 开启 + public byte byEnableThermalMovementPower; //热成像机芯电源开关(低功耗模式下有效):0- 关闭,1- 开启 + public byte byEnablePtzPower; //云台电源开关(低功耗模式下有效):0- 关闭,1- 开启 + public byte byPowerSavingControl; //低功耗策略:0- 保留,1- 休眠模式,2-低功耗模式(低功耗模式下,可见光机芯电源、热成像机芯电源、云台电源控制生效) + public byte byCaptureWithSupplimentLightEnabled; //启用抓拍补光使能 0-关闭,1-开启 + public byte[] byRes = new byte[244]; //保留,置为0 + } + + public static final int MAX_UPLOADFILE_URL_LEN = 240; + public static final int IMPORT_DATA_TO_FACELIB = 39; //导入人脸数据(人脸图片+图片附件信息 到设备人脸库) + + public static class NET_DVR_UPLOAD_FILE_RET extends HIKSDKStructure { + + public byte[] sUrl = new byte[MAX_UPLOADFILE_URL_LEN]; //url + public byte[] byRes = new byte[260]; + } + + public static class NET_DVR_FLOW_TEST_PARAM extends HIKSDKStructure { + public int dwSize; //结构大小 + public int lCardIndex; //网卡索引 + public int dwInterval; //设备上传流量时间间隔, 单位:100ms + public byte[] byRes = new byte[8]; //保留字节 + } + + public static class NET_DVR_RECORD_TIME_SPAN_INQUIRY extends HIKSDKStructure { + public int dwSize; //结构体大小 + public byte byType; //0 正常音视频录像, 1图片通道录像, 2ANR通道录像, 3抽帧通道录像 + public byte[] byRes = new byte[63]; + } + + public static class NET_DVR_RECORD_TIME_SPAN extends HIKSDKStructure { + public int dwSize; //结构体大小 + public NET_DVR_TIME strBeginTime; //开始时间 + public NET_DVR_TIME strEndTime; //结束时间 + public byte byType; //0 正常音视频录像, 1图片通道录像, 2ANR通道录像, 3抽帧通道录像 + public byte[] byRes = new byte[35]; //保留 + } + + /* + * 月历录像分布查询条件结构体 + */ + public static class NET_DVR_MRD_SEARCH_PARAM extends HIKSDKStructure { + public int dwSize; // 结构体大小 + public NET_DVR_STREAM_INFO struStreamInfo = new NET_DVR_STREAM_INFO(); // 布防点 + public short wYear; // 年 + public byte byMonth; // 月 + public byte byDrawFrame; // 0-不抽帧 1-抽帧 + public byte byStreamType; //0-主码流 1-子码流 + public byte byLocalOrUTC; //0-设备本地时区 1-UTC + public byte[] byRes = new byte[30]; + } + + /* + * 月历录像分布查询结果结构体 + */ + public static class NET_DVR_MRD_SEARCH_RESULT extends HIKSDKStructure { + + public int dwSize; // 结构体大小 + public byte[] byRecordDistribution = new byte[32]; // 录像分布,byRecordDistribution[0]=1表示1日存在录像,byRecordDistribution[0]=0表示没有录像,byRecordDistribution[1]表示2日,以此类推 + public byte[] byHasEventRecode = new byte[31]; //事件录像 0-无事件录像,1-有事件录像 + public byte byRes; //保留 + } + + public static final int NET_DVR_GET_GISINFO = 3711; + //GIS信息 + + public static class NET_DVR_GIS_INFO extends HIKSDKStructure { + public int dwSize; + public float fAzimuth; + public float fHorizontalValue; + public float fVerticalValue; + public float fVisibleRadius; + public float fMaxViewRadius; + public byte byLatitudeType; + public byte byLongitudeType; + public byte byPTZPosExEnable; + public byte byRes1; + public NET_DVR_LLI_PARAM struLatitude = new NET_DVR_LLI_PARAM(); + public NET_DVR_LLI_PARAM struLongitude = new NET_DVR_LLI_PARAM(); + public NET_DVR_PTZPOS_PARAM struPtzPos = new NET_DVR_PTZPOS_PARAM(); + public NET_DVR_SENSOR_PARAM struSensorParam = new NET_DVR_SENSOR_PARAM(); + public NET_PTZ_INFO struPtzPosEx = new NET_PTZ_INFO(); + public float fMinHorizontalValue; + public float fMaxHorizontalValue; + public float fMinVerticalValue; + public float fMaxVerticalValue; + public byte[] byRes = new byte[220]; + } + + //GBT28181协议的设备编码通道配置 + public static class NET_DVR_GBT28181_CHANINFO_CFG extends HIKSDKStructure { + public int dwSize; + public byte[] szVideoChannelNumID = new byte[64];//设备视频通道编码ID:64字节字符串,仅限数字 + public byte[] byRes = new byte[256]; + } + + // 巡航路径配置条件结构体 + public static class NET_DVR_CRUISEPOINT_COND extends HIKSDKStructure { + public int dwSize; + public int dwChan; + public short wRouteNo; + public byte[] byRes = new byte[30]; + } + + // 巡航路径配置结构体 + public static class NET_DVR_CRUISEPOINT_V40 extends HIKSDKStructure { + public int dwSize; + public NET_DVR_CRUISEPOINT_PARAM[] struCruisePoint = (NET_DVR_CRUISEPOINT_PARAM[]) new NET_DVR_CRUISEPOINT_PARAM().toArray(128); + public byte[] byRes = new byte[64]; + } + + // 巡航路径配置结构体 + public static class NET_DVR_CRUISEPOINT_V50 extends HIKSDKStructure { + public int dwSize; + public NET_DVR_CRUISEPOINT_PARAM[] struCruisePoint = (NET_DVR_CRUISEPOINT_PARAM[]) new NET_DVR_CRUISEPOINT_PARAM().toArray(256); + public byte[] byRes = new byte[64]; + } + + // 巡航点参数结构体 + public static class NET_DVR_CRUISEPOINT_PARAM extends HIKSDKStructure { + public short wPresetNo; + public short wDwell; + public byte bySpeed; + public byte bySupport256PresetNo; + public byte[] byRes = new byte[6]; + } + + //因为Java没有二维数组,BYTE_TWODIM是自定义的结构体 + public static class BYTE_TWODIM extends HIKSDKStructure { + public byte[] strIP = new byte[16]; + } + + //云台锁定配置结构体 + public static class NET_DVR_PTZ_LOCKCFG extends HIKSDKStructure { + public int dwSize;//结构体大小 + public byte byWorkMode ;//云台锁定控制:0- 解锁,1- 锁定 + public byte[] byRes = new byte[123]; + } +} + + +//播放库函数声明,PlayCtrl.dll +interface PlayCtrl extends Library { + public static final int STREAME_REALTIME = 0; + public static final int STREAME_FILE = 1; + + boolean PlayM4_GetPort(IntByReference nPort); + + boolean PlayM4_OpenStream(int nPort, Pointer pFileHeadBuf, int nSize, int nBufPoolSize); + + boolean PlayM4_InputData(int nPort, Pointer pBuf, int nSize); + + boolean PlayM4_CloseStream(int nPort); + + boolean PlayM4_SetStreamOpenMode(int nPort, int nMode); + + boolean PlayM4_Play(int nPort, HWND hWnd); + + boolean PlayM4_Stop(int nPort); + + boolean PlayM4_SetSecretKey(int nPort, int lKeyType, String pSecretKey, int lKeyLen); + + boolean PlayM4_GetPictureSize(int nPort, IntByReference pWidth, IntByReference pHeight); + + boolean PlayM4_GetJPEG(int nPort, Pointer pBitmap, int nBufSize, IntByReference pBmpSize); + + int PlayM4_GetLastError(int nPort); + + boolean PlayM4_SetDecCallBackExMend(int nPort, DecCallBack decCBFun, Pointer pDest, int nDestSize, int nUser); + + public static interface DecCallBack extends Callback { + void invoke(int nPort, Pointer pBuf, int nSize, FRAME_INFO pFrameInfo, int nReserved1, int nReserved2); + } + + public class FRAME_INFO extends HIKSDKStructure { + public int nWidth; /* 画面宽,单位像素。如果是音频数据,则为音频声道数 */ + public int nHeight; /* 画面高,单位像素。如果是音频数据,则为样位率 */ + public int nStamp; /* 时标信息,单位毫秒 */ + public int nType; /* 数据类型,T_AUDIO16, T_RGB32, T_YV12 */ + public int nFrameRate; /* 编码时产生的图像帧率,如果是音频数据则为采样率 */ + public int dwFrameNum; /* 帧号 */ + } + +} + +//windows gdi接口,gdi32.dll in system32 folder, 在设置遮挡区域,移动侦测区域等情况下使用 +interface GDI32 extends W32API { + GDI32 INSTANCE = (GDI32) Native.loadLibrary("gdi32", GDI32.class, DEFAULT_OPTIONS); + + public static final int TRANSPARENT = 1; + + int SetBkMode(HDC hdc, int i); + + HANDLE CreateSolidBrush(int icolor); +} + +//windows user32接口,user32.dll in system32 folder, 在设置遮挡区域,移动侦测区域等情况下使用 +interface USER32 extends W32API { + + USER32 INSTANCE = (USER32) Native.loadLibrary("user32", USER32.class, DEFAULT_OPTIONS); + + public static final int BF_LEFT = 0x0001; + public static final int BF_TOP = 0x0002; + public static final int BF_RIGHT = 0x0004; + public static final int BF_BOTTOM = 0x0008; + public static final int BDR_SUNKENOUTER = 0x0002; + public static final int BF_RECT = (BF_LEFT | BF_TOP | BF_RIGHT | BF_BOTTOM); + + boolean DrawEdge(HDC hdc, com.sun.jna.examples.win32.GDI32.RECT qrc, int edge, int grfFlags); + + int FillRect(HDC hDC, com.sun.jna.examples.win32.GDI32.RECT lprc, HANDLE hbr); +} + diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HCNetTools.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HCNetTools.java new file mode 100644 index 0000000..8132b8f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HCNetTools.java @@ -0,0 +1,366 @@ +package com.sz.admin.monitor.sdk.hkSdk; + + +import com.sun.jna.NativeLong; +import com.sun.jna.Pointer; +import com.sun.jna.ptr.IntByReference; +import com.sz.admin.monitor.enums.HCPlayControlEnum; +import com.sz.admin.monitor.pojo.dto.camera.CameraDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class HCNetTools { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE; + + //海康播放库(SDK里的PlayCtrl不是此处的PlayCtrl) + //static PlayCtrl playControl = PlayCtrl.INSTANCE; + + private HCNetSDK.NET_DVR_WORKSTATE_V30 m_strWorkState; + private HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo;//设备信息 + private HCNetSDK.NET_DVR_IPPARACFG m_strIpparaCfg;//IP参数 + private HCNetSDK.NET_DVR_IPPARACFG_V40 m_strIpparaCfgV40;//更详细的参数 + private HCNetSDK.NET_DVR_CLIENTINFO m_strClientInfo;//用户参数 + + private boolean bRealPlay;//是否在预览. + private String m_sDeviceIP;//已登录设备的IP地址 + + private int lUserID;//用户句柄 + private int loadHandle;//下载句柄 + private int lPreviewHandle;//预览句柄 + private IntByReference m_lPort;//回调预览时播放库端口指针 + private IntByReference m_err;//错误号 + + public HCNetTools() { + lUserID = -1; + lPreviewHandle = -1; + m_lPort = new IntByReference(-1); + m_err = new IntByReference(-1); + } + + /** + * 初始化资源配置 + */ + public int initDevices() { + boolean b = hCNetSDK.NET_DVR_Init(); + if (!b) { + //初始化失败 + //throw new RuntimeException("初始化失败"); + System.out.println("初始化失败"); + return 1; + } + return 0; + } + + /** + * 设备注册 + * + * @param name 设备用户名 + * @param password 设备登录密码 + * @param ip IP地址 + * @param port 端口 + * @return 结果 + */ + public int deviceLogin(String name, String password, String ip, String port) { + + if (bRealPlay) {//判断当前是否在预览 + return 2;//"注册新用户请先停止当前预览"; + } + if (lUserID > -1) {//先注销,在登录 + hCNetSDK.NET_DVR_Logout_V30(lUserID); + lUserID = -1; + } + //注册(既登录设备)开始 + m_sDeviceIP = ip; + short iPort = Integer.valueOf(port).shortValue(); + m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();//获取设备参数结构 + lUserID = hCNetSDK.NET_DVR_Login_V30(ip, iPort, name, password, m_strDeviceInfo);//登录设备 + long userID = lUserID; + if (userID == -1) { + int iErr = hCNetSDK.NET_DVR_GetLastError(); + System.out.println(":注册失败,错误号:" + iErr); + System.out.println(hCNetSDK.NET_DVR_GetErrorMsg(m_err)); + m_sDeviceIP = "";//登录未成功,IP置为空 + return 3;//"注册失败"; + } + return 0; + } + + /** + * 注销登陆 + */ + public void deviceLogout() { + + //如果在预览,先停止预览, 释放句柄 + if (lPreviewHandle > -1) + { + hCNetSDK.NET_DVR_StopRealPlay(lPreviewHandle); + } + + //如果已经注册,注销 + if (lUserID> -1) { + hCNetSDK.NET_DVR_Logout_V30(lUserID); + } + hCNetSDK.NET_DVR_Cleanup(); + } + + /** + * 获取设备通道 + */ + public List getChannelNumber() { + List channelList = new ArrayList<>(); + IntByReference ibrBytesReturned = new IntByReference(0);//获取IP接入配置参数 + HCNetSDK.NET_DVR_IPPARACFG_V40 m_strIpparaCfg = new HCNetSDK.NET_DVR_IPPARACFG_V40(); + m_strIpparaCfg.write(); + //lpIpParaConfig 接收数据的缓冲指针 + Pointer lpIpParaConfig = m_strIpparaCfg.getPointer(); + boolean bRet = hCNetSDK.NET_DVR_GetDVRConfig(lUserID, HCNetSDK.NET_DVR_GET_IPPARACFG_V40, 0, lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned); + m_strIpparaCfg.read(); + for (int iChannum = 0; iChannum < m_strIpparaCfg.dwDChanNum; iChannum++) { + CameraDTO cameraDTO = new CameraDTO(); + int channum = iChannum + m_strIpparaCfg.dwStartDChan; + HCNetSDK.NET_DVR_PICCFG_V40 strPicCfg = new HCNetSDK.NET_DVR_PICCFG_V40(); + strPicCfg.dwSize = strPicCfg.size(); + strPicCfg.write(); + Pointer pStrPicCfg = strPicCfg.getPointer(); + NativeLong lChannel = new NativeLong(channum); + IntByReference pInt = new IntByReference(0); + boolean b_GetPicCfg = hCNetSDK.NET_DVR_GetDVRConfig(lUserID, HCNetSDK.NET_DVR_GET_PICCFG_V40, lChannel.intValue(), + pStrPicCfg, strPicCfg.size(), pInt); + strPicCfg.read(); + m_strIpparaCfg.struStreamMode[iChannum].read(); + if (m_strIpparaCfg.struStreamMode[iChannum].byGetStreamType == 0) { + m_strIpparaCfg.struStreamMode[iChannum].uGetStream.setType(HCNetSDK.NET_DVR_IPCHANINFO.class); + m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.read(); + +// System.out.println("--------------第" + (iChannum + 1) + "个通道------------------"); + int channel = m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byIPID + m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byIPIDHigh * 256; +// System.out.println("channel:" + channel); + if (channel > 0) { +// System.out.println("ip: " + new String(m_strIpparaCfg.struIPDevInfo[channel - 1].struIP.sIpV4).trim()); + cameraDTO.setIpAddress(new String(m_strIpparaCfg.struIPDevInfo[channel - 1].struIP.sIpV4).trim()); + } +// System.out.println("name: " + new String(strPicCfg.sChanName, "GBK").trim()); + cameraDTO.setName(new String(strPicCfg.sChanName).trim()); + // cameraDTO.setChannelNumber(channum); + // cameraDTO.setIpDeviceId(id); + // cameraDTO.setChannelDriver(0); + // cameraDTO.setType(1); + // cameraDTO.setVideoType(Integer.valueOf(m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byChannel)); + System.out.println("通道名称:"+cameraDTO.getName()+"通道号:"+channum); + if (m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byEnable == 1) { + cameraDTO.setStatus(1); +// System.out.println("IP通道" + channum + "在线"); + } else { + cameraDTO.setStatus(0); +// System.out.println("IP通道" + channum + "不在线"); + } + } + if (cameraDTO.getIpAddress() != null) { + channelList.add(cameraDTO); + } + } + + return channelList; + } + + + /** + * 抓拍图片 + * + * @param channel 通道号 + */ + public boolean getDVRPic(int channel, String path) { + + HCNetSDK.NET_DVR_WORKSTATE_V30 devwork = new HCNetSDK.NET_DVR_WORKSTATE_V30(); + if (!hCNetSDK.NET_DVR_GetDVRWorkState_V30(lUserID, devwork)) { + // 返回Boolean值,判断是否获取设备能力 + logger.info("hksdk(抓图)-返回设备状态失败"); + } + //图片质量 + HCNetSDK.NET_DVR_JPEGPARA jpeg = new HCNetSDK.NET_DVR_JPEGPARA(); + //设置图片分辨率 + jpeg.wPicSize = 4; + //设置图片质量 + jpeg.wPicQuality = 0; + IntByReference a = new IntByReference(); + //需要加入通道 + boolean ok = hCNetSDK.NET_DVR_CaptureJPEGPicture(lUserID,channel,jpeg,path.getBytes()); + if (ok) { + logger.info("hksdk(抓图)-结果状态值(0表示成功):" + hCNetSDK.NET_DVR_GetLastError()); + } else { + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.info("hksdk(抓图)-抓取失败,错误码:" + m_err.getValue() + "," + err); + } + return ok; + } + + /** + * 下载录像 + * @return boolean + */ + public boolean downloadBack(LocalDateTime startTime, LocalDateTime endTime, String filePath, int channel) throws InterruptedException { + loadHandle = -1; + loadHandle = hCNetSDK.NET_DVR_GetFileByTime(lUserID, channel, getHkTime(startTime), getHkTime(endTime), filePath); + if (loadHandle >= 0) { + //开始下载 + boolean downloadFlag = hCNetSDK.NET_DVR_PlayBackControl(loadHandle, hCNetSDK.NET_DVR_PLAYSTART, 0, null); + int tmp = -1; + IntByReference pos = new IntByReference(0); + while (loadHandle >= 0) { + boolean backFlag = hCNetSDK.NET_DVR_PlayBackControl(loadHandle, hCNetSDK.NET_DVR_PLAYGETPOS, 0, pos); + if (!backFlag) {//防止单个线程死循环 + return downloadFlag; + } + int produce = pos.getValue(); + if ((produce % 10) == 0 && tmp != produce) {//输出进度 + tmp = produce; + logger.info("视频下载进度:" + "==" + produce + "%"); + } + if (produce == 100) {//下载成功 + hCNetSDK.NET_DVR_StopGetFile(loadHandle); + loadHandle = -1; + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.info("下载结束,last error: " + m_err.getValue() + "," + err); + return true; + } + if (produce > 100) {//下载失败 + hCNetSDK.NET_DVR_StopGetFile(loadHandle); + loadHandle = -1; + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.warn("下载异常终止!错误原因:" + m_err.getValue() + "," + err); + return false; + } + Thread.sleep(500); + } + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.warn("下载异常终止!错误原因:" + m_err.getValue() + "," + err); + return false; + } else { + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.warn("获取录像文件错误!错误原因:" + m_err.getValue() + "," + err); + return false; + } + } + + /** + * 获取录像文件信息 + * @Return: + */ + public List> getVideoFileList(LocalDateTime startTime, LocalDateTime endTime, int channel) { + List> fileList = new ArrayList<>(); + + // 搜索条件 + HCNetSDK.NET_DVR_FILECOND m_strFilecond = new HCNetSDK.NET_DVR_FILECOND(); + + m_strFilecond.struStartTime = getHkTime(startTime); + m_strFilecond.struStopTime = getHkTime(endTime); + m_strFilecond.lChannel = channel;//通道号 + + int lFindFile = hCNetSDK.NET_DVR_FindFile_V30(lUserID, m_strFilecond); + HCNetSDK.NET_DVR_FINDDATA_V30 strFile = new HCNetSDK.NET_DVR_FINDDATA_V30(); + if (lFindFile < 0) { + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.warn("获取录像文件错误!错误原因:" + m_err.getValue() + "," + err); + return null; + } + int lnext; + strFile = new HCNetSDK.NET_DVR_FINDDATA_V30(); + HashMap map = new HashMap<>(); + boolean flag=true; + while (flag) { + lnext = hCNetSDK.NET_DVR_FindNextFile_V30(lFindFile, strFile); + if (lnext == HCNetSDK.NET_DVR_FILE_SUCCESS) { + //搜索成功 + //添加文件名信息 + String[] s = new String[2]; + s = new String(strFile.sFileName).split("\0", 2); + map.put("fileName:", new String(s[0])); + + int iTemp; + String MyString; + if (strFile.dwFileSize < 1024 * 1024) { + iTemp = (strFile.dwFileSize) / (1024); + MyString = iTemp + "K"; + } else { + iTemp = (strFile.dwFileSize) / (1024 * 1024); + MyString = iTemp + "M "; + iTemp = ((strFile.dwFileSize) % (1024 * 1024)) / (1204); + MyString = MyString + iTemp + "K"; + } + map.put("fileSize", MyString); //添加文件大小信息 + map.put("struStartTime", strFile.struStartTime.toStringTime()); //添加开始时间信息 + map.put("struStopTime", strFile.struStopTime.toStringTime()); //添加结束时间信息 + fileList.add(map); + } else { + if (lnext == HCNetSDK.NET_DVR_ISFINDING) {//搜索中 + //System.out.println("搜索中"); + continue; + } else { + flag=false; + if (lnext == HCNetSDK.NET_DVR_FILE_NOFIND) { + //flag=false; + } else { + //flag=false; + System.out.println("搜索文件结束"); + boolean flag2 = hCNetSDK.NET_DVR_FindClose_V30(lFindFile); + if (flag2 == false) { + System.out.println("结束搜索失败"); + } + } + } + } + } + return fileList; + } + + public boolean playControl(String command,int mill,int channel) throws InterruptedException { + HCPlayControlEnum controlEnum = HCPlayControlEnum.valueOf(command); + boolean playHandle = false; + //开始控制 + playHandle = hCNetSDK.NET_DVR_PTZControl_Other(lUserID,channel,controlEnum.getCode(),0); + if(!playHandle){ + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.warn("(开始)控制失败!错误原因:" + m_err.getValue() + "," + err); + return false; + } + //控制时间 + Thread.sleep(mill); + //停止控制 + playHandle = hCNetSDK.NET_DVR_PTZControl_Other(lUserID,channel,controlEnum.getCode(),1); + if(!playHandle){ + String err = hCNetSDK.NET_DVR_GetErrorMsg(m_err); + logger.warn("(停止)控制失败!错误原因:" + m_err.getValue() + "," + err); + return false; + } + return true; + } + + /** + * 获取海康录像机格式的时间 + * + * @param time + * @return + */ + public HCNetSDK.NET_DVR_TIME getHkTime(LocalDateTime time) { + HCNetSDK.NET_DVR_TIME structTime = new HCNetSDK.NET_DVR_TIME(); + + String str = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss").format(time); + String[] times = str.split("-"); + structTime.dwYear = Integer.parseInt(times[0]); + structTime.dwMonth = Integer.parseInt(times[1]); + structTime.dwDay = Integer.parseInt(times[2]); + structTime.dwHour = Integer.parseInt(times[3]); + structTime.dwMinute = Integer.parseInt(times[4]); + structTime.dwSecond = Integer.parseInt(times[5]); + return structTime; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HIKSDKStructure.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HIKSDKStructure.java new file mode 100644 index 0000000..679ba91 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HIKSDKStructure.java @@ -0,0 +1,34 @@ +package com.sz.admin.monitor.sdk.hkSdk; + +import com.sun.jna.Structure; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +/** + * @author: zxsong + * @Desc: 解决海康jna版本过低,无法与大华高版本jna兼容问题 + * @create: 2025-02-10 15:30 + */ +public class HIKSDKStructure extends Structure{ + @Override + protected List getFieldOrder(){ + List fieldOrderList = new ArrayList(); + for (Class cls = getClass(); + !cls.equals(HIKSDKStructure.class); + cls = cls.getSuperclass()) { + Field[] fields = cls.getDeclaredFields(); + int modifiers; + for (Field field : fields) { + modifiers = field.getModifiers(); + if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) { + continue; + } + fieldOrderList.add(field.getName()); + } + } + return fieldOrderList; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HkNVR.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HkNVR.java new file mode 100644 index 0000000..b508354 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/sdk/hkSdk/HkNVR.java @@ -0,0 +1,688 @@ +package com.sz.admin.monitor.sdk.hkSdk; + +import cn.hutool.core.date.DateUtil; +import com.sun.jna.Native; +import com.sun.jna.NativeLong; +import com.sun.jna.Pointer; +import com.sun.jna.ptr.IntByReference; +import com.sz.admin.monitor.common.CommonKit; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.RecordFile; +import com.sz.admin.monitor.sdk.AbstractNVR; +import com.sz.admin.monitor.utils.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.sz.admin.monitor.sdk.hkSdk.HCNetSDK.NET_DVR_CHECK_USER_STATUS; + +/** + * ClassName: HKNVR + * Package: com.sz.admin.monitor.hik + * Description: + */ +@Component +@Slf4j +public class HkNVR extends AbstractNVR { + static HCNetSDK hCNetSDK = null; + static FExceptionCallBack_Imp fExceptionCallBack;//异常回调 + private final VcrlUserIdContainer vcrlUserIdContainer; + // Linux系统下的SDK路径 + private String hkSdkLibPath = "/home/rytec/sdk/libsHK/"; + // 抓图的保存前置路径 + private String pathPrefix="D:\\work\\images\\"; + // 录像的保存前置路径 + private String recordPic = "D:\\work\\"; + + public HkNVR(VcrlUserIdContainer vcrlUserIdContainer) { + super(); + this.vcrlUserIdContainer = vcrlUserIdContainer; + } + + @Override + public HCNetSDK registerPlugin() { + if (hCNetSDK == null) { + if (!createSDKInstance()) { + System.out.println("Load SDK fail"); + return null; + } + } + //linux系统建议调用以下接口加载组件库 + if (osSelect.isLinux()) { + HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256); + HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256); + //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限 + String strPath1 = hkSdkLibPath + "libcrypto.so.1.1"; + String strPath2 = hkSdkLibPath + "libssl.so.1.1"; + + System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length()); + ptrByteArray1.write(); + hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer()); + + System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length()); + ptrByteArray2.write(); + hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer()); + + String strPathCom = hkSdkLibPath; + HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH(); + System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length()); + struComPath.write(); + hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer()); + } + //SDK初始化,一个程序进程只需要调用一次 + hCNetSDK.NET_DVR_Init(); + if (fExceptionCallBack == null) { + fExceptionCallBack = new FExceptionCallBack_Imp(); + } + Pointer pUser = null; + if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) { + return null; + } + System.out.println("设置异常消息回调成功"); + + //启用SDK写日志 +// hCNetSDK.NET_DVR_SetLogToFile(3, "./sdkLog", false); + return hCNetSDK; + } + + @Override + public int loginVcr(String ipAddress, String port, String userName, String password) { + return login_V40(ipAddress, Short.parseShort(port), userName, password); + } + + @Override + public boolean ptzControl(int luerId, int iChannel, String ptzCommand, String dwStop, int dwSpeed) { + //带速度的云台控制操作(不用启动图象预览) + return hCNetSDK.NET_DVR_PTZControlWithSpeed_Other(luerId, iChannel, Integer.parseInt(ptzCommand), Integer.parseInt(dwStop), dwSpeed); + } + + @Override + public boolean ptzPreset(int luerId, int iChannel, int ptzPresetCmd, String dwPresetIndex) { + //云台预置点操作(不用启动预览) + boolean b = hCNetSDK.NET_DVR_PTZPreset_Other(luerId, iChannel, ptzPresetCmd, Integer.parseInt(dwPresetIndex)); + if(!b){ + log.error("调用(设置)预置点失败,错误码:{}", hCNetSDK.NET_DVR_GetLastError()); + } + return b; + } + + @Override + public boolean ptzPreset(int luerId, int iChannel, int ptzPresetCmd, String dwPresetIndex, String pointName) { + boolean b = hCNetSDK.NET_DVR_PTZPreset_Other(luerId, iChannel, ptzPresetCmd, Integer.parseInt(dwPresetIndex)); + if(!b){ + log.error("调用(设置)预置点失败,错误码:{}", hCNetSDK.NET_DVR_GetLastError()); + } +// else { +// if(!ptzPresetCmd.equals("39")){ +// boolean b1 = setPresetName(luerId, iChannel, Integer.parseInt(dwPresetIndex), pointName); +// try { +// String r = IsapiPtzPreset.renamePreset("192.168.2.205", 1, 2, "admin", "rytec.2020", "acxfsvdgfvgfvcgmmmmmmmmmmmmmmmmmmm"); +// } catch (Exception e) { +// throw new RuntimeException(e); +// } +// } +// } + return b; + } + + @Override + public String capturePic(int luerId, int iChannel,String fileName) { + return captureP(luerId, iChannel,fileName); + } + /** + * 动态库加载 + * + * + * @return + */ + private boolean createSDKInstance() { + if (hCNetSDK == null) { + synchronized (HCNetSDK.class) { + String strDllPath = ""; + try { + if (osSelect.isWindows()) + //win系统加载SDK库路径 + { + strDllPath = CommonKit.class.getClassLoader().getResource("").getPath().substring(1) + "lib\\win\\HCNetSDK.dll"; + } else if (osSelect.isLinux()) + //Linux系统加载SDK库路径 + { + strDllPath = System.getProperty("user.dir") + "/intelligent-inspection-NVRSDK/libs/HKSDK/libhcnetsdk.so"; + // strDllPath = hkSdkLibPath + "libhcnetsdk.so"; + } + hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class); + + } catch (Exception ex) { + System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage()); + return false; + } + } + } + return true; + } + /** + * 异常消息回调 + */ + static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack { + @Override + public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) { + log.error("异常事件类型:" + dwType); + } + } + /** + * 设备登录 + * + * @param ip 设备IP + * @param port SDK端口,默认设备的8000端口 + * @param user 设备用户名 + * @param psw 设备密码 + */ + public int login_V40(String ip, short port, String user, String psw) { + + //设置连接时间 + hCNetSDK.NET_DVR_SetConnectTime(5000, 1); + //设置重连时间 + hCNetSDK.NET_DVR_SetReconnect(120000, true); + hCNetSDK.NET_DVR_SetLogToFile(3, "/home/rytec/data/logs/", true);//日志 + + HCNetSDK.NET_DVR_USER_LOGIN_INFO loginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO(); + HCNetSDK.NET_DVR_DEVICEINFO_V40 devInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40(); + + System.arraycopy(ip.getBytes(StandardCharsets.US_ASCII), + 0, loginInfo.sDeviceAddress, 0, ip.length()); + System.arraycopy(user.getBytes(StandardCharsets.US_ASCII), + 0, loginInfo.sUserName, 0, user.length()); + System.arraycopy(psw.getBytes(StandardCharsets.US_ASCII), + 0, loginInfo.sPassword, 0, psw.length()); + + loginInfo.wPort = port; + loginInfo.bUseAsynLogin = false; + + loginInfo.write(); + devInfo.write(); + + int iUserID = hCNetSDK.NET_DVR_Login_V40(loginInfo, devInfo); + devInfo.read(); + if (iUserID < 0) { + log.error("{}登录失败,错误码为{}", ip, hCNetSDK.NET_DVR_GetLastError()); + } else { + log.info("{}:设备登录成功!", ip); + } + return iUserID; + } + /** + * 抓图 + * + * @param lUserId + * @param lchannel + * @return + */ + public String captureP(int lUserId, int lchannel, String fileName) { + HCNetSDK.NET_DVR_JPEGPARA jpegPara = new HCNetSDK.NET_DVR_JPEGPARA(); + jpegPara.wPicSize = (short) 0xFF; // 用当前分辨率 + jpegPara.wPicQuality = 0; // 0-最好 + jpegPara.write(); + + String path = pathPrefix + fileName; + + // 如果文件名/路径可能包含中文,按 SDK 要求改编码(例如 GBK) + byte[] pathBytes = path.getBytes(StandardCharsets.UTF_8); + + byte[] cStr = new byte[pathBytes.length + 1]; + System.arraycopy(pathBytes, 0, cStr, 0, pathBytes.length); + cStr[pathBytes.length] = 0; + + boolean ok = hCNetSDK.NET_DVR_CaptureJPEGPicture(lUserId, lchannel, jpegPara, cStr); + if (!ok) { + int err = hCNetSDK.NET_DVR_GetLastError(); + log.error("抓图失败,错误码:{}", err); + return "抓图失败,错误码:" + err; + } + return path; + } + /** + * 设备登出 + * + * @param luserId + * @return + */ + public Integer loginOut(int luserId,String ip) { + boolean b = hCNetSDK.NET_DVR_Logout_V30(luserId); + if (!b) { + return hCNetSDK.NET_DVR_GetLastError(); + } + log.info(ip+"-设备登出成功"); + return 0; + } + /** + * 获取IP通道 + */ + public List getIPChannelInfo(int iUserID, Long id) throws UnsupportedEncodingException { + List ipChannelList = new ArrayList<>(); + IntByReference ibrBytesReturned = new IntByReference(0);//获取IP接入配置参数 + HCNetSDK.NET_DVR_IPPARACFG_V40 m_strIpparaCfg = new HCNetSDK.NET_DVR_IPPARACFG_V40(); + m_strIpparaCfg.write(); + //lpIpParaConfig 接收数据的缓冲指针 + Pointer lpIpParaConfig = m_strIpparaCfg.getPointer(); + boolean bRet = hCNetSDK.NET_DVR_GetDVRConfig(iUserID, HCNetSDK.NET_DVR_GET_IPPARACFG_V40, 0, lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned); + m_strIpparaCfg.read(); +// System.out.println("起始数字通道号:" + m_strIpparaCfg.dwStartDChan); + + for (int iChannum = 0; iChannum < m_strIpparaCfg.dwDChanNum; iChannum++) { + Camera camera = new Camera(); + int channum = iChannum + m_strIpparaCfg.dwStartDChan; + HCNetSDK.NET_DVR_PICCFG_V40 strPicCfg = new HCNetSDK.NET_DVR_PICCFG_V40(); + strPicCfg.dwSize = strPicCfg.size(); + strPicCfg.write(); + Pointer pStrPicCfg = strPicCfg.getPointer(); + NativeLong lChannel = new NativeLong(channum); + IntByReference pInt = new IntByReference(0); + boolean b_GetPicCfg = hCNetSDK.NET_DVR_GetDVRConfig(iUserID, HCNetSDK.NET_DVR_GET_PICCFG_V40, lChannel.intValue(), + pStrPicCfg, strPicCfg.size(), pInt); + strPicCfg.read(); + m_strIpparaCfg.struStreamMode[iChannum].read(); + if (m_strIpparaCfg.struStreamMode[iChannum].byGetStreamType == 0) { + m_strIpparaCfg.struStreamMode[iChannum].uGetStream.setType(HCNetSDK.NET_DVR_IPCHANINFO.class); + m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.read(); + +// System.out.println("--------------第" + (iChannum + 1) + "个通道------------------"); + int channel = m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byIPID + m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byIPIDHigh * 256; +// System.out.println("channel:" + channel); + if (channel > 0) { +// System.out.println("ip: " + new String(m_strIpparaCfg.struIPDevInfo[channel - 1].struIP.sIpV4).trim()); + camera.setIpAddress(new String(m_strIpparaCfg.struIPDevInfo[channel - 1].struIP.sIpV4).trim()); + } +// System.out.println("name: " + new String(strPicCfg.sChanName, "GBK").trim()); + camera.setName(new String(strPicCfg.sChanName, "GBK").trim()); + // 通道号 + camera.setChannelId(channum); + // 所属 NVR + camera.setNvrId(id); + // 用于区分海康,大华的通道 + camera.setChannelDriver(0); + // 云台类型 0-枪机 1-球体 + camera.setType(1); + // 可见光 红外 + camera.setVideoType(Integer.valueOf(m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byChannel)); + if (m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byEnable == 1) { + camera.setStatus(1); // 1-在线 +// System.out.println("IP通道" + channum + "在线"); + } else { + camera.setStatus(0); // 0-离线 +// System.out.println("IP通道" + channum + "不在线"); + } + } + if (camera.getIpAddress() != null) { + ipChannelList.add(camera); + } + } + return ipChannelList; + } + /** + * 3Dptz功能 + * + * @param lUserID + * @param lChannel + * @param threeDPtz + * @return + */ + public boolean threeDPositioning(int lUserID, int lChannel, ThreeDPtz threeDPtz) { + HCNetSDK.NET_DVR_POINT_FRAME point_frame = new HCNetSDK.NET_DVR_POINT_FRAME(); + point_frame.xTop = (int) (threeDPtz.getxTop() * 255 / threeDPtz.getRealPlayWndWidth()); + point_frame.xBottom = (int) (threeDPtz.getxBottom() * 255 / threeDPtz.getRealPlayWndWidth()); + point_frame.yTop = (int) (threeDPtz.getyTop() * 255 / threeDPtz.getRealPlayWndHeight()); + point_frame.yBottom = (int) (threeDPtz.getyBottom() * 255 / threeDPtz.getRealPlayWndHeight()); + point_frame.write(); + boolean b = hCNetSDK.NET_DVR_PTZSelZoomIn_EX(lUserID, lChannel, point_frame); + + if(!b){ + log.error("3Dptz功能错误码:{}", hCNetSDK.NET_DVR_GetLastError()); + } + return b; + } + /** + * 云台守望 + * @return + */ + public static HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG getWatchCfg(HCNetSDK sdk, int userId, int channel) { + HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG cfg = new HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG(); + cfg.dwSize = cfg.size(); + cfg.write(); + + IntByReference bytesReturned = new IntByReference(0); + boolean ok = sdk.NET_DVR_GetDVRConfig( + userId, + HCNetSDK.NET_DVR_GET_PTZ_PARKACTION_CFG, + channel, + cfg.getPointer(), + cfg.size(), + bytesReturned + ); + + if (!ok) { + System.out.println("GET 守望配置失败 err=" + sdk.NET_DVR_GetLastError()); + return null; + } + + cfg.read(); + return cfg; + } + // 开启守望位:无操作 idleSeconds 秒后 → 回到 presetNo 预置点 + public boolean enableParkActionToPreset(int userId, int channel, int watchTime, int presetId) { + HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG cfg = new HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG(); + cfg.dwSize = cfg.size(); + + cfg.byEnable = 1; + cfg.byOneTouchSwitch = 0; + cfg.dwParkTime = watchTime; + + cfg.wActionType = 5; + cfg.wID = (short) presetId; + + cfg.write(); + + boolean ok = hCNetSDK.NET_DVR_SetDVRConfig( + userId, + HCNetSDK.NET_DVR_SET_PTZ_PARKACTION_CFG, + channel, + cfg.getPointer(), + cfg.size() + ); + + if (!ok) { + System.out.println("SET 开启守望失败 err=" + hCNetSDK.NET_DVR_GetLastError()); + return false; + } + return true; + } + // 关闭守望位 + public boolean disableParkAction(int userId, int channel) { + HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG cfg = getWatchCfg(hCNetSDK, userId, channel); + if (cfg == null) return false; + + cfg.byEnable = 0; + cfg.write(); + + boolean ok = hCNetSDK.NET_DVR_SetDVRConfig( + userId, + HCNetSDK.NET_DVR_SET_PTZ_PARKACTION_CFG, + channel, + cfg.getPointer(), + cfg.size() + ); + + if (!ok) { + System.out.println("SET 关闭守望失败 err=" + hCNetSDK.NET_DVR_GetLastError()); + return false; + } + return true; + } + /** + * 设备在线状态监测 + */ + public int getDeviceStatus(Nvr nvr) { + Integer userId = (Integer) vcrlUserIdContainer.getlUserId(nvr.getId().intValue()); + if (userId == null) { + int loginVcr = this.loginVcr( + nvr.getIp(), + String.valueOf(nvr.getPort()), + nvr.getAccount(), + nvr.getPassword() + ); + if (loginVcr < 0) { + return 0; + } + vcrlUserIdContainer.addData(nvr.getId().intValue(), loginVcr); + return 1; + } + + boolean online = hCNetSDK.NET_DVR_RemoteControl( + userId, NET_DVR_CHECK_USER_STATUS, Pointer.NULL, 0 + ); + + if (!online) { + this.loginOut(userId, nvr.getIp()); + int loginVcr = this.loginVcr( + nvr.getIp(), + String.valueOf(nvr.getPort()), + nvr.getAccount(), + nvr.getPassword() + ); + if (loginVcr == -1) { + return 0; + } + vcrlUserIdContainer.addData(nvr.getId().intValue(), loginVcr); + } + return 1; + } + private static Map realPlayV40Map = new ConcurrentHashMap(); + + /** + * 录像功能 + * @param userId 用户ID + * @param channelNumber 通道号 + * @param isRecord 是否录像 + * @param fileName 文件名 + * @return + */ + public String videotaped(Integer userId, Integer channelNumber, boolean isRecord, String fileName) { + + String key = userId + "_" + channelNumber; + Integer realPlayV40 = realPlayV40Map.get(key); + if (realPlayV40 == null) { + HCNetSDK.NET_DVR_PREVIEWINFO netDvrPreviewinfo = new HCNetSDK.NET_DVR_PREVIEWINFO(); + netDvrPreviewinfo.read(); + netDvrPreviewinfo.lChannel = channelNumber; + netDvrPreviewinfo.dwStreamType = 0; + netDvrPreviewinfo.dwLinkMode = 0; + netDvrPreviewinfo.bBlocked = 1; + netDvrPreviewinfo.bPassbackRecord = 0; + netDvrPreviewinfo.byProtoType = 1; + netDvrPreviewinfo.byVideoCodingType = 0; + netDvrPreviewinfo.write(); + realPlayV40 = hCNetSDK.NET_DVR_RealPlay_V40(userId, netDvrPreviewinfo, null, null); + realPlayV40Map.put(key, realPlayV40); + } + String path = recordPic + fileName; + if (isRecord) { + hCNetSDK.NET_DVR_SaveRealData(realPlayV40, path); + return ""; + } else { + hCNetSDK.NET_DVR_StopSaveRealData(realPlayV40); + return path; + } + } + + /** + * 在NVR设备上按时间范围搜索录像文件 + * @param userId + * @param channelNumber + * @param startTime + * @param endTime + * @return + * @throws UnsupportedEncodingException + */ + public List findRecordFile(Integer userId, Integer channelNumber, LocalDateTime startTime, LocalDateTime endTime) throws UnsupportedEncodingException { + HCNetSDK.NET_DVR_FILECOND_V40 netDvrFilecondV40 = new HCNetSDK.NET_DVR_FILECOND_V40(); + netDvrFilecondV40.read(); + netDvrFilecondV40.lChannel = channelNumber; + netDvrFilecondV40.dwFileType = 0xff; + HCNetSDK.NET_DVR_TIME startDvrTime = new HCNetSDK.NET_DVR_TIME(); + startDvrTime.dwYear= startTime.getYear(); //年 + startDvrTime.dwMonth=startTime.getMonthValue(); //月 + startDvrTime.dwDay=startTime.getDayOfMonth(); //日 + startDvrTime.dwHour=startTime.getHour(); //时 + startDvrTime.dwMinute=startTime.getMinute(); //分 + startDvrTime.dwSecond=startTime.getSecond(); //秒 + HCNetSDK.NET_DVR_TIME endDvrTime = new HCNetSDK.NET_DVR_TIME(); + endDvrTime.dwYear= endTime.getYear(); //年 + endDvrTime.dwMonth=endTime.getMonthValue(); //月 + endDvrTime.dwDay=endTime.getDayOfMonth(); //日 + endDvrTime.dwHour=endTime.getHour(); //时 + endDvrTime.dwMinute=endTime.getMinute(); //分 + endDvrTime.dwSecond=endTime.getSecond(); //秒 + netDvrFilecondV40.struStartTime = startDvrTime; + netDvrFilecondV40.struStopTime = endDvrTime; +// netDvrFilecondV40.byAudioFile = 0; + netDvrFilecondV40.write(); + int i = hCNetSDK.NET_DVR_FindFile_V40(userId, netDvrFilecondV40); + if (i<-1){ + return null; + } + List recordFiles = new ArrayList<>(); + RecordFile recordFile = null; + while (true) { + HCNetSDK.NET_DVR_FINDDATA_V40 netDvrFileDataV40 = new HCNetSDK.NET_DVR_FINDDATA_V40(); + netDvrFileDataV40.read(); + int iRet = hCNetSDK.NET_DVR_FindNextFile_V40(i, netDvrFileDataV40); + if (iRet == 1000){ + recordFile = new RecordFile(); + recordFile.setFileName(new String(netDvrFileDataV40.sFileName,StandardCharsets.UTF_8)); +// System.out.println(new String(netDvrFileDataV40.sFileName, StandardCharsets.UTF_8)); + recordFile.setStartTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStartTime.toStringTime(),"yyyy/MM/ddHH:mm:ss")); + recordFile.setStopTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStopTime.toStringTime(),"yyyy/MM/ddHH:mm:ss")); + recordFile.setFileSize(netDvrFileDataV40.dwFileSize); + recordFiles.add(recordFile); + }else if(iRet == 1003) { + System.out.println("没有更多文件"); + hCNetSDK.NET_DVR_FindClose_V30(i); + return recordFiles; + } + + } + } + /** + * 获取nvr的硬盘问题 + * @return + */ + public Map getDevCfg(String ip,int port,String user,String psw) { + Map map = new HashMap<>(); + try { + HikHdd.HddSummary sum = HikHdd.fetchHddSummaryHttp(ip, port, user, psw); + map.put("totalTiB", String.format("%.2f", sum.totalTiB())+"TiB"); + map.put("usedTiB", String.format("%.2f", sum.usedTiB())+"TiB"); + map.put("deviceNumber",String.valueOf(sum.diskCount)); + map.put("noOkCount",String.valueOf(sum.diskCount-sum.okCount)); + } catch (Exception e) { + log. error("无法访问到{}录像机,网络不可达", ip); + } + return map; + } + /** + * 获取通道录像起止时间 + */ + public List getChannelyRecordTime(int luserId,int channel,LocalDateTime startTime,LocalDateTime endTime){ + long daysBetween = ChronoUnit.DAYS.between(startTime, endTime); + if(Math.abs(daysBetween) > 90){ + long exceededDays = daysBetween - 90; + startTime = startTime.plusDays(exceededDays); + } + HCNetSDK.NET_DVR_FILECOND_V40 netDvrFilecondV40 = new HCNetSDK.NET_DVR_FILECOND_V40(); + netDvrFilecondV40.read(); + netDvrFilecondV40.lChannel = channel; + netDvrFilecondV40.dwFileType = 0xff; + HCNetSDK.NET_DVR_TIME startDvrTime = new HCNetSDK.NET_DVR_TIME(); + startDvrTime.dwYear= startTime.getYear(); //年 + startDvrTime.dwMonth=startTime.getMonthValue(); //月 + startDvrTime.dwDay=startTime.getDayOfMonth(); //日 + startDvrTime.dwHour=startTime.getHour(); //时 + startDvrTime.dwMinute=startTime.getMinute(); //分 + startDvrTime.dwSecond=startTime.getSecond(); //秒 + HCNetSDK.NET_DVR_TIME endDvrTime = new HCNetSDK.NET_DVR_TIME(); + endDvrTime.dwYear= endTime.getYear(); //年 + endDvrTime.dwMonth=endTime.getMonthValue(); //月 + endDvrTime.dwDay=endTime.getDayOfMonth(); //日 + endDvrTime.dwHour=endTime.getHour(); //时 + endDvrTime.dwMinute=endTime.getMinute(); //分 + endDvrTime.dwSecond=endTime.getSecond(); //秒 + netDvrFilecondV40.struStartTime = startDvrTime; + netDvrFilecondV40.struStopTime = endDvrTime; + netDvrFilecondV40.write(); + int i = hCNetSDK.NET_DVR_FindFile_V40(luserId, netDvrFilecondV40); + int i1 = hCNetSDK.NET_DVR_GetLastError(); + if(i == -1){ + log.error("获取分段录像文件失败,海康错误码:"+i1); + } + List recordFiles = new ArrayList<>(); + RecordFile recordFile = null; + try { + while (true) { + HCNetSDK.NET_DVR_FINDDATA_V40 netDvrFileDataV40 = new HCNetSDK.NET_DVR_FINDDATA_V40(); + netDvrFileDataV40.read(); + int iRet = hCNetSDK.NET_DVR_FindNextFile_V40(i, netDvrFileDataV40); + int i2 = hCNetSDK.NET_DVR_GetLastError(); + if(iRet == -1){ + log.error("获取分段录像文件信息失败,海康错误码:{}", i2); + break; + } + if (iRet == 1000){ + recordFile = new RecordFile(); + recordFile.setStartTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStartTime.toStringTime(),"yyyy/MM/ddHH:mm:ss")); + recordFile.setStopTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStopTime.toStringTime(),"yyyy/MM/ddHH:mm:ss")); + recordFiles.add(recordFile); + }else if(iRet == 1003) { + log.info("已获取全部分段录像文件信息"); + break; + }else if(iRet == 1001){ + log.info("此摄像机在此时间段没有录像"); + break; + }else { + break; + } + } + }finally { + hCNetSDK.NET_DVR_FindClose_V30(i); + } + + return recordFiles; + } + public boolean checkCameraThree(int luerId){ + return Hik3DptzChecker.isSupport3DPTZ(hCNetSDK, luerId); + } + // 返回最后操作的错误码 + public int getLastError() + { + return hCNetSDK.NET_DVR_GetLastError(); + } + + // 定义获取 PTZ 坐标的专用函数 + public Map NET_DVR_GetPTZPos(int userId, int channelId) { + HCNetSDK.NET_DVR_PTZPOS ptzPos = new HCNetSDK.NET_DVR_PTZPOS(); + ptzPos.wAction = 1; // 某些老设备要求填1 + ptzPos.write(); // 关键:将 Java 字段的值写入内存 (初始化) + + // 2. 准备返回长度变量 + IntByReference lpBytesReturned = new IntByReference(0); + boolean result = hCNetSDK.NET_DVR_GetDVRConfig( + userId, + HCNetSDK.NET_DVR_GET_PTZPOS, // 命令号 292 + channelId, // NVR 通道通常是 33 + ptzPos.getPointer(), // 接收数据的结构体 + ptzPos.size(), // 结构体大小 + lpBytesReturned // SDK 告诉你实际写了多少字节 + ); + if (!result) { + System.err.println("获取坐标失败,错误码: " + hCNetSDK.NET_DVR_GetLastError()); + return null; // 或者抛出异常 + } + ptzPos.read(); + int pan = ptzPos.wPanPos & 0xFFFF; + int tilt = ptzPos.wTiltPos & 0xFFFF; + int zoom = ptzPos.wZoomPos & 0xFFFF; + Map map = new HashMap<>(); + map.put("pan", pan); + map.put("tilt", tilt); + map.put("zoom", zoom); + return map; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/AlgorithmTaskService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/AlgorithmTaskService.java new file mode 100644 index 0000000..338be64 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/AlgorithmTaskService.java @@ -0,0 +1,26 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.edgebox.AlarmReportDTO; +import com.sz.admin.monitor.pojo.po.AlgorithmTask; +import com.sz.admin.monitor.pojo.po.CameraAlarm; +import com.sz.admin.monitor.pojo.vo.cameraalarm.CameraAlarmVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlgorithmTaskVO; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: AlgorithmTaskService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface AlgorithmTaskService extends IService { + + // 根据摄像头id获取算法任务 + AlgorithmTaskVO getAlgorithmTaskByCameraId(Long cameraId); + // 报警上报接口 + CameraAlarmVO alarmReport(AlarmReportDTO alarmReportDto); + + List listByCameraIds(List ids); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraAlarmService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraAlarmService.java new file mode 100644 index 0000000..c33b0d8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraAlarmService.java @@ -0,0 +1,45 @@ +package com.sz.admin.monitor.service; + + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmCreateDTO; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmListDTO; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmUpdateDTO; +import com.sz.admin.monitor.pojo.po.CameraAlarm; +import com.sz.admin.monitor.pojo.vo.cameraalarm.CameraAlarmVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlarmReportVO; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + *

+ * 告警工单表 Service + *

+ * + * @author Lz + * @since 2026-02-10 + */ +public interface CameraAlarmService extends IService { + + void create(CameraAlarmCreateDTO dto); + + void update(CameraAlarmUpdateDTO dto); + + PageResult page(CameraAlarmListDTO dto); + + List list(CameraAlarmListDTO dto); + + void remove(SelectIdsDTO dto); + + CameraAlarmVO detail(Object id); + + void importExcel(ImportExcelDTO dto); + + void exportExcel(CameraAlarmListDTO dto, HttpServletResponse response); + // 根据id查询算法报警的详细信息 + AlarmReportVO getAlarmReportDetail(Long id); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraService.java new file mode 100644 index 0000000..44aa070 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraService.java @@ -0,0 +1,52 @@ +package com.sz.admin.monitor.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.mybatisflex.core.service.IService; + +import com.sz.admin.monitor.pojo.dto.camera.CameraListDTO; +import com.sz.admin.monitor.pojo.dto.camera.CameraUpdateDTO; +import com.sz.admin.monitor.pojo.po.Camera; + +import com.sz.admin.monitor.pojo.vo.camera.CameraVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlgorithmTaskVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: CameraService + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +public interface CameraService extends IService { + // 根据通道号查询摄像头信息 + Camera getByChannelId(Integer channelId); + + void update(CameraUpdateDTO dto); + + PageResult page(CameraListDTO dto); + + List list(CameraListDTO dto); + + void remove(SelectIdsDTO dto); + + CameraVO detail(Long id); + + // 根据IP地址更新守望位 + void updateWatchfulStateByIp(String ipAddress, int watchfulState); + + List remoteSearch(String keyword); + + // 查询开启巡航功能的摄像机 + List selectListByInspection(); + void batchDeleteLocalData(List cameraIds, List taskList); + + // 获取还没有绑定盒子的摄像头列表 + List getUnboundList(); + + // 获取已经绑定盒子的摄像头列表 + List getBoundList(Long boxId); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraSnapshotService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraSnapshotService.java new file mode 100644 index 0000000..8a5bd87 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/CameraSnapshotService.java @@ -0,0 +1,28 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.CameraSnapshot; +import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: CameraSnapshotService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface CameraSnapshotService extends IService { + + // 抓图的接口 + CameraSnapshotVO captureAndSave(Long id, int triggerType); + + CameraSnapshotVO captureAndSave(Long id, int triggerType, int presetIndex); + + // 根据 摄像头id和预置位查询 + CameraSnapshotVO selectByCameraIdAndPresetIndex(Long id, int presetIndex); + // 根据摄像头ID查询快照列表 + List getExistSnapshotList(Long id); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/DeviceService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/DeviceService.java new file mode 100644 index 0000000..5ec18c8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/DeviceService.java @@ -0,0 +1,16 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.po.Nvr; + +/** + * ClassName: DeviceService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface DeviceService extends IService { + Boolean refresh(Long id, Integer deviceType); + + // 设备登录 + Object deviceLogin(Long id); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/EdgeBoxService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/EdgeBoxService.java new file mode 100644 index 0000000..d596b59 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/EdgeBoxService.java @@ -0,0 +1,46 @@ +package com.sz.admin.monitor.service; + + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxBindCamerasDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxCreateDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxListDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.EdgeBoxUpdateDTO; +import com.sz.admin.monitor.pojo.po.EdgeBox; +import com.sz.admin.monitor.pojo.vo.edgebox.EdgeBoxVO; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + *

+ * 边缘盒子 Service + *

+ * + * @author Lz + * @since 2026-03-05 + */ +public interface EdgeBoxService extends IService { + + void create(EdgeBoxCreateDTO dto); + + void update(EdgeBoxUpdateDTO dto); + + PageResult page(EdgeBoxListDTO dto); + + List list(EdgeBoxListDTO dto); + + void remove(SelectIdsDTO dto); + + EdgeBoxVO detail(Object id); + + void importExcel(ImportExcelDTO dto); + + void exportExcel(EdgeBoxListDTO dto, HttpServletResponse response); + + // 给盒子绑定摄像头通道 + void bindCameras(EdgeBoxBindCamerasDTO dto); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceImageService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceImageService.java new file mode 100644 index 0000000..8494856 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceImageService.java @@ -0,0 +1,25 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.po.FaceImage; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.vo.faceimage.FaceImageVO; +import org.springframework.web.multipart.MultipartFile; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: FaceImageService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface FaceImageService extends IService { + String fileUpload(MultipartFile file); + // 根据人脸ID查询人脸图片 + List getByFaceId(Long id); + // 人脸图片上传直接与人脸信息表绑定 + void fileUploadBind(MultipartFile file, Long id); + // 根据人脸ID删除人脸图片 + void removeByFaceIds(List ids); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceInfoService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceInfoService.java new file mode 100644 index 0000000..215f640 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceInfoService.java @@ -0,0 +1,45 @@ +package com.sz.admin.monitor.service; + + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoCreateDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoListDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoUpdateDTO; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.vo.faceinfo.FaceInfoVO; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.Serializable; +import java.util.List; + +/** + *

+ * 人脸信息表 Service + *

+ * + * @author Lz + * @since 2026-02-26 + */ +public interface FaceInfoService extends IService { + + void create(FaceInfoCreateDTO dto); + + void update(FaceInfoUpdateDTO dto); + + PageResult page(FaceInfoListDTO dto); + + List list(FaceInfoListDTO dto); + + void remove(SelectIdsDTO dto); + + FaceInfoVO detail(Object id); + + void importExcel(ImportExcelDTO dto); + + void exportExcel(FaceInfoListDTO dto, HttpServletResponse response); + // 根据库ID删除人脸信息 + void removeByLibraryIds(List ids); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceLibraryService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceLibraryService.java new file mode 100644 index 0000000..b1eb661 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/FaceLibraryService.java @@ -0,0 +1,42 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoCreateDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoListDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryCreateDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryListDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryUpdateDTO; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.po.FaceLibrary; +import com.sz.admin.monitor.pojo.vo.faceinfo.FaceInfoVO; +import com.sz.admin.monitor.pojo.vo.facelibrary.FaceLibraryVO; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + * ClassName: FaceLibraryService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface FaceLibraryService extends IService { + + void create(FaceLibraryCreateDTO dto); + + void update(FaceLibraryUpdateDTO dto); + + PageResult page(FaceLibraryListDTO dto); + + List list(FaceLibraryListDTO dto); + + void remove(SelectIdsDTO dto); + + FaceLibraryVO detail(Object id); + + void importExcel(ImportExcelDTO dto); + + void exportExcel(FaceLibraryListDTO dto, HttpServletResponse response); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/ForwardService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/ForwardService.java new file mode 100644 index 0000000..3048826 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/ForwardService.java @@ -0,0 +1,17 @@ +package com.sz.admin.monitor.service; + +import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * ClassName: ForwardService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface ForwardService { + /** + * 转发报警方法 + */ + void enrichAndForward(BoxAlarmReportDto boxAlarm); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/IpChannelService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/IpChannelService.java new file mode 100644 index 0000000..8e5a760 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/IpChannelService.java @@ -0,0 +1,39 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.edgebox.AlgorithmTaskDTO; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.vo.watchful.WatchfulVO; +import com.sz.admin.monitor.utils.AlgMediaConfigResponse; + +/** + * ClassName: IpChannelService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface IpChannelService extends IService { + // 根据通道号查询摄像头信息 + Camera getByChannelId(Integer channelId); + // 视频预览接口 + String preview(Long id) ; + + // 停止预览 + Integer stopPreview(Long id, String uuid); + // 云台控制 + Object ptzControl(Long id, Integer direction, int speed, int startFlag); + // 控制预置位 + Object controlPreset(Long id, int ptzPresetCmd, int dwPresetIndex, String pointName, int isBasicPoint); + + // 心跳保活 + void userHeartbeat(Long id,String uuid); + + // 控制云台守望功能 + boolean ControlSentinel(Long id, int openOrNo, int watchTime, Integer presetIndex); + + // 获取云台守望的参数 + WatchfulVO getWatchful(Long id); + // 配置算法任务 + AlgMediaConfigResponse configAlg(AlgorithmTaskDTO algTaskConfigDto); + +// void resetSentinel(int channelId, int watchTime, int presetIndex); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/NvrService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/NvrService.java new file mode 100644 index 0000000..3b461fc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/NvrService.java @@ -0,0 +1,41 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.nvr.NvrDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrCreateDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrListDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrUpdateDTO; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.vo.nvr.NvrVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.List; + +/** + * ClassName: NvrService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface NvrService extends IService { + + + // 更新设备的状态 + void upStatusById(Long id, int status); + + Long create(NvrCreateDTO dto); + + void update(NvrUpdateDTO dto); + + PageResult page(NvrListDTO dto); + + List list(NvrListDTO dto); + + void remove(SelectIdsDTO dto); + + NvrVO detail(Long id); + // 获取指定节点下的所有NVR数据 + PageResult listByNode(Long nodeId, Integer type, Integer pageNum, Integer pageSize); + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/PresetService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/PresetService.java new file mode 100644 index 0000000..8e3dd63 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/PresetService.java @@ -0,0 +1,37 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.preset.PresetCreateDTO; +import com.sz.admin.monitor.pojo.dto.preset.PresetDeleteDTO; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.Preset; +import com.sz.admin.monitor.pojo.vo.Region.RegionVO; +import com.sz.admin.monitor.pojo.vo.preset.PresetVO; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: PresetService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface PresetService extends IService { + List getPresetList(Long id); + + // 删除预置位 + void removePreset(PresetDeleteDTO dto); + + // 新增预置位 + void create(PresetCreateDTO dto); + + // 根据 摄像头id和当前预置点查询 + Preset selectByCameraIdAndPresetIndex(Long cameraId, int presetIndex); + + // 查询数据库中已经存在的预置位 + List getExistPresetList(Long cameraId); + + // 查询设置了标准位的通道号的预置位 + List selectByCameraIds(List cameraIds); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/RegionService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/RegionService.java new file mode 100644 index 0000000..1df247a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/RegionService.java @@ -0,0 +1,34 @@ +package com.sz.admin.monitor.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.region.RegionCreateDTO; +import com.sz.admin.monitor.pojo.dto.region.RegionListDTO; +import com.sz.admin.monitor.pojo.dto.region.RegionUpdateDTO; +import com.sz.admin.monitor.pojo.po.Region; +import com.sz.admin.monitor.pojo.vo.Region.RegionVO; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + * ClassName: RegionService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface RegionService extends IService { + void create(RegionCreateDTO dto); + + void update(RegionUpdateDTO dto); + + PageResult page(RegionListDTO dto); + + List list(RegionListDTO dto); + + void remove(SelectIdsDTO dto); + + RegionVO detail(Long id); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/SubstationService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/SubstationService.java new file mode 100644 index 0000000..b232dcd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/SubstationService.java @@ -0,0 +1,42 @@ +package com.sz.admin.monitor.service; + + +import com.mybatisflex.core.service.IService; +import com.sz.admin.monitor.pojo.dto.substation.SubstationCreateDTO; +import com.sz.admin.monitor.pojo.dto.substation.SubstationListDTO; +import com.sz.admin.monitor.pojo.dto.substation.SubstationUpdateDTO; +import com.sz.admin.monitor.pojo.po.Substation; +import com.sz.admin.monitor.pojo.vo.substation.SubstationVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import com.sz.core.common.entity.ImportExcelDTO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + *

+ * 变电站和超高压信息表 Service + *

+ * + * @author Lz + * @since 2026-03-06 + */ +public interface SubstationService extends IService { + + void create(SubstationCreateDTO dto); + + void update(SubstationUpdateDTO dto); + + PageResult page(SubstationListDTO dto); + + List list(SubstationListDTO dto); + + void remove(SelectIdsDTO dto); + + SubstationVO detail(Object id); + + void importExcel(ImportExcelDTO dto); + void exportExcel(SubstationListDTO dto, HttpServletResponse response); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/TreeService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/TreeService.java new file mode 100644 index 0000000..495a59f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/TreeService.java @@ -0,0 +1,20 @@ +package com.sz.admin.monitor.service; + + + +import com.sz.admin.monitor.pojo.vo.tree.TreeNodeVO; + +import java.util.List; + +/** + * ClassName: TreeService + * Package: com.sz.admin.monitor.service + * Description: + */ +public interface TreeService { + + List buildTree(); + + // 获取视频预览的树型结构数据 + List buildTreePreview(); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/AlgorithmTaskServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/AlgorithmTaskServiceImpl.java new file mode 100644 index 0000000..fce8632 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/AlgorithmTaskServiceImpl.java @@ -0,0 +1,182 @@ +package com.sz.admin.monitor.service.impl; + +import cn.hutool.core.lang.UUID; +import com.alibaba.fastjson.JSON; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.enums.AlarmReportEnums; +import com.sz.admin.monitor.mapper.AlgorithmTaskMapper; +import com.sz.admin.monitor.mapper.CameraAlarmMapper; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.NvrMapper; +import com.sz.admin.monitor.pojo.dto.edgebox.AlarmReportDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto; +import com.sz.admin.monitor.pojo.po.AlgorithmTask; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.CameraAlarm; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.vo.cameraalarm.CameraAlarmVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlarmReportVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlgorithmTaskVO; +import com.sz.admin.monitor.service.AlgorithmTaskService; +import com.sz.admin.monitor.service.ForwardService; +import com.sz.admin.monitor.utils.ImageNameUtils; +import com.sz.admin.system.pojo.dto.sysmessage.Message; +import com.sz.admin.system.service.SysMessageService; +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.enums.MessageTransferScopeEnum; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.JsonUtils; +import com.sz.redis.WebsocketRedisService; +import com.sz.security.core.util.LoginUtils; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * ClassName: AlgorithmTaskServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +@Slf4j +public class AlgorithmTaskServiceImpl extends ServiceImpl implements AlgorithmTaskService { + @Resource + private AlgorithmTaskMapper algorithmTaskMapper; + @Resource + private CameraMapper cameraMapper; + @Resource + private NvrMapper nvrMapper; + @Resource + private CameraAlarmMapper cameraAlarmMapper; + @Resource + private WebsocketRedisService websocketRedisService; + @Resource + private ForwardService forwardService; + @Resource + private SysMessageService sysMessageService; + private final String IMAGE_ROOT_PATH = "D:/work/images/"; + @Override + public AlgorithmTaskVO getAlgorithmTaskByCameraId(Long cameraId) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(AlgorithmTask.class) + .where(AlgorithmTask::getCameraId).eq(cameraId); + AlgorithmTask algorithmTask = algorithmTaskMapper.selectOneByQuery(wrapper); + if (algorithmTask == null) { + return null; + } + return BeanCopyUtils.copy(algorithmTask, AlgorithmTaskVO.class); + } + private String saveBase64AsFile(String base64Image, Long cameraId) { + byte[] imageBytes = Base64.getDecoder().decode(base64Image); + String fileName = ImageNameUtils.generateFileName("ALARM", cameraId); + File dir = new File(IMAGE_ROOT_PATH); + if (!dir.exists()) { + dir.mkdirs(); + } + File file = new File(IMAGE_ROOT_PATH + fileName); + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(imageBytes); + }catch (Exception e) + { + log.error("保存图片失败", e); + throw new RuntimeException("保存图片失败"); + } + return IMAGE_ROOT_PATH + fileName; + } + @Override + public CameraAlarmVO alarmReport(AlarmReportDTO alarmReportDto) { + CameraAlarm cameraAlarm = new CameraAlarm(); + // 根据告警的任务标识获取算法任务信息 + AlgorithmTask algorithmTask = algorithmTaskMapper.selectOneByQuery(QueryWrapper.create() + .select() + .from(AlgorithmTask.class) + .where(AlgorithmTask::getAlgTaskSession).eq(alarmReportDto.getTaskSession())); + // 根据算法任务信息获取摄像头信息 + Long cameraId = algorithmTask.getCameraId(); + cameraAlarm.setCameraId(cameraId); + Camera camera = cameraMapper.selectOneById(cameraId); + cameraAlarm.setChannelId(camera.getChannelId()); + cameraAlarm.setCameraNo(camera.getCameraNo()); + // 设置告警区域 + // 根据摄像头查询它对应的nvr + Nvr nvr = nvrMapper.selectOneById(camera.getNvrId()); + // 设置告警区域 + cameraAlarm.setAlarmAreaId(nvr.getStationId()); + // 获取Base64的字符串 + String imageData = alarmReportDto.getImageData(); + cameraAlarm.setBaseImage(saveBase64AsFile(imageData, cameraId)); + String imageDataLabeled = alarmReportDto.getImageDataLabeled(); + cameraAlarm.setCaptureImage(saveBase64AsFile(imageDataLabeled, cameraId)); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + cameraAlarm.setCreateTime(LocalDateTime.parse(alarmReportDto.getTime(), formatter)); + AlarmReportEnums alarmReportEnums = AlarmReportEnums.getAlarmReportEnums(alarmReportDto.getSummary()); + if (alarmReportEnums != null) + { + cameraAlarm.setAlarmType(alarmReportEnums.getAlarmCode()); + // 推送信息给前端 + SocketMessage bean = new SocketMessage(); + Map data = new HashMap<>(); + data.put("title", "摄像头报警"); + data.put("content", "摄像头[" + cameraId + "]发生报警,报警内容为:" + alarmReportEnums.getAlarmDescription()+",请及时处理"); + bean.setData(JSON.toJSONString(data)); + bean.setChannel(SocketChannelEnum.MESSAGE); + bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT); + TransferMessage msg = new TransferMessage(); + msg.setMessage(bean); + msg.setFromUser("system"); + msg.setToPushAll(true); + websocketRedisService.sendServiceToWs(msg); + // 统一处理报警信息后,将摄像头信息+报警信息上报给别人服务器 + BoxAlarmReportDto reportDto = new BoxAlarmReportDto(); + reportDto.setAlarmReportTime(LocalDateTime.parse(alarmReportDto.getTime(), formatter)); + reportDto.setAlarmReportType(alarmReportEnums.getAlarmDescription()); + reportDto.setDescription(alarmReportDto.getResult().getDescription()); + reportDto.setBaseImage(imageData); + reportDto.setCaptureImage(imageDataLabeled); + reportDto.setUrl(algorithmTask.getUrl()); + reportDto.setCameraName(camera.getName()); + reportDto.setCameraId(cameraId); + reportDto.setCameraNo(camera.getCameraNo()); + try { + forwardService.enrichAndForward(reportDto); + }catch ( Exception e) + { + log.error("报警信息上报失败", e); + } + } + cameraAlarm.setAlgoResult(JsonUtils.toJsonString(alarmReportDto.getResult())); + cameraAlarm.setStatus(0); + cameraAlarm.setCameraName(camera.getName()); + cameraAlarm.setSummary(alarmReportDto.getSummary()); + cameraAlarm.setTaskDesc(alarmReportDto.getTaskDesc()); + cameraAlarm.setTaskSession(alarmReportDto.getTaskSession()); + cameraAlarm.setBoardIp(alarmReportDto.getBoardIp()); + // 保存到数据库 + cameraAlarmMapper.insert(cameraAlarm); + return BeanCopyUtils.copy(cameraAlarm, CameraAlarmVO.class); + } + + @Override + public List listByCameraIds(List ids) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(AlgorithmTask.class) + .where(AlgorithmTask::getCameraId).in(ids); + List algorithmTasks = algorithmTaskMapper.selectListByQuery(wrapper); + return BeanCopyUtils.copyList(algorithmTasks, AlgorithmTaskVO.class); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraAlarmServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraAlarmServiceImpl.java new file mode 100644 index 0000000..1f44be2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraAlarmServiceImpl.java @@ -0,0 +1,247 @@ +package com.sz.admin.monitor.service.impl; + + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.enums.AlarmReportEnums; +import com.sz.admin.monitor.mapper.CameraAlarmMapper; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmCreateDTO; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmImportDTO; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmListDTO; +import com.sz.admin.monitor.pojo.dto.cameraalarm.CameraAlarmUpdateDTO; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.CameraAlarm; +import com.sz.admin.monitor.pojo.vo.camera.CameraVO; +import com.sz.admin.monitor.pojo.vo.cameraalarm.CameraAlarmVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlarmReportVO; +import com.sz.admin.monitor.pojo.vo.offset.OffsetVO; +import com.sz.admin.monitor.service.CameraAlarmService; +import com.sz.admin.monitor.service.CameraService; +import com.sz.admin.monitor.utils.UrlConvert; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.*; +import com.sz.excel.core.ExcelResult; +import com.sz.excel.utils.ExcelUtils; +import com.sz.security.core.util.LoginUtils; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Service; + +import java.io.OutputStream; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 告警工单表 服务实现类 + *

+ * + * @author Lz + * @since 2026-02-10 + */ +@Service +@RequiredArgsConstructor +public class CameraAlarmServiceImpl extends ServiceImpl implements CameraAlarmService { + private final CameraService cameraService; + @Override + public void create(CameraAlarmCreateDTO dto) { + CameraAlarm ryCameraAlarm = BeanCopyUtils.copy(dto, CameraAlarm.class); + save(ryCameraAlarm); + } + + @Override + public void update(CameraAlarmUpdateDTO dto) { + CameraAlarm ryCameraAlarm = BeanCopyUtils.copy(dto, CameraAlarm.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create() + .eq(CameraAlarm::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + // 设置处理人,即为当前登录的用户 + String username = LoginUtils.getLoginUser().getUserInfo().getUsername(); + ryCameraAlarm.setHandleTime(LocalDateTime.now()); + ryCameraAlarm.setHandleBy(username); + saveOrUpdate(ryCameraAlarm); + } + + @Override + public PageResult page(CameraAlarmListDTO dto) { + try { + SimpleDataScopeHelper.start(CameraAlarm.class); + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), CameraAlarmVO.class); + List result = page.getRecords().stream().map(cameraAlarmVO -> { + String baseImage = cameraAlarmVO.getBaseImage(); + cameraAlarmVO.setBaseImage(UrlConvert.convertToUrl(baseImage)); + String captureImage = cameraAlarmVO.getCaptureImage(); + cameraAlarmVO.setCaptureImage(UrlConvert.convertToUrl(captureImage)); + return cameraAlarmVO; + }).toList(); + page.setRecords(result); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(CameraAlarmListDTO dto) { + try { + SimpleDataScopeHelper.start(CameraAlarm.class); + return listAs(buildQueryWrapper(dto), CameraAlarmVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public CameraAlarmVO detail(Object id) { + CameraAlarm ryCameraAlarm = getById((Serializable) id); + String baseImage = ryCameraAlarm.getBaseImage(); + ryCameraAlarm.setBaseImage(UrlConvert.convertToUrl(baseImage)); + String captureImage = ryCameraAlarm.getCaptureImage(); + ryCameraAlarm.setCaptureImage(UrlConvert.convertToUrl(captureImage)); + CommonResponseEnum.INVALID_ID.assertNull(ryCameraAlarm); + return BeanCopyUtils.copy(ryCameraAlarm, CameraAlarmVO.class); + } + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), CameraAlarmImportDTO.class, true); + List list = excelResult.getList(); + // 入库 + List importList = BeanCopyUtils.copyList(list, CameraAlarm.class); + saveBatch(importList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + } + + @SneakyThrows + @Override + public void exportExcel(CameraAlarmListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "告警工单表模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "告警工单表", CameraAlarmVO.class, os); + } + + @Override + public AlarmReportVO getAlarmReportDetail(Long id) { + CameraAlarm cameraAlarm = this.getById(id); + if (!Utils.isNotNull(cameraAlarm)) { + return null; + } + AlarmReportVO reportVO = BeanCopyUtils.copy(cameraAlarm, AlarmReportVO.class); + String baseImage = reportVO.getBaseImage(); + reportVO.setBaseImage(UrlConvert.convertToUrl(baseImage)); + String captureImage = reportVO.getCaptureImage(); + reportVO.setCaptureImage(UrlConvert.convertToUrl(captureImage)); + String algoResult = cameraAlarm.getAlgoResult(); + // {"x": "-113.48", "y": "-6.36", "unit": "px"} + AlarmReportEnums alarmReportEnums = AlarmReportEnums.getAlarmReportEnums(cameraAlarm.getAlarmType()); + if (Utils.isNotNull(alarmReportEnums)) { + reportVO.setAlarmType(alarmReportEnums.getAlarmDescription()); + reportVO.setSummary(alarmReportEnums.getAlarmType()); + } + // 区别出移位报警 + if(cameraAlarm.getAlarmType() == 1) + { + OffsetVO offsetVO = JsonUtils.parseObject(algoResult, OffsetVO.class); + if (offsetVO != null) + { + // 如果是移位报警,则需要特殊处理 + AlarmReportVO.SimpleResult simpleResult = getSimpleResult(offsetVO); + reportVO.setResult(simpleResult); + } + + }else { + AlarmReportVO.SimpleResult simpleResult = JsonUtils.parseObject(algoResult, AlarmReportVO.SimpleResult.class); + reportVO.setResult(simpleResult); + } + Long cameraId = cameraAlarm.getCameraId(); + CameraVO cameraVO = cameraService.detail(cameraId); + if (Utils.isNotNull(cameraVO)) { + reportVO.setRtspUrl(cameraVO.getRtsp()); + } + return reportVO; + } + + private static AlarmReportVO. SimpleResult getSimpleResult(OffsetVO offsetVO) { + AlarmReportVO.SimpleResult simpleResult = new AlarmReportVO.SimpleResult(); + simpleResult.setDescription("移位报警"); + AlarmReportVO.SimpleProperty simplePropertyX = new AlarmReportVO.SimpleProperty(); + simplePropertyX.setProperty("x"); + simplePropertyX.setDesc("水平方向偏移量"); + simplePropertyX.setValue(offsetVO.getX()); + AlarmReportVO.SimpleProperty simplePropertyY = new AlarmReportVO.SimpleProperty(); + simplePropertyX.setProperty("y"); + simplePropertyY.setDesc("垂直方向偏移量"); + simplePropertyY.setValue(offsetVO.getY()); + simpleResult.setProperties(List.of(simplePropertyX, simplePropertyY)); + return simpleResult; + } + + private static QueryWrapper buildQueryWrapper(CameraAlarmListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(CameraAlarm.class); + wrapper.orderBy(CameraAlarm::getCreateTime).desc(); + if (Utils.isNotNull(dto.getCameraId())) { + wrapper.eq(CameraAlarm::getCameraId, dto.getCameraId()); + } + if (Utils.isNotNull(dto.getAlarmTimeStart()) && Utils.isNotNull(dto.getAlarmTimeEnd())) + { + wrapper.between(CameraAlarm::getCreateTime, dto.getAlarmTimeStart(), dto.getAlarmTimeEnd()); + } + if (Utils.isNotNull(dto.getChannelId())) { + wrapper.eq(CameraAlarm::getChannelId, dto.getChannelId()); + } + if(Utils.isNotNull(dto.getAlarmAreaId())) + { + wrapper.eq(CameraAlarm::getAlarmAreaId, dto.getAlarmAreaId()); + } + if (Utils.isNotNull(dto.getPresetIndex())) { + wrapper.eq(CameraAlarm::getPresetIndex, dto.getPresetIndex()); + } + if (Utils.isNotNull(dto.getAlarmType())) { + wrapper.eq(CameraAlarm::getAlarmType, dto.getAlarmType()); + } + if (Utils.isNotNull(dto.getBaseImage())) { + wrapper.eq(CameraAlarm::getBaseImage, dto.getBaseImage()); + } + if (Utils.isNotNull(dto.getCaptureImage())) { + wrapper.eq(CameraAlarm::getCaptureImage, dto.getCaptureImage()); + } + if (Utils.isNotNull(dto.getAlgoResult())) { + wrapper.eq(CameraAlarm::getAlgoResult, dto.getAlgoResult()); + } + if (Utils.isNotNull(dto.getStatus())) { + wrapper.eq(CameraAlarm::getStatus, dto.getStatus()); + } + if (Utils.isNotNull(dto.getHandleTimeStart()) && Utils.isNotNull(dto.getHandleTimeEnd())) { + wrapper.between(CameraAlarm::getHandleTime, dto.getHandleTimeStart(), dto.getHandleTimeEnd()); + } + if (Utils.isNotNull(dto.getHandleBy())) { + wrapper.eq(CameraAlarm::getHandleBy, dto.getHandleBy()); + } + if (Utils.isNotNull(dto.getHandleRemark())) { + wrapper.eq(CameraAlarm::getHandleRemark, dto.getHandleRemark()); + } + return wrapper; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraServiceImpl.java new file mode 100644 index 0000000..6ca3295 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraServiceImpl.java @@ -0,0 +1,295 @@ +package com.sz.admin.monitor.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mybatisflex.core.logicdelete.LogicDeleteManager; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.enums.HKPTZPreEnum; +import com.sz.admin.monitor.mapper.*; +import com.sz.admin.monitor.pojo.dto.camera.CameraListDTO; +import com.sz.admin.monitor.pojo.dto.camera.CameraUpdateDTO; +import com.sz.admin.monitor.pojo.po.AlgorithmTask; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.EdgeBox; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.table.CameraTableDef; +import com.sz.admin.monitor.pojo.vo.camera.CameraVO; +import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO; +import com.sz.admin.monitor.pojo.vo.edgebox.AlgorithmTaskVO; +import com.sz.admin.monitor.pojo.vo.preset.PresetVO; +import com.sz.admin.monitor.sdk.ManageNVR; +import com.sz.admin.monitor.enums.HCPlayControlEnum; +import com.sz.admin.monitor.service.*; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.RtspUtil; +import com.sz.admin.monitor.utils.ZLMediaKitUtils; +import com.sz.admin.teacher.pojo.po.TeacherStatistics; +import com.sz.admin.teacher.pojo.vo.TeacherStatisticsVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import com.sz.platform.enums.AdminResponseEnum; +import com.sz.security.core.util.LoginUtils; +import jakarta.annotation.Resource; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.sz.admin.monitor.pojo.po.table.NvrTableDef.NVR; + +/** + * ClassName: CameraServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: 摄像机业务类 + */ +@Service +@Slf4j +public class CameraServiceImpl extends ServiceImpl implements CameraService { + @Resource + private CameraMapper cameraMapper; + @Resource + private NvrMapper nvrMapper; + @Resource + private AlgorithmTaskService algorithmTaskService; + @Resource + private PresetMapper presetMapper; + @Resource + private CameraSnapshotMapper cameraSnapshotMapper; + @Resource + private AiBoxRequestUtil aiBoxRequestUtil; + @Resource + private EdgeBoxMapper edgeBoxMapper; + // 自己注入自己 + @Resource + @Lazy + private CameraService cameraService; + @Override + public Camera getByChannelId(Integer channelId) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(Camera.class) + .eq(Camera::getChannelId, channelId); + return cameraMapper.selectOneByQuery(wrapper); + } + + @Override + public void update(CameraUpdateDTO dto) { + Camera camera = BeanCopyUtils.copy(dto, Camera.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(Camera::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + // 唯一性校验 + saveOrUpdate(camera); + } + + @Override + public PageResult page(CameraListDTO dto) { + try { + SimpleDataScopeHelper.start(Camera.class); // 指定要追加条件的表PO实体 + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), CameraVO.class); // 调试sql + page.getRecords().forEach(r -> { + Long nvrId = r.getNvrId(); + Nvr nvr = nvrMapper.selectOneById(nvrId); + if(nvr!=null) + { + r.setNvrName(nvr.getName()); + Map rtsp = RtspUtil.getRtsp(nvr.getDriver(), nvr.getAccount(), nvr.getPassword(), r.getChannelId() - 32, nvr.getIp(), 554); + r.setRtsp(rtsp.get("mainRtsp")); + } + // 根据摄像机的id查询算法任务表 + AlgorithmTaskVO algorithmTaskVO = algorithmTaskService.getAlgorithmTaskByCameraId(r.getId()); + if (algorithmTaskVO != null) + { + r.setAlgInfo(algorithmTaskVO.getAlgInfo()); + } + }); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(CameraListDTO dto) { + try { + SimpleDataScopeHelper.start(Camera.class); // 指定要追加条件的表PO实体 + return listAs(buildQueryWrapper(dto), CameraVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + List cameraList = listByIds(dto.getIds()); + if (cameraList.isEmpty()) { + return; + } + List taskList = algorithmTaskService.listByCameraIds(dto.getIds()); + for (AlgorithmTaskVO task : taskList) { + if (task != null && task.getAlgTaskSession() != null) { + try { + Long cameraId = task.getCameraId(); + Camera camera = this.getById(cameraId); + Long boxId = camera.getBoxId(); + EdgeBox edgeBox = edgeBoxMapper.selectOneById(boxId); + // 删除任务 + aiBoxRequestUtil.controlTask(edgeBox.getIp(), edgeBox.getPort(), task.getAlgTaskSession(), 0); + aiBoxRequestUtil.deleteTask(edgeBox.getIp(), edgeBox.getPort(), task.getAlgTaskSession()); + } catch (Exception e) { + log.error("清理 AI 盒子任务失败,摄像机ID: {}, Session: {}", task.getCameraId(), task.getAlgTaskSession(), e); + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null,"同步清理设备算法任务失败,请检查网络后重试"); + } + } + } + for (Camera camera : cameraList) { + // 删除通道 + Long boxId = camera.getBoxId(); + EdgeBox edgeBox = edgeBoxMapper.selectOneById(boxId); + aiBoxRequestUtil.deleteVideoChannel(edgeBox.getIp(), edgeBox.getPort(), camera.getId().toString()); + } + cameraService.batchDeleteLocalData(dto.getIds(), taskList); + } + @Transactional(rollbackFor = Exception.class) + public void batchDeleteLocalData(List cameraIds, List taskList) { + // 1. 批量删除预置位 + presetMapper.removeByCameraIds(cameraIds); + // 2. 批量删除快照图 + cameraSnapshotMapper.removeByCameraIds(cameraIds); + // 3. 批量删除算法任务 + if (!taskList.isEmpty()) { + List taskIds = taskList.stream().map(AlgorithmTaskVO::getId).toList(); + algorithmTaskService.removeByIds(taskIds); + } + // 4. 最后删除摄像头本身 + removeByIds(cameraIds); + } + + @Override + public List getUnboundList() { + QueryWrapper queryWrapper = QueryWrapper.create() + .select() + .from(Camera.class) + .isNull(Camera::getBoxId); + List cameraList = cameraMapper.selectListByQuery(queryWrapper); + return BeanCopyUtils.copyList(cameraList, CameraVO.class); + } + + @Override + public List getBoundList(Long boxId) { + QueryWrapper queryWrapper = QueryWrapper.create() + .select() + .from(Camera.class) + .eq(Camera::getBoxId, boxId); + List cameraList = cameraMapper.selectListByQuery(queryWrapper); + return BeanCopyUtils.copyList(cameraList, CameraVO.class); + } + + @Override + public CameraVO detail(Long id) { + // 查询时忽略逻辑删除 + Camera camera = LogicDeleteManager.execWithoutLogicDelete(() -> cameraService.getById(id)); + if (camera == null) + { + return null; + } + CommonResponseEnum.INVALID_ID.assertNull(camera); + CameraVO cameraVO = BeanCopyUtils.copy(camera, CameraVO.class); + Long nvrId = cameraVO.getNvrId(); + Nvr nvr = nvrMapper.selectOneById(nvrId); + if (nvr!=null) + { + Map rtsp = RtspUtil.getRtsp(nvr.getDriver(), nvr.getAccount(), nvr.getPassword(), cameraVO.getChannelId() - 32, nvr.getIp(), 554); + cameraVO.setNvrName(nvr.getName()); + cameraVO.setRtsp(rtsp.get("mainRtsp")); + } + return cameraVO; + } + + @Override + public void updateWatchfulStateByIp(String ipAddress, int watchfulState) { + QueryWrapper queryWrapper = QueryWrapper.create() + .from(CameraTableDef.CAMERA) + .where(CameraTableDef.CAMERA.IP_ADDRESS.eq(ipAddress)); + Camera camera = new Camera(); + camera.setWatchfulState(watchfulState); + cameraMapper.updateByQuery(camera, queryWrapper); + } + + @SneakyThrows + @Override + public List remoteSearch(String keyword) { + Thread.sleep(1000); + QueryWrapper wrapper = QueryWrapper.create().from(Camera.class).like(Camera::getChannelId, keyword); + return listAs(wrapper, CameraVO.CameraTypeEnum.class); + } + + @Override + public List selectListByInspection() { + QueryWrapper wrapper = QueryWrapper.create().select() + .from(CameraTableDef.CAMERA) + .where(CameraTableDef.CAMERA.ENABLE_INSPECTION.eq(1)) + .and(CameraTableDef.CAMERA.STATUS.eq(1)); + return this.list(wrapper); + } + + + private QueryWrapper buildQueryWrapper(CameraListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(Camera.class); + // wrapper.orderBy(Camera::getUpdateTime).desc(); + if (Utils.isNotNull(dto.getNvrName())) { + // 根据NVR名称模糊查询NVR数据 + QueryWrapper where = QueryWrapper.create().from(NVR).select(NVR.ID) + .where(NVR.NAME.like(dto.getNvrName())); + List nvrList = nvrMapper.selectListByQuery(where); + List ids = nvrList.stream().map(Nvr::getId).toList(); + wrapper.in(Camera::getNvrId, ids); + } + if (Utils.isNotNull(dto.getChannelDriver())) { + wrapper.eq(Camera::getChannelDriver, dto.getChannelDriver()); + } + if (Utils.isNotNull(dto.getName())) { + wrapper.like(Camera::getName, dto.getName()); + } + + if (Utils.isNotNull(dto.getStatus())) { + wrapper.eq(Camera::getStatus, dto.getStatus()); + } + if (Utils.isNotNull(dto.getType())) { + wrapper.eq(Camera::getType, dto.getType()); + } + if (Utils.isNotNull(dto.getNvrId())) { + wrapper.eq(Camera::getNvrId, dto.getNvrId()); + } + if (Utils.isNotNull(dto.getIpAddress())) { + wrapper.eq(Camera::getIpAddress, dto.getIpAddress()); + } + if (Utils.isNotNull(dto.getVideoType())) { + wrapper.eq(Camera::getVideoType, dto.getVideoType()); + } + if (Utils.isNotNull(dto.getChannelId())) + { + wrapper.eq(Camera::getChannelId, dto.getChannelId()); + } + return wrapper; + } + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraSnapshotServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraSnapshotServiceImpl.java new file mode 100644 index 0000000..40bebc6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/CameraSnapshotServiceImpl.java @@ -0,0 +1,98 @@ +package com.sz.admin.monitor.service.impl; + +import cn.hutool.core.lang.UUID; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.CameraSnapshotMapper; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.CameraSnapshot; +import com.sz.admin.monitor.pojo.po.table.CameraSnapshotTableDef; +import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO; +import com.sz.admin.monitor.sdk.ManageNVR; +import com.sz.admin.monitor.service.CameraService; +import com.sz.admin.monitor.service.CameraSnapshotService; +import com.sz.admin.monitor.utils.ImageNameUtils; +import com.sz.core.util.BeanCopyUtils; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: CameraSnapshotServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +public class CameraSnapshotServiceImpl extends ServiceImpl implements CameraSnapshotService { + @Resource + private ManageNVR manageNVR; + @Resource + private CameraSnapshotMapper cameraSnapshotMapper; + @Resource + private CameraService cameraService; + + @Override + public CameraSnapshotVO captureAndSave(Long id, int triggerType) { + // 生成一个随机的文件名称 + String fileName = ImageNameUtils.generateFileName("CAPTURE", id); + String path = manageNVR.capturePic(id.intValue(), fileName); + CameraSnapshot snapshot = new CameraSnapshot(); + snapshot.setImagePath(path); + snapshot.setCameraId(id); + snapshot.setCheckType(triggerType); + // 先删除,后插入 + cameraSnapshotMapper.insert(snapshot); + return BeanCopyUtils.copy(snapshot, CameraSnapshotVO.class); + } + + @Override + @Transactional + public CameraSnapshotVO captureAndSave(Long id, int triggerType, int presetIndex) { + // 生成一个随机的文件名称 + String fileName = ImageNameUtils.generateFileName("CAPTURE", id); + String path = manageNVR.capturePic(id.intValue(), fileName); + CameraSnapshot snapshot = new CameraSnapshot(); + snapshot.setImagePath(path); + snapshot.setCameraId(id); + snapshot.setPresetIndex(presetIndex); + snapshot.setCheckType(triggerType); + // 先删除,后插入 + deleteSnapshotByChannelIdAndPresetIndex(id, presetIndex); + cameraSnapshotMapper.insert(snapshot); + return BeanCopyUtils.copy(snapshot, CameraSnapshotVO.class); + } + + @Override + public CameraSnapshotVO selectByCameraIdAndPresetIndex(Long id, int presetIndex) { + QueryWrapper wrapper = QueryWrapper.create().select().from(CameraSnapshot.class) + .where(CameraSnapshot::getCameraId).eq(id) + .and(CameraSnapshot::getPresetIndex).eq(presetIndex); + CameraSnapshot cameraSnapshot = cameraSnapshotMapper.selectOneByQuery(wrapper); + return BeanCopyUtils.copy(cameraSnapshot, CameraSnapshotVO.class); + } + + @Override + public List getExistSnapshotList(Long id) { + QueryWrapper wrapper = QueryWrapper.create().select().from(CameraSnapshot.class) + .where(CameraSnapshot::getCameraId).eq(id); + cameraSnapshotMapper.selectListByQuery(wrapper); + return BeanCopyUtils.copyList(cameraSnapshotMapper.selectListByQuery(wrapper), CameraSnapshotVO.class); + } + + + + private void deleteSnapshotByChannelIdAndPresetIndex(Long id, int presetIndex) { + QueryWrapper wrapper = QueryWrapper.create().select().from(CameraSnapshot.class) + .where(CameraSnapshot::getCameraId).eq(id) + .and(CameraSnapshot::getPresetIndex).eq(presetIndex); + CameraSnapshot cameraSnapshot = cameraSnapshotMapper.selectOneByQuery(wrapper); + if (cameraSnapshot != null) { + cameraSnapshotMapper.delete(cameraSnapshot); + } + + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/DeviceServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/DeviceServiceImpl.java new file mode 100644 index 0000000..f8e9415 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/DeviceServiceImpl.java @@ -0,0 +1,141 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.NvrMapper; +import com.sz.admin.monitor.pojo.dto.edgebox.SetupChannelDTO; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.sdk.ManageNVR; +import com.sz.admin.monitor.service.DeviceService; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.AlgMediaConfigResponse; +import com.sz.admin.monitor.utils.RtspUtil; +import com.sz.admin.monitor.utils.VcrlUserIdContainer; +import com.sz.admin.system.pojo.dto.sysmessage.PayloadBody; +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.platform.enums.AdminResponseEnum; +import com.sz.redis.WebsocketRedisService; +import com.sz.security.core.util.LoginUtils; +import com.sz.socket.SocketService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.UnsupportedEncodingException; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * ClassName: DeviceServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +@Slf4j +public class DeviceServiceImpl extends ServiceImpl implements DeviceService { + @Resource + private VcrlUserIdContainer vcrlUserIdContainer; + @Resource + private ManageNVR manageNVR; + @Resource + private CameraMapper cameraMapper; + @Resource + private NvrMapper nvrMapper; + @Resource + private SocketService socketService; + @Resource + private WebsocketRedisService websocketRedisService; + @Resource + private AiBoxRequestUtil aiBoxRequestUtil; + + @Override + public Object deviceLogin(Long id) { + Nvr nvr = this.getById(id); + // 设备登录 + int result = (int) manageNVR.loginOne(nvr.getId(), nvr.getIp(), String.valueOf(nvr.getPort()), nvr.getAccount(), nvr.getPassword(), String.valueOf(nvr.getDriver())); + if(result>0) + { + nvr.setStatus(1); + this.updateById(nvr); + } + return result; + } + + /** + * 通道刷新 + * @param id NVR的id + * @param deviceType NVR的类型 + * @return + */ + @Override + public Boolean refresh(Long id, Integer deviceType) { + Integer userId=(Integer)vcrlUserIdContainer.getlUserId(id.intValue()); + if (userId==null) + { + throw new BusinessException(AdminResponseEnum.DEVICE_OFFLINE,null, "设备为离线状态无法刷新"); + } + try { + // 从SDK中获取到的通道信息 + List channel = manageNVR.getChannel(userId, id, deviceType); + Map sdkMap = channel.stream() + .collect(Collectors.toMap(Camera::getChannelId, c -> c)); + // 从数据库中获取当前已有的列表 + List dbCameras = cameraMapper.selectByNvrId(id); + Map dbMap = dbCameras.stream() + .collect(Collectors.toMap(Camera::getChannelId, c -> c)); + Nvr nvr = nvrMapper.selectOneById(id); + // 处理更新和新增 + for (Camera sdkInfo : channel) { + Camera existingCamera = dbMap.get(sdkInfo.getChannelId()); + if (existingCamera != null) { + // --- 数据库里有 -> 更新状态 --- + existingCamera.setName(sdkInfo.getName()); + existingCamera.setIpAddress(sdkInfo.getIpAddress()); + existingCamera.setStatus(sdkInfo.getStatus()); + existingCamera.setVideoType(sdkInfo.getVideoType()); + existingCamera.setUpdateTime(LocalDateTime.now()); + cameraMapper.update(existingCamera); + } else { + // --- 数据库里没有 -> 新增 --- + this.handleNewCameraSync(id, sdkInfo, nvr); + } + } + // 处理移除,如果数据库中的某个通道,在SDK中没有 + for (Camera dbCam : dbCameras) { + // 如果数据库里的某个通道,SDK里没有了 + if (!sdkMap.containsKey(dbCam.getChannelId())) { + dbCam.setStatus(0); // 0 代表离线 + cameraMapper.update(dbCam); + } + } + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + return true; + } + private void handleNewCameraSync(Long id, Camera sdkInfo, Nvr nvr) { + Camera newCamera = new Camera(); + newCamera.setNvrId(id); + newCamera.setChannelId(sdkInfo.getChannelId()); + newCamera.setName(sdkInfo.getName()); + newCamera.setStatus(sdkInfo.getStatus()); + newCamera.setCreateTime(LocalDateTime.now()); + // 初始化配置 + newCamera.setEnableInspection(0); + newCamera.setChannelDriver(0); + newCamera.setWatchfulState(0); + newCamera.setIpAddress(sdkInfo.getIpAddress()); + newCamera.setType(1); + newCamera.setVideoType(sdkInfo.getVideoType()); + cameraMapper.insert(newCamera); + } + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/EdgeBoxServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/EdgeBoxServiceImpl.java new file mode 100644 index 0000000..2a334c0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/EdgeBoxServiceImpl.java @@ -0,0 +1,237 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.AlgorithmTaskMapper; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.EdgeBoxMapper; +import com.sz.admin.monitor.mapper.NvrMapper; +import com.sz.admin.monitor.pojo.dto.edgebox.*; +import com.sz.admin.monitor.pojo.po.AlgorithmTask; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.EdgeBox; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.vo.edgebox.EdgeBoxVO; +import com.sz.admin.monitor.service.EdgeBoxService; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.RtspUtil; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.platform.enums.AdminResponseEnum; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.query.QueryChain; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.PageUtils; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.Utils; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.io.Serializable; +import java.util.List; + +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.excel.core.ExcelResult; + +import java.io.OutputStream; +import java.util.Map; +import java.util.stream.Collectors; + +import jakarta.servlet.http.HttpServletResponse; +import com.sz.core.util.FileUtils; +import com.sz.excel.utils.ExcelUtils; +import lombok.SneakyThrows; +import com.sz.core.datascope.SimpleDataScopeHelper; +import org.springframework.transaction.annotation.Transactional; + + +/** + *

+ * 边缘盒子 服务实现类 + *

+ * + * @author Lz + * @since 2026-03-05 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class EdgeBoxServiceImpl extends ServiceImpl implements EdgeBoxService { + private final CameraMapper cameraMapper; + private final AiBoxRequestUtil aiBoxRequestUtil; + private final NvrMapper nvrMapper; + private final AlgorithmTaskMapper algorithmTaskMapper; + + @Override + public void create(EdgeBoxCreateDTO dto) { + EdgeBox ryEdgeBox = BeanCopyUtils.copy(dto, EdgeBox.class); + long count; + // 唯一性校验 + count = QueryChain.of(EdgeBox.class).eq(EdgeBox::getIp, dto.getIp()).count(); + CommonResponseEnum.EXISTS.message("ip已存在").assertTrue(count > 0); + save(ryEdgeBox); + } + + @Override + public void update(EdgeBoxUpdateDTO dto) { + EdgeBox ryEdgeBox = BeanCopyUtils.copy(dto, EdgeBox.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create() + .eq(EdgeBox::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + + // 唯一性校验 + long count; + count = QueryChain.of(EdgeBox.class).eq(EdgeBox::getIp, dto.getIp()).ne(EdgeBox::getId, dto.getId()).count(); + CommonResponseEnum.EXISTS.message("ip已存在").assertTrue(count > 0); + saveOrUpdate(ryEdgeBox); + } + + @Override + public PageResult page(EdgeBoxListDTO dto) { + try { + SimpleDataScopeHelper.start(EdgeBox.class); + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), EdgeBoxVO.class); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(EdgeBoxListDTO dto) { + try { + SimpleDataScopeHelper.start(EdgeBox.class); + return listAs(buildQueryWrapper(dto), EdgeBoxVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public EdgeBoxVO detail(Object id) { + EdgeBox ryEdgeBox = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(ryEdgeBox); + return BeanCopyUtils.copy(ryEdgeBox, EdgeBoxVO.class); + } + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), EdgeBoxImportDTO.class, true); + List list = excelResult.getList(); + // 入库 + List importList = BeanCopyUtils.copyList(list, EdgeBox.class); + saveBatch(importList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + } + + @SneakyThrows + @Override + public void exportExcel(EdgeBoxListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "边缘盒子模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "边缘盒子", EdgeBoxVO.class, os); + } + + @Override + @Transactional + public void bindCameras(EdgeBoxBindCamerasDTO dto) { + List cameraIds = dto.getCameraIds(); + Long boxId = dto.getBoxId(); + if (cameraIds.size() > 16) { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "绑定的摄像头数量不能超过16个"); + } + // 找出新增和被移除的通道 + List oldCameraIds = cameraMapper.selectIdsByEdgeBoxId(boxId); + // 找出新增的通道 + List addedIds = cameraIds.stream().filter(id -> !oldCameraIds.contains(id)).toList(); + // 找出被移除的通道 + List removeIds = oldCameraIds.stream().filter(id -> !cameraIds.contains(id)).toList(); + if (!addedIds.isEmpty()) { + // 批量更新 + cameraMapper.updateBoxIdForCameras(boxId, addedIds); + } + if (!removeIds.isEmpty()) { + cameraMapper.updateBoxIdForCameras(null, removeIds); + } + // 调用盒子接口 + try { + if (!addedIds.isEmpty()) { + // 注册新通道 + EdgeBox box = this.getById(boxId); + for (Long addedId : addedIds) { + SetupChannelDTO channelDTO = new SetupChannelDTO(); + channelDTO.setMediaName(addedId.toString()); + Camera camera = cameraMapper.selectOneById(addedId); + Nvr nvr = nvrMapper.selectOneById(camera.getNvrId()); + Map rtsp = RtspUtil.getRtsp(nvr.getDriver(), nvr.getAccount(), nvr.getPassword(), camera.getChannelId() - 32, nvr.getIp(), 554); + channelDTO.setMediaUrl(rtsp.get("mainRtsp")); + channelDTO.setMediaDesc(camera.getName() + ":" + camera.getIpAddress()); + aiBoxRequestUtil.setupVideoChannel(box.getIp(), box.getPort(), channelDTO); + } + } + if (!removeIds.isEmpty()) { + // 删除被移出的通道 + EdgeBox box = this.getById(boxId); + for (Long removeId : removeIds) { + // TODO 如果该通道配置了算法,则需要关闭和删除任务再进行一个删除通道 + AlgorithmTask algorithmTask = algorithmTaskMapper.selectByCameraId(removeId); + if (algorithmTask != null) + { + algorithmTaskMapper.delete(algorithmTask); + aiBoxRequestUtil.controlTask(box.getIp(), box.getPort(), algorithmTask.getAlgTaskSession(), 0); + aiBoxRequestUtil.deleteTask(box.getIp(), box.getPort(), algorithmTask.getAlgTaskSession()); + aiBoxRequestUtil.deleteVideoChannel(box.getIp(), box.getPort(), removeId.toString()); + }else { + aiBoxRequestUtil.deleteVideoChannel(box.getIp(), box.getPort(), removeId.toString()); + } + + } + } + } catch (Exception e) { + log.error("同步边缘盒子失败", e); + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "边缘计算盒子同步失败,已撤销绑定操作。请检查盒子网络!"); + } + } + + private static QueryWrapper buildQueryWrapper(EdgeBoxListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(EdgeBox.class); + if (Utils.isNotNull(dto.getName())) { + wrapper.like(EdgeBox::getName, dto.getName()); + } + if (Utils.isNotNull(dto.getIp())) { + wrapper.eq(EdgeBox::getIp, dto.getIp()); + } + if (Utils.isNotNull(dto.getPort())) { + wrapper.eq(EdgeBox::getPort, dto.getPort()); + } + if (Utils.isNotNull(dto.getMask())) { + wrapper.eq(EdgeBox::getMask, dto.getMask()); + } + if (Utils.isNotNull(dto.getGateway())) { + wrapper.eq(EdgeBox::getGateway, dto.getGateway()); + } + if (Utils.isNotNull(dto.getAccount())) { + wrapper.eq(EdgeBox::getAccount, dto.getAccount()); + } + if (Utils.isNotNull(dto.getPassword())) { + wrapper.eq(EdgeBox::getPassword, dto.getPassword()); + } + return wrapper; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceImageServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceImageServiceImpl.java new file mode 100644 index 0000000..bee9de8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceImageServiceImpl.java @@ -0,0 +1,143 @@ +package com.sz.admin.monitor.service.impl; + +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.IdUtil; +import com.mybatisflex.core.BaseMapper; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.EdgeBoxMapper; +import com.sz.admin.monitor.mapper.FaceImageMapper; +import com.sz.admin.monitor.mapper.FaceInfoMapper; +import com.sz.admin.monitor.mapper.FaceLibraryMapper; +import com.sz.admin.monitor.pojo.po.EdgeBox; +import com.sz.admin.monitor.pojo.po.FaceImage; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.po.FaceLibrary; +import com.sz.admin.monitor.pojo.po.table.FaceImageTableDef; +import com.sz.admin.monitor.pojo.vo.faceimage.FaceImageVO; +import com.sz.admin.monitor.service.FaceImageService; +import com.sz.admin.monitor.service.FaceInfoService; +import com.sz.admin.monitor.service.FaceLibraryService; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.ImageNameUtils; +import com.sz.admin.monitor.utils.UrlConvert; +import com.sz.core.util.BeanCopyUtils; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.Base64; +import java.util.List; + +/** + * ClassName: FaceImageServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +@Slf4j +public class FaceImageServiceImpl extends ServiceImpl implements FaceImageService { + @Resource + private AiBoxRequestUtil aiBoxRequestUtil; + @Resource + private FaceInfoMapper faceInfoMapper; + @Resource + private FaceLibraryMapper faceLibraryMapper; + @Resource + private EdgeBoxMapper edgeBoxMapper; + // 图片上传接口 + @Override + public String fileUpload(MultipartFile file) { + String originalFilename = file.getOriginalFilename(); + String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); + String fileName = ImageNameUtils.generateFileName("face",suffix); + // 保存到本地文件夹 + String filePath = "D:\\work\\images\\" + fileName; + try { + file.transferTo(new File(filePath)); + return UrlConvert.convertToUrl(filePath); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + @Override + public List getByFaceId(Long id) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(FaceImageTableDef.FACE_IMAGE) + .where(FaceImageTableDef.FACE_IMAGE.FACE_INFO_ID.eq(id)); + List faceImages = this.list(wrapper); + return BeanCopyUtils.copyList(faceImages, FaceImageVO.class); + } + + @Override + @Transactional + public void fileUploadBind(MultipartFile file, Long id) { + String path = fileUpload(file); + FaceInfo faceInfo = faceInfoMapper.selectOneById(id); + if (faceInfo == null) { + throw new RuntimeException("未找到对应的人脸信息,绑定失败"); + } + FaceLibrary faceLibrary = faceLibraryMapper.selectOneById(faceInfo.getLibraryId()); + if (faceLibrary == null) { + throw new RuntimeException("未找到关联的人脸库,绑定失败"); + } + EdgeBox edgeBox = edgeBoxMapper.selectOneById(faceLibrary.getBoxId()); + String base64Image = null; + try { + String realFilePath = getRealFilePath(path); + File f = new File(realFilePath); + if (!f.exists()) { + throw new RuntimeException("读取人脸图片失败,文件不存在: " + path); + } + byte[] fileBytes = Files.readAllBytes(Paths.get(realFilePath)); + base64Image = Base64.getEncoder().encodeToString(fileBytes); + } catch (IOException e) { + log.error("图片转Base64编码异常, 图片路径: {}", path, e); + throw new RuntimeException("处理人脸图片文件时发生异常"); + } + aiBoxRequestUtil.registerFaceLibrary(edgeBox.getIp(), edgeBox.getPort(), faceLibrary.getName(), + faceInfo.getFaceSign(), + faceInfo.getName(), + base64Image, + UUID.randomUUID().toString().replaceAll("-", "")); + try { + FaceImage faceImage = new FaceImage(); + faceImage.setFaceInfoId(id); + faceImage.setImageUrl(path); + faceImage.setUploadTime(LocalDateTime.now()); + this.save(faceImage); + } catch (Exception e) { + log.error("本地保存图片记录失败,准备执行 AI 盒子反向清理。图片路径: {}", path, e); + try { + aiBoxRequestUtil.deleteFaceInfo(edgeBox.getIp(), edgeBox.getPort(), faceInfo.getFaceSign(), faceLibrary.getName()); + } catch (Exception rollbackEx) { + log.error("【严重告警】本地落库失败,且 AI 盒子清理也失败!需人工排查。", rollbackEx); + } + throw new RuntimeException("图片绑定失败,请重试"); + } + } + private String getRealFilePath(String imageUrl) { + String basePath="D:/work/images"; + return basePath + imageUrl.replace("/save", ""); + } + + @Override + public void removeByFaceIds(List ids) { + QueryWrapper queryWrapper = QueryWrapper.create() + .select() + .from(FaceImageTableDef.FACE_IMAGE) + .where(FaceImageTableDef.FACE_IMAGE.FACE_INFO_ID.in(ids)); + this.remove(queryWrapper); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceInfoServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceInfoServiceImpl.java new file mode 100644 index 0000000..b88d7e7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceInfoServiceImpl.java @@ -0,0 +1,253 @@ +package com.sz.admin.monitor.service.impl; + + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.EdgeBoxMapper; +import com.sz.admin.monitor.mapper.FaceInfoMapper; +import com.sz.admin.monitor.mapper.FaceLibraryMapper; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoCreateDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoImportDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoListDTO; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoUpdateDTO; +import com.sz.admin.monitor.pojo.po.EdgeBox; +import com.sz.admin.monitor.pojo.po.FaceImage; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.po.FaceLibrary; +import com.sz.admin.monitor.pojo.vo.faceimage.FaceImageVO; +import com.sz.admin.monitor.pojo.vo.faceinfo.FaceInfoVO; +import com.sz.admin.monitor.pojo.vo.facelibrary.FaceLibraryVO; +import com.sz.admin.monitor.service.FaceImageService; +import com.sz.admin.monitor.service.FaceInfoService; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.UrlConvert; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.FileUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import com.sz.excel.core.ExcelResult; +import com.sz.excel.utils.ExcelUtils; +import com.sz.platform.enums.AdminResponseEnum; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.Base64; +import java.util.List; + +/** + *

+ * 人脸信息表 服务实现类 + *

+ * + * @author Lz + * @since 2026-02-26 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class FaceInfoServiceImpl extends ServiceImpl implements FaceInfoService { + private final FaceImageService faceImageService; + private final FaceLibraryMapper faceLibraryMapper; + private final AiBoxRequestUtil aiBoxRequestUtil; + private final EdgeBoxMapper edgeBoxMapper; + @Override + public void create(FaceInfoCreateDTO dto) { + String imageUrl = dto.getImageUrl(); + String base64Image = null; + try { + String realFilePath = getRealFilePath(imageUrl); + java.io.File file = new java.io.File(realFilePath); + if (!file.exists()) { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "读取人脸图片失败,文件不存在"); + } + byte[] fileBytes = Files.readAllBytes(Paths.get(realFilePath)); + base64Image = Base64.getEncoder().encodeToString(fileBytes); + } catch (IOException e) { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "处理人脸图片文件时发生异常"); + } + Long libraryId = dto.getLibraryId(); + FaceLibrary faceLibrary = faceLibraryMapper.selectOneById(libraryId); + Long boxId = faceLibrary.getBoxId(); + EdgeBox edgeBox = edgeBoxMapper.selectOneById(boxId); + aiBoxRequestUtil.registerFaceLibrary(edgeBox.getIp(), edgeBox.getPort(), faceLibrary.getName(), + dto.getFaceSign(), + dto.getName(), + base64Image); + try { + this.saveFaceDataToDb(dto, imageUrl); + } catch (Exception e) { + log.error("本地数据库保存人脸失败,开始回滚 AI 盒子数据。人员: {}", dto.getName(), e); + try { + // 调用盒子端“删除人脸”的接口 + aiBoxRequestUtil.deleteFaceInfo(edgeBox.getIp(), edgeBox.getPort(), dto.getFaceSign(), faceLibrary.getName()); + } catch (Exception rollbackEx) { + log.error("【严重告警】本地落库失败,且 AI 盒子数据回滚失败!需人工排查脏数据。", rollbackEx); + } + // 向前端抛出异常 + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "系统内部异常,保存人脸数据失败"); + } + } + @Transactional(rollbackFor = Exception.class) + public void saveFaceDataToDb(FaceInfoCreateDTO dto, String imageUrl) { + FaceInfo ryFaceInfo = BeanCopyUtils.copy(dto, FaceInfo.class); + ryFaceInfo.setRegisterTime(LocalDateTime.now()); + save(ryFaceInfo); + FaceImage faceImage = new FaceImage(); + faceImage.setImageUrl(imageUrl); + faceImage.setFaceInfoId(ryFaceInfo.getId()); + faceImage.setUploadTime(LocalDateTime.now()); + faceImageService.save(faceImage); + } + private String getRealFilePath(String imageUrl) { + String basePath="D:/work/images"; + return basePath + imageUrl.replace("/save", ""); + } + @Override + public void update(FaceInfoUpdateDTO dto){ + FaceInfo ryFaceInfo = BeanCopyUtils.copy(dto, FaceInfo.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create() + .eq(FaceInfo::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + saveOrUpdate(ryFaceInfo); + } + + @Override + public PageResult page(FaceInfoListDTO dto){ + try { + SimpleDataScopeHelper.start(FaceInfo.class); + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), FaceInfoVO.class); + List result = page.getRecords().stream().map(faceInfoVO -> { + Long id = faceInfoVO.getId(); + Long faceLibraryId = faceInfoVO.getLibraryId(); + // 根据人脸库id查询人脸库 + FaceLibrary faceLibrary = faceLibraryMapper.selectOneById(faceLibraryId); + // PO转VO + faceInfoVO.setFaceLibraryVO(BeanCopyUtils.copy(faceLibrary, FaceLibraryVO.class)); + List faceImageVOS= faceImageService.getByFaceId(id); + faceInfoVO.setFaceImageList(faceImageVOS); + return faceInfoVO; + }).toList(); + page.setRecords(result); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(FaceInfoListDTO dto){ + try { + SimpleDataScopeHelper.start(FaceInfo.class); + return listAs(buildQueryWrapper(dto), FaceInfoVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void remove(SelectIdsDTO dto){ + // 根据id查询 + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + List faceInfoList = listByIds(dto.getIds()); + if (faceInfoList.isEmpty()) { + return; + } + for (FaceInfo faceInfo : faceInfoList) { + try { + FaceLibrary faceLibrary = faceLibraryMapper.selectOneById(faceInfo.getLibraryId()); + EdgeBox edgeBox = edgeBoxMapper.selectOneById(faceLibrary.getBoxId()); + aiBoxRequestUtil.deleteFaceInfo(edgeBox.getIp(), edgeBox.getPort(), faceInfo.getFaceSign(), faceLibrary.getName()); + }catch (Exception e) + { + log.error("AI盒子删除人脸库失败, faceInfoName: {}", faceInfo.getName(), e); + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "同步删除AI盒子数据失败,请重试"); + } + } + removeByIds(dto.getIds()); + faceImageService.removeByFaceIds(dto.getIds()); + } + + @Override + public FaceInfoVO detail(Object id){ + FaceInfo ryFaceInfo = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(ryFaceInfo); + return BeanCopyUtils.copy(ryFaceInfo, FaceInfoVO.class); + } + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), FaceInfoImportDTO.class, true); + List list = excelResult.getList(); + // 入库 + List importList = BeanCopyUtils.copyList(list, FaceInfo.class); + saveBatch(importList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + } + + @SneakyThrows + @Override + public void exportExcel(FaceInfoListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "人脸信息表模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "人脸信息表", FaceInfoVO.class, os); + } + + @Override + @Transactional + public void removeByLibraryIds(List ids) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(FaceInfo.class) + .in(FaceInfo::getLibraryId, ids); + List faceInfoList = this.list(wrapper); + if (faceInfoList.isEmpty()) { + return; + } + // 删除关联的人脸图片表数据 + faceImageService.removeByFaceIds(faceInfoList.stream().map(FaceInfo::getId).toList()); + // 删除人脸信息表数据 + removeByIds(faceInfoList.stream().map(FaceInfo::getId).toList()); + } + + private static QueryWrapper buildQueryWrapper(FaceInfoListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(FaceInfo.class); + if (Utils.isNotNull(dto.getFaceSign())) { + wrapper.eq(FaceInfo::getFaceSign, dto.getFaceSign()); + } + if (Utils.isNotNull(dto.getName())) { + wrapper.like(FaceInfo::getName, dto.getName()); + } + if (Utils.isNotNull(dto.getLibraryId())) { + wrapper.eq(FaceInfo::getLibraryId, dto.getLibraryId()); + } + if (Utils.isNotNull(dto.getRegisterTimeStart()) && Utils.isNotNull(dto.getRegisterTimeEnd())) { + wrapper.between(FaceInfo::getRegisterTime, dto.getRegisterTimeStart(), dto.getRegisterTimeEnd()); + } + return wrapper; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceLibraryServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceLibraryServiceImpl.java new file mode 100644 index 0000000..8efecd2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/FaceLibraryServiceImpl.java @@ -0,0 +1,183 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.EdgeBoxMapper; +import com.sz.admin.monitor.mapper.FaceImageMapper; +import com.sz.admin.monitor.mapper.FaceInfoMapper; +import com.sz.admin.monitor.mapper.FaceLibraryMapper; +import com.sz.admin.monitor.pojo.dto.faceinfo.FaceInfoListDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryCreateDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryImportDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryListDTO; +import com.sz.admin.monitor.pojo.dto.facelibrary.FaceLibraryUpdateDTO; +import com.sz.admin.monitor.pojo.po.EdgeBox; +import com.sz.admin.monitor.pojo.po.FaceInfo; +import com.sz.admin.monitor.pojo.po.FaceLibrary; +import com.sz.admin.monitor.pojo.vo.faceinfo.FaceInfoVO; +import com.sz.admin.monitor.pojo.vo.facelibrary.FaceLibraryVO; +import com.sz.admin.monitor.service.FaceInfoService; +import com.sz.admin.monitor.service.FaceLibraryService; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.AlgMediaConfigResponse; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.FileUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import com.sz.excel.core.ExcelResult; +import com.sz.excel.utils.ExcelUtils; +import com.sz.platform.enums.AdminResponseEnum; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.OutputStream; +import java.io.Serializable; +import java.util.List; + +/** + * ClassName: FaceLibraryServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class FaceLibraryServiceImpl extends ServiceImpl implements FaceLibraryService { + private final FaceInfoService faceInfoService; + private final AiBoxRequestUtil aiBoxRequestUtil; + private final EdgeBoxMapper edgeBoxMapper; + @Override + @Transactional(rollbackFor = Exception.class) + public void create(FaceLibraryCreateDTO dto){ + EdgeBox edgeBox = edgeBoxMapper.selectOneById(dto.getBoxId()); + if (edgeBox == null) { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "盒子不存在"); + } + AlgMediaConfigResponse response = aiBoxRequestUtil.createFaceLibrary(edgeBox.getIp(), + edgeBox.getPort(), + dto.getName()); + Integer albumId = response.getAlbumId(); + // 创建人脸库 + FaceLibrary ryFaceLibrary = BeanCopyUtils.copy(dto, FaceLibrary.class); + ryFaceLibrary.setAlbumId(albumId); + try { + // 保存数据到数据库 + save(ryFaceLibrary); + }catch (Exception e) + { + // 如果保存失败,则删除盒子新建的人脸库 + aiBoxRequestUtil.deleteFaceLibrary(edgeBox.getIp(), + edgeBox.getPort(), dto.getName()); + throw e; + } + } + + @Override + public void update(FaceLibraryUpdateDTO dto){ + FaceLibrary ryFaceLibrary = BeanCopyUtils.copy(dto, FaceLibrary.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create() + .eq(FaceLibrary::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + + saveOrUpdate(ryFaceLibrary); + } + + @Override + public PageResult page(FaceLibraryListDTO dto){ + try { + SimpleDataScopeHelper.start(FaceLibrary.class); + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), FaceLibraryVO.class); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(FaceLibraryListDTO dto){ + try { + SimpleDataScopeHelper.start(FaceLibrary.class); + return listAs(buildQueryWrapper(dto), FaceLibraryVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void remove(SelectIdsDTO dto){ + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + List faceLibraryList = listByIds(dto.getIds()); + if (faceLibraryList.isEmpty()) + { + return; + } + for (FaceLibrary library : faceLibraryList) { + try { + Long boxId = library.getBoxId(); + EdgeBox edgeBox = edgeBoxMapper.selectOneById(boxId); + aiBoxRequestUtil.deleteFaceLibrary(edgeBox.getIp(), edgeBox.getPort(), library.getName()); + }catch (Exception e) + { + log.error("AI盒子删除人脸库失败, libraryName: {}", library.getName(), e); + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, "同步删除AI盒子数据失败,请重试"); + } + } + // 删除人脸信息表关联数据 + faceInfoService.removeByLibraryIds(dto.getIds()); + removeByIds(dto.getIds()); + } + @Override + public FaceLibraryVO detail(Object id){ + FaceLibrary ryFaceLibrary = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(ryFaceLibrary); + return BeanCopyUtils.copy(ryFaceLibrary, FaceLibraryVO.class); + } + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), FaceLibraryImportDTO.class, true); + List list = excelResult.getList(); + // 入库 + List importList = BeanCopyUtils.copyList(list, FaceLibrary.class); + saveBatch(importList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + } + + @SneakyThrows + @Override + public void exportExcel(FaceLibraryListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "人脸库表模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "人脸库表", FaceLibraryVO.class, os); + } + + private static QueryWrapper buildQueryWrapper(FaceLibraryListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(FaceLibrary.class); + if (Utils.isNotNull(dto.getName())) { + wrapper.like(FaceLibrary::getName, dto.getName()); + } + if (Utils.isNotNull(dto.getBoxId())) { + wrapper.eq(FaceLibrary::getBoxId, dto.getBoxId()); + } + return wrapper; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/ForwardServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/ForwardServiceImpl.java new file mode 100644 index 0000000..824b3b0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/ForwardServiceImpl.java @@ -0,0 +1,25 @@ +package com.sz.admin.monitor.service.impl; + +import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto; +import com.sz.admin.monitor.service.ForwardService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +/** + * ClassName: ForwardServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +@Slf4j +public class ForwardServiceImpl implements ForwardService { + @Resource + private RestTemplate restTemplate; + @Override + public void enrichAndForward(BoxAlarmReportDto boxAlarm) { + ResponseEntity response = restTemplate.postForEntity(boxAlarm.getUrl(), boxAlarm, String.class); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/IpChannelServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/IpChannelServiceImpl.java new file mode 100644 index 0000000..1431dd2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/IpChannelServiceImpl.java @@ -0,0 +1,388 @@ +package com.sz.admin.monitor.service.impl; + +import cn.hutool.core.lang.UUID; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.enums.HCPlayControlEnum; +import com.sz.admin.monitor.mapper.AlgorithmTaskMapper; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.EdgeBoxMapper; +import com.sz.admin.monitor.mapper.NvrMapper; +import com.sz.admin.monitor.pojo.dto.Ipchannel.ControlDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.AlgorithmTaskDTO; +import com.sz.admin.monitor.pojo.po.AlgorithmTask; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.EdgeBox; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO; +import com.sz.admin.monitor.pojo.vo.ptz.PTZVO; +import com.sz.admin.monitor.pojo.vo.watchful.WatchfulVO; +import com.sz.admin.monitor.sdk.ManageNVR; +import com.sz.admin.monitor.service.CameraSnapshotService; +import com.sz.admin.monitor.service.IpChannelService; +import com.sz.admin.monitor.service.PresetService; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.AlgMediaConfigResponse; +import com.sz.admin.monitor.utils.RtspUtil; +import com.sz.admin.monitor.utils.ZLMediaKitUtils; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.JsonUtils; +import com.sz.platform.enums.AdminResponseEnum; +import com.sz.redis.handler.WsToServiceMsgHandler; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * ClassName: IpChannelServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +@Slf4j +public class IpChannelServiceImpl extends ServiceImpl implements IpChannelService, WsToServiceMsgHandler { + @Resource + private CameraMapper cameraMapper; + @Resource + private NvrMapper nvrMapper; + @Resource + private ManageNVR manageNVR; + @Resource + private ZLMediaKitUtils zlMediaKitUtils; + + @Resource + private AlgorithmTaskMapper algorithmTaskMapper; + + @Resource + private PresetService presetService; + + @Resource + private AiBoxRequestUtil aiBoxRequestUtil; + + @Resource + private CameraSnapshotService cameraSnapshotService; + + @Resource + private StringRedisTemplate stringRedisTemplate; + @Resource + private EdgeBoxMapper edgeBoxMapper; + + // Redis Key 前缀 + private static final String VIEWERS_KEY_PREFIX = "camera:viewers:"; + // 所有的活跃流Key集合 + private static final String ACTIVE_CHANNELS_SET = "camera:active_channels"; + + + @Override + public Camera getByChannelId(Integer channelId) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(Camera.class) + .eq(Camera::getChannelId, channelId); + return cameraMapper.selectOneByQuery(wrapper); + } + + @Override + public void userHeartbeat(Long id,String uuid) { + String key = VIEWERS_KEY_PREFIX + id; + long now = System.currentTimeMillis(); + // 在zSet中更新用户的时间戳 + stringRedisTemplate.opsForZSet().add(key, uuid, now); + // 设置key的过期时间为一个小时 + stringRedisTemplate.expire(key, 1, TimeUnit.HOURS); + // 将该频道加入到活跃频道列表,给定时任务进行遍历 + stringRedisTemplate.opsForSet().add(ACTIVE_CHANNELS_SET, String.valueOf(id)); + } + + /** + * + * @param id 通道id + * @return + */ + @Override + public String preview(Long id) { + Camera camera = this.getById(id); + if(camera.getStatus()==0) + { + // 如果摄像头不在线,直接返回 + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null,"摄像头不在线"); + } + Nvr nvr = nvrMapper.selectOneById(camera.getNvrId()); + Map rtspMap = RtspUtil.getRtsp(nvr.getDriver(), nvr.getAccount(), nvr.getPassword(), camera.getChannelId()-32, nvr.getIp(), 554); + // 获取主码流 + String mainRtsp = rtspMap.get("mainRtsp"); + log.info("主码流的rtsp信息: {}", mainRtsp); + // 进行拉流代理 + JSONObject jsonObject =zlMediaKitUtils.addStreamProxy(String.valueOf(id), mainRtsp); + // JSONObject jsonObject = zlMediaKitUtils.addStreamProxy("test", "rtsp://132.239.12.145:554/axis-media/media.amp"); + if ("0".equals(jsonObject.get("code").toString())) { + //拉流代理成功 + return zlMediaKitUtils.getPlayUrl(String.valueOf(id)); + } else if (jsonObject.get("msg").toString().contains("already exists") || "-1".equals(jsonObject.get("code").toString())) { + // 流已经存在了,直接复用 + return zlMediaKitUtils.getPlayUrl(String.valueOf(id)); + } else { + throw new BusinessException(AdminResponseEnum.DEVICE_ADD_PROXY_FAIL,null,"添加流代理失败"); + } + } + + // 停止预览 + @Override + public Integer stopPreview(Long id, String uuid) { + String key = VIEWERS_KEY_PREFIX + id; + // 从zSet中移除该用户 + stringRedisTemplate.opsForZSet().remove(key, uuid); + return checkAndCloseStream(id); + } + + /** + * 定时任务:看门狗 (每 10 秒执行一次) + */ + @Scheduled(fixedRate = 10000) + public void scanZombieStreams() { + // 获取所有记录在案的活跃频道 + Set channels = stringRedisTemplate.opsForSet().members(ACTIVE_CHANNELS_SET); + if (channels == null || channels.isEmpty()) return; + + for (String channelIdStr : channels) { + Long id = Long.parseLong(channelIdStr); + checkAndCloseStream(id); + } + } + + // 检查流是否应该关闭 + private Integer checkAndCloseStream(Long id) { + String key = VIEWERS_KEY_PREFIX + id; + long now = System.currentTimeMillis(); + // 阈值:30秒没心跳视为掉线 + long threshold = now - 30000; + // 移除超过30秒没有更新心跳的成员 + stringRedisTemplate.opsForZSet().removeRangeByScore(key, 0, threshold); + // 统计剩余人数 + Long count = stringRedisTemplate.opsForZSet().zCard(key); + if (count == null || count == 0) { + // 如果剩余人数为0了,那么意味着这个摄像头的流没有人在观看了直接关流 + JSONObject jsonObject = zlMediaKitUtils.CloseStreamProxy(String.valueOf(id)); + log.info("关闭流:{}", jsonObject.toString()); + // 清理redis中的数据 + stringRedisTemplate.delete(key); + stringRedisTemplate.opsForSet().remove(ACTIVE_CHANNELS_SET, String.valueOf(id)); + return 1; + } else { + log.info("摄像头[{}] 当前在线观看人数:{}", id, count); + return -1; + } + } + + + @Override + public Object ptzControl(Long id, Integer direction, int speed, int startFlag) { + HCPlayControlEnum hcPlayControlEnum = HCPlayControlEnum.getByCode(direction); + if (hcPlayControlEnum == null) { + throw new BusinessException(AdminResponseEnum.DEVICE_PTZ_CONTROL_FAIL, null, "PTZ控制失败"); + } + return manageNVR.ptzCon(id.intValue(), hcPlayControlEnum.getCode().toString(), String.valueOf(speed), String.valueOf(startFlag)); + } + + @Override + public Object controlPreset(Long id, int ptzPresetCmd, int dwPresetIndex, String pointName, int isBasicPoint) { + if (ptzPresetCmd == 8 && isBasicPoint == 1) { + // 如果是设置预置位并且是基准位,那么就需要抓取一张标准图片 + CameraSnapshotVO cameraSnapshotVO = cameraSnapshotService.captureAndSave(id, 1, dwPresetIndex); + Camera camera = this.getById(id); + // 保存基准图 + camera.setHomeImagePath(cameraSnapshotVO.getImagePath()); + updateById(camera); + } + return manageNVR.ptzPresets(id.intValue(), ptzPresetCmd, String.valueOf(dwPresetIndex), pointName); + } + + // 开启一个定时任务,去校验摄像头的ptz参数是否一致了,如果一致则是归位了 + // @Scheduled(fixedRate = 1000) // 每秒执行一次 + public void scanSentinelTasks() { + String s = stringRedisTemplate.opsForValue().get("camera:sentinel"); + PTZVO ptzvo = JSON.parseObject(s, PTZVO.class); + if (ptzvo != null) { + // 获取当前的位置 + PTZVO curPtz = manageNVR.getPTZLocation(ptzvo.getCameraId()); + curPtz.setCameraId(ptzvo.getCameraId()); + log.info("当前位置:{}", curPtz); + if (ptzvo.equals(curPtz)) { + // 如果两个位置相同,则是归位了 TODO 进行图片对比的功能 + log.info("redis中的ptz信息:{},当前位置的ptz信息:{}", ptzvo, curPtz); + } + } + + } + + // 开启和关闭云台守望 + @Override + @Transactional + public boolean ControlSentinel(Long id, int openOrNo, int watchTime, Integer presetIndex) { + boolean flag=false; + if (openOrNo==0) + { + flag = manageNVR.watchful(id.intValue(), openOrNo, watchTime, -1); + }else { + flag = manageNVR.watchful(id.intValue(), openOrNo, watchTime, presetIndex); + } + if (flag) { + // 获取当前预置点的ptz坐标,并且保存 + PTZVO ptzLocation = manageNVR.getPTZLocation(id); + ptzLocation.setCameraId(id); + // 将ptz保存到redis中 + stringRedisTemplate.opsForValue().set("camera:sentinel", JSON.toJSONString(ptzLocation)); + log.info("ptz 坐标:{}", ptzLocation); + Camera camera = this.getById(id); + // 保存守望信息 + camera.setWatchfulTime(watchTime); + camera.setWatchfulIndex(presetIndex); + if (openOrNo != 0) { + cameraMapper.update(camera); + } + + } + return flag; + } + + @Override + public WatchfulVO getWatchful(Long id) { + Camera camera = this.getById(id); + // WatchfulVO watchful = manageNVR.getWatchful(channelId); + return BeanCopyUtils.copy(camera, WatchfulVO.class); + } + + @Override + public AlgMediaConfigResponse configAlg(AlgorithmTaskDTO algorithmTaskDTO) { + Long cameraId = algorithmTaskDTO.getCameraId(); + // 查询摄像机 + Camera camera = cameraMapper.selectOneById(cameraId); + if (camera==null) + { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "摄像头不存在"); + } + Long boxId = camera.getBoxId(); + if (boxId == null) { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "摄像头没有绑定盒子"); + } + EdgeBox edgeBox = edgeBoxMapper.selectOneById(boxId); + List algInfo = algorithmTaskDTO.getAlgInfo(); + if (algInfo == null) + { + algInfo = new ArrayList<>(); + } + if (algInfo.size()>3) + { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL, null, "算法配置同时最多支持3个"); + } + // 摄像机名称,从数据库查询获取 + algorithmTaskDTO.setMediaName(camera.getId().toString()); + // 查询该摄像机是否已有算法配置记录 + QueryWrapper queryWrapper = QueryWrapper.create() + .select() + .from(AlgorithmTask.class) + .where(AlgorithmTask::getCameraId).eq(cameraId) + .orderBy(AlgorithmTask::getCreateTime, false) + .limit(1); + AlgorithmTask existingTask = algorithmTaskMapper.selectOneByQuery(queryWrapper); + String sessionUuid; + LocalDateTime createTime=null; + if (existingTask != null) + { + // 修改 + sessionUuid = existingTask.getAlgTaskSession(); + createTime=existingTask.getCreateTime(); + }else { + // 新增 + sessionUuid=UUID.randomUUID().toString().replaceAll("-", ""); + } + algorithmTaskDTO.setAlgTaskSession(sessionUuid); + List algList= new ArrayList<>(); + if (algInfo.contains(8)) { + // 配置子算法 + algList.add(46); + } + if(algInfo.contains(52)) + { + algList.add(207); + } + if(algInfo.contains(58)) + { + algList.add(248); + } + if (algInfo.contains(1)) { + algList.add(195); + } + AlgorithmTaskDTO.UserDataDto userDataDto = AlgorithmTaskDTO.UserDataDto.builder() + .build(); + if (algorithmTaskDTO.getUserData()!=null) + { + BeanCopyUtils.copy(algorithmTaskDTO.getUserData(), userDataDto); + } + userDataDto.setMethodConfig(algList); + algorithmTaskDTO.setUserData(userDataDto); + // DTO转PO + AlgorithmTask algorithmTask = BeanCopyUtils.copy(algorithmTaskDTO, AlgorithmTask.class); + algorithmTask.setIsDeleted("F"); + algorithmTask.setCreateTime(createTime); + ObjectMapper mapper = new ObjectMapper(); + try { + String userDataJson = mapper.writeValueAsString(algorithmTaskDTO.getUserData()); + JsonNode jsonNode = mapper.readTree(userDataJson); + algorithmTask.setUserData(jsonNode); + }catch (Exception e) + { + throw new RuntimeException("UserData转换失败", e); + } + AlgMediaConfigResponse response; + try { + if (existingTask != null) { + log.info("摄像机已存在配置,先清理旧任务: {}", sessionUuid); + aiBoxRequestUtil.controlTask(edgeBox.getIp(), edgeBox.getPort(), sessionUuid, 0); + aiBoxRequestUtil.deleteTask(edgeBox.getIp(), edgeBox.getPort(), sessionUuid); + } + // 应用新算法 + response = aiBoxRequestUtil.setupTask(edgeBox.getIp(), edgeBox.getPort(), algorithmTaskDTO); + } catch (Exception e) { + log.error("AI 盒子任务下发失败, 摄像机: {}", camera.getName(), e); + throw new RuntimeException("下发算法配置到设备失败,请检查网络或设备状态", e); + } + try { + algorithmTaskMapper.insertOrUpdate(algorithmTask); + } catch (Exception e) { + log.error("本地数据库保存算法配置失败,开始尝试回滚盒子端任务。摄像机: {}", camera.getName(), e); + try { + // 把刚才成功创建的盒子任务删掉 + aiBoxRequestUtil.controlTask(edgeBox.getIp(), edgeBox.getPort(), sessionUuid, 0); + aiBoxRequestUtil.deleteTask(edgeBox.getIp(), edgeBox.getPort(), sessionUuid); + } catch (Exception rollbackEx) { + log.error("【严重】数据库落库失败,且清理AI盒子配置也失败!", rollbackEx); + } + throw new RuntimeException("系统内部异常,算法配置数据保存失败"); + } + return response; + } + // 在这里接收透传过来的 websocket信息,进行业务处理 + @Override + public void handlerMsg(TransferMessage transferMessage) { + Object data = transferMessage.getMessage().getData(); + ControlDTO controlDTO = JsonUtils.parseObject(JsonUtils.toJsonString(data), ControlDTO.class); + if (controlDTO != null) + { + this.ptzControl(controlDTO.getId(), controlDTO.getDirection(), controlDTO.getSpeed(), controlDTO.getStartFlag()); + } + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/NvrServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/NvrServiceImpl.java new file mode 100644 index 0000000..2b8e4c8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/NvrServiceImpl.java @@ -0,0 +1,220 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.NvrMapper; +import com.sz.admin.monitor.mapper.RegionMapper; +import com.sz.admin.monitor.pojo.dto.nvr.NvrCreateDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrListDTO; +import com.sz.admin.monitor.pojo.dto.nvr.NvrUpdateDTO; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.Region; +import com.sz.admin.monitor.pojo.po.table.RegionTableDef; +import com.sz.admin.monitor.pojo.po.table.SubstationTableDef; +import com.sz.admin.monitor.pojo.vo.nvr.NvrVO; +import com.sz.admin.monitor.service.NvrService; +import com.sz.core.common.entity.PageQuery; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import com.sz.platform.enums.AdminResponseEnum; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static com.sz.admin.monitor.pojo.po.table.NvrTableDef.NVR; + +/** + * ClassName: NvrServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +public class NvrServiceImpl extends ServiceImpl implements NvrService { + private static final Logger log = LoggerFactory.getLogger(NvrServiceImpl.class); + @Resource + private RegionMapper regionMapper; + @Resource + private CameraMapper cameraMapper; + + @Resource + private NvrMapper nvrMapper; + @Override + public void upStatusById(Long id, int status) { + QueryWrapper wrapper = QueryWrapper.create() + .eq(Nvr::getId, id); + update(Nvr.builder().status(status).build(), wrapper); + } + @Override + public Long create(NvrCreateDTO dto) { + Nvr nvr = BeanCopyUtils.copy(dto, Nvr.class); + // 唯一性校验 + nvrMapper.insert(nvr); + return nvr.getId(); + } + + @Override + public void update(NvrUpdateDTO dto) { + Nvr nvr = BeanCopyUtils.copy(dto, Nvr.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(Nvr::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + // 唯一性校验 + saveOrUpdate(nvr); + } + + @Override + public PageResult page(NvrListDTO dto) { + try { + SimpleDataScopeHelper.start(Nvr.class); // 指定要追加条件的表PO实体 + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), NvrVO.class); // 调试sql + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(NvrListDTO dto) { + try { + SimpleDataScopeHelper.start(Nvr.class); // 指定要追加条件的表PO实体 + return listAs(buildQueryWrapper(dto), NvrVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + // 批量查询nvr信息 + List nvrList = listByIds(dto.getIds()); + if (nvrList.isEmpty()) { + return; + } + nvrList.forEach(nvr -> { + Long id = nvr.getId(); + // 根据nvr的ID,去查询关联的摄像头 + List cameras = cameraMapper.selectByNvrId(id); + if (!cameras.isEmpty()) + { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null,nvr.getName()+"下存在摄像头,请先删除摄像头"); + } + }); + removeByIds(dto.getIds()); + } + + @Override + public NvrVO detail(Long id) { + Nvr nvr = getById(id); + CommonResponseEnum.INVALID_ID.assertNull(nvr); + return BeanCopyUtils.copy(nvr, NvrVO.class); + } + + @Override + public PageResult listByNode(Long nodeId, Integer type, Integer pageNum, Integer pageSize) { + Page page=null; + if(type==0) + { + // 获取某个区域下的所有NVR + // 查询区域信息,用于判断是否是根节点 + QueryWrapper regionWrapper = QueryWrapper.create() + .select(RegionTableDef.REGION.ALL_COLUMNS) + .from(Region.class) + .where(RegionTableDef.REGION.ID.eq(nodeId)); + Region region = regionMapper.selectOneByQuery(regionWrapper); + if (region.getParentId()==0) + { + // 根节点 + QueryWrapper subQuery1 = QueryWrapper.create() + .select(SubstationTableDef.SUBSTATION.ID) + .from(SubstationTableDef.SUBSTATION) + .join(RegionTableDef.REGION) + .on(SubstationTableDef.SUBSTATION.REGION_ID.eq(RegionTableDef.REGION.ID)) + .where(RegionTableDef.REGION.PARENT_ID.eq(region.getId())); + QueryWrapper subQuery2 = QueryWrapper.create() + .select(SubstationTableDef.SUBSTATION.ID) + .from(SubstationTableDef.SUBSTATION) + .where(SubstationTableDef.SUBSTATION.REGION_ID.eq(region.getId())); + QueryWrapper mainQuery = QueryWrapper.create() + .select(NVR.ALL_COLUMNS) + .from(NVR) + .where(NVR.STATION_ID.in( + subQuery1.union(subQuery2) + )); + PageQuery pageQuery = new PageQuery(); + pageQuery.setPage(pageNum); + pageQuery.setLimit(pageSize); + page = pageAs(PageUtils.getPage(pageQuery),mainQuery, NvrVO.class); + }else { + QueryWrapper wrapper = QueryWrapper.create() + .select(NVR.ALL_COLUMNS) + .from(NVR) + .join(SubstationTableDef.SUBSTATION) + .on(NVR.STATION_ID.eq(SubstationTableDef.SUBSTATION.ID)) + .where(SubstationTableDef.SUBSTATION.REGION_ID.eq(nodeId)); + PageQuery pageQuery = new PageQuery(); + pageQuery.setPage(pageNum); + pageQuery.setLimit(pageSize); + page = pageAs(PageUtils.getPage(pageQuery), wrapper, NvrVO.class); + } + + }else if (type==1) + { + // 获取某个变电站下的所有NVR + QueryWrapper wrapper = QueryWrapper.create() + .select() + .where(NVR.STATION_ID.eq(nodeId)); + PageQuery pageQuery = new PageQuery(); + pageQuery.setPage(pageNum); + pageQuery.setLimit(pageSize); + page = pageAs(PageUtils.getPage(pageQuery), wrapper, NvrVO.class); + } + assert page != null; + return PageUtils.getPageResult(page); + } + + + + + private static QueryWrapper buildQueryWrapper(NvrListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(Nvr.class); + if (Utils.isNotNull(dto.getIp())) { + wrapper.eq(Nvr::getIp, dto.getIp()); + } + if (Utils.isNotNull(dto.getId())) { + wrapper.eq(Nvr::getId, dto.getId()); + } + if (Utils.isNotNull(dto.getName())) { + wrapper.like(Nvr::getName, dto.getName()); + } + + if (Utils.isNotNull(dto.getDriver())) { + wrapper.eq(Nvr::getDriver, dto.getDriver()); + } + if (Utils.isNotNull(dto.getStatus())) { + wrapper.eq(Nvr::getStatus, dto.getStatus()); + } + if (Utils.isNotNull(dto.getStationId())) { + wrapper.eq(Nvr::getStationId, dto.getStationId()); + } + if (Utils.isNotNull(dto.getPort())) { + wrapper.eq(Nvr::getPort, dto.getPort()); + } + return wrapper; + } + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/PresetServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/PresetServiceImpl.java new file mode 100644 index 0000000..7f11a45 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/PresetServiceImpl.java @@ -0,0 +1,156 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.PresetMapper; +import com.sz.admin.monitor.pojo.dto.preset.PresetCreateDTO; +import com.sz.admin.monitor.pojo.dto.preset.PresetDeleteDTO; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.Preset; +import com.sz.admin.monitor.pojo.po.table.CameraTableDef; +import com.sz.admin.monitor.pojo.po.table.PresetTableDef; +import com.sz.admin.monitor.pojo.vo.preset.PresetVO; +import com.sz.admin.monitor.pojo.vo.watchful.WatchfulVO; +import com.sz.admin.monitor.sdk.ManageNVR; +import com.sz.admin.monitor.service.IpChannelService; +import com.sz.admin.monitor.service.PresetService; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.core.util.BeanCopyUtils; +import com.sz.platform.enums.AdminResponseEnum; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * ClassName: PresetServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +public class PresetServiceImpl extends ServiceImpl implements PresetService { + private static final Logger log = LoggerFactory.getLogger(PresetServiceImpl.class); + @Resource + private PresetMapper presetMapper; + @Resource + private CameraMapper cameraMapper; + @Resource + private ManageNVR manageNVR; + + @Override + public List getPresetList(Long cameraId) { + QueryWrapper queryWrapper = QueryWrapper.create() + .from(PresetTableDef.PRESET) + .where(PresetTableDef.PRESET.CAMERA_ID.eq(cameraId)); + List presets = presetMapper.selectListByQuery(queryWrapper); + Map definedMap = presets.stream().collect(Collectors.toMap(Preset::getPresetId, Preset::getPresetName)); + // 构造1-8条预置位给前端 + List result = new ArrayList<>(); + for (int i = 1; i <= 8; i++) { + PresetVO presetVO = new PresetVO(); + presetVO.setPresetIndex(i); + if (definedMap.containsKey(i)) { + presetVO.setPresetName(definedMap.get(i)); + presetVO.setIsSet(true); + } else { + presetVO.setPresetName("未定义"); + presetVO.setIsSet(false); + } + result.add(presetVO); + } + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void removePreset(PresetDeleteDTO dto) { + log.info("准备删除预置位,请求参数:{}", dto); + // 1. 获取守望信息,并做防空处理 + WatchfulVO watchful = manageNVR.getWatchful(dto.getCameraId()); + if (watchful != null) { + // 安全比对预置位索引是否相同 + boolean isCurrentWatchful = Objects.equals(watchful.getWatchfulIndex(), dto.getCurrentPresetIndex()); + if (watchful.getWatchfulState() == 1 && isCurrentWatchful) { + throw new BusinessException(AdminResponseEnum.CHANNEL_PRESET_FAIL, null, "当前预置位被设置为守望位,请先关闭或者修改守望位"); + } + if (watchful.getWatchfulState() == 0 && isCurrentWatchful) { + Camera updateEntity = new Camera(); + updateEntity.setWatchfulIndex(null); + QueryWrapper updateWrapper = QueryWrapper.create() + .from(CameraTableDef.CAMERA) + .where(CameraTableDef.CAMERA.ID.eq(dto.getCameraId())) + .and(CameraTableDef.CAMERA.WATCHFUL_INDEX.eq(dto.getCurrentPresetIndex())); + int updateCount = cameraMapper.updateByQuery(updateEntity, updateWrapper); + } + } + // 3. 删除预置位表中的数据 + QueryWrapper deleteWrapper = QueryWrapper.create() + .from(PresetTableDef.PRESET) + .where(PresetTableDef.PRESET.CAMERA_ID.eq(dto.getCameraId())) + .and(PresetTableDef.PRESET.PRESET_ID.eq(dto.getCurrentPresetIndex())); + int deleteCount = presetMapper.deleteByQuery(deleteWrapper); + log.info("预置位删除完成,受影响行数:{}", deleteCount); + } + + @Override + @Transactional + public void create(PresetCreateDTO dto) { + // 先删除和新增 + Integer presetId = dto.getPresetId(); + Long cameraId = dto.getCameraId(); + Preset curPreset = selectByCameraIdAndPresetIndex(cameraId, presetId); + if (curPreset != null) { + this.removeById(curPreset); + } + Preset preset = BeanCopyUtils.copy(dto, Preset.class); + save(preset); + } + + @Override + public Preset selectByCameraIdAndPresetIndex(Long cameraId, int presetIndex) { + QueryWrapper wrapper = QueryWrapper.create() + .from(PresetTableDef.PRESET) + .where(PresetTableDef.PRESET.CAMERA_ID.eq(cameraId)) + .and(PresetTableDef.PRESET.PRESET_ID.eq(presetIndex)); + return presetMapper.selectOneByQuery(wrapper); + } + + @Override + public List getExistPresetList(Long cameraId) { + QueryWrapper wrapper = QueryWrapper.create() + .from(PresetTableDef.PRESET) + .where(PresetTableDef.PRESET.CAMERA_ID.eq(cameraId)); + List presets = presetMapper.selectListByQuery(wrapper); + return presets.stream().map(preset -> { + PresetVO presetVO = new PresetVO(); + presetVO.setPresetName(preset.getPresetName()); + presetVO.setPresetIndex(preset.getPresetId()); + presetVO.setIsSet(true); + return presetVO; + }).toList(); + + } + + @Override + public List selectByCameraIds(List cameraIds) { + QueryWrapper wrapper = QueryWrapper.create() + .from(PresetTableDef.PRESET) + .where(PresetTableDef.PRESET.CAMERA_ID.in(cameraIds)) + .and(PresetTableDef.PRESET.IS_BASIC_POINT.eq(1)); + return list(wrapper); + } + + + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/RegionServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/RegionServiceImpl.java new file mode 100644 index 0000000..8952cf8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/RegionServiceImpl.java @@ -0,0 +1,106 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.RegionMapper; +import com.sz.admin.monitor.pojo.dto.region.RegionCreateDTO; +import com.sz.admin.monitor.pojo.dto.region.RegionListDTO; +import com.sz.admin.monitor.pojo.dto.region.RegionUpdateDTO; +import com.sz.admin.monitor.pojo.po.Region; +import com.sz.admin.monitor.pojo.vo.Region.RegionVO; +import com.sz.admin.monitor.service.RegionService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * ClassName: RegionServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +public class RegionServiceImpl extends ServiceImpl implements RegionService { + @Override + public void create(RegionCreateDTO dto) { + Region region = BeanCopyUtils.copy(dto, Region.class); + // 唯一性校验 + save(region); + } + + @Override + public void update(RegionUpdateDTO dto) { + Region region = BeanCopyUtils.copy(dto, Region.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(Region::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + // 唯一性校验 + saveOrUpdate(region); + } + + @Override + public PageResult page(RegionListDTO dto) { + try { + SimpleDataScopeHelper.start(Region.class); // 指定要追加条件的表PO实体 + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), RegionVO.class); // 调试sql + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(RegionListDTO dto) { + try { + SimpleDataScopeHelper.start(Region.class); // 指定要追加条件的表PO实体 + return listAs(buildQueryWrapper(dto), RegionVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public RegionVO detail(Long id) { + Region region = getById(id); + CommonResponseEnum.INVALID_ID.assertNull(region); + return BeanCopyUtils.copy(region, RegionVO.class); + } + + + + + + private static QueryWrapper buildQueryWrapper(RegionListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(Region.class); + if (Utils.isNotNull(dto.getCode())) { + wrapper.eq(Region::getCode, dto.getCode()); + } + if (Utils.isNotNull(dto.getName())) { + wrapper.like(Region::getName, dto.getName()); + } + + if (Utils.isNotNull(dto.getLevel())) { + wrapper.eq(Region::getLevel, dto.getLevel()); + } + if (Utils.isNotNull(dto.getType())) { + wrapper.eq(Region::getType, dto.getType()); + } + return wrapper; + } + + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/SubstationServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/SubstationServiceImpl.java new file mode 100644 index 0000000..764c033 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/SubstationServiceImpl.java @@ -0,0 +1,146 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.monitor.mapper.SubstationMapper; +import com.sz.admin.monitor.pojo.dto.substation.SubstationCreateDTO; +import com.sz.admin.monitor.pojo.dto.substation.SubstationImportDTO; +import com.sz.admin.monitor.pojo.dto.substation.SubstationListDTO; +import com.sz.admin.monitor.pojo.dto.substation.SubstationUpdateDTO; +import com.sz.admin.monitor.pojo.po.Substation; +import com.sz.admin.monitor.pojo.vo.substation.SubstationVO; +import com.sz.admin.monitor.service.SubstationService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.query.QueryChain; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.PageUtils; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.Utils; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import java.io.Serializable; +import java.util.List; + +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.excel.core.ExcelResult; +import java.io.OutputStream; +import jakarta.servlet.http.HttpServletResponse; +import com.sz.core.util.FileUtils; +import com.sz.excel.utils.ExcelUtils; +import lombok.SneakyThrows; +import com.sz.core.datascope.SimpleDataScopeHelper; + + +/** + *

+ * 变电站和超高压信息表 服务实现类 + *

+ * + * @author Lz + * @since 2026-03-06 + */ +@Service +@RequiredArgsConstructor +public class SubstationServiceImpl extends ServiceImpl implements SubstationService { + @Override + public void create(SubstationCreateDTO dto){ + Substation rySubstation = BeanCopyUtils.copy(dto, Substation.class); + long count; + // 唯一性校验 + count = QueryChain.of(Substation.class).eq(Substation::getName, dto.getName()).count(); + CommonResponseEnum.EXISTS.message("name已存在").assertTrue(count > 0); + save(rySubstation); + } + + @Override + public void update(SubstationUpdateDTO dto){ + Substation rySubstation = BeanCopyUtils.copy(dto, Substation.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create() + .eq(Substation::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + + // 唯一性校验 + long count; + count = QueryChain.of(Substation.class).eq(Substation::getName, dto.getName()).ne(Substation::getId, dto.getId()).count(); + CommonResponseEnum.EXISTS.message("name已存在").assertTrue(count > 0); + saveOrUpdate(rySubstation); + } + + @Override + public PageResult page(SubstationListDTO dto){ + try { + SimpleDataScopeHelper.start(Substation.class); + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), SubstationVO.class); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(SubstationListDTO dto){ + try { + SimpleDataScopeHelper.start(Substation.class); + return listAs(buildQueryWrapper(dto), SubstationVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public void remove(SelectIdsDTO dto){ + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public SubstationVO detail(Object id){ + Substation rySubstation = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(rySubstation); + return BeanCopyUtils.copy(rySubstation, SubstationVO.class); + } + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), SubstationImportDTO.class, true); + List list = excelResult.getList(); + // 入库 + List importList = BeanCopyUtils.copyList(list, Substation.class); + saveBatch(importList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + } + + @SneakyThrows + @Override + public void exportExcel(SubstationListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "变电站和超高压信息表模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "变电站和超高压信息表", SubstationVO.class, os); + } + + private static QueryWrapper buildQueryWrapper(SubstationListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(Substation.class); + if (Utils.isNotNull(dto.getName())) { + wrapper.like(Substation::getName, dto.getName()); + } + if (Utils.isNotNull(dto.getRegionId())) { + wrapper.eq(Substation::getRegionId, dto.getRegionId()); + } + if (Utils.isNotNull(dto.getType())) { + wrapper.eq(Substation::getType, dto.getType()); + } + if (Utils.isNotNull(dto.getAddress())) { + wrapper.eq(Substation::getAddress, dto.getAddress()); + } + return wrapper; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/TreeServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/TreeServiceImpl.java new file mode 100644 index 0000000..86b83a3 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/service/impl/TreeServiceImpl.java @@ -0,0 +1,160 @@ +package com.sz.admin.monitor.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.NvrMapper; +import com.sz.admin.monitor.mapper.RegionMapper; +import com.sz.admin.monitor.mapper.SubstationMapper; + +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.Region; +import com.sz.admin.monitor.pojo.po.Substation; +import com.sz.admin.monitor.pojo.vo.tree.CameraNodeVO; +import com.sz.admin.monitor.pojo.vo.tree.NvrNodeVO; +import com.sz.admin.monitor.pojo.vo.tree.TreeNodeVO; +import com.sz.admin.monitor.service.TreeService; +import jakarta.annotation.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * ClassName: TreeServiceImpl + * Package: com.sz.admin.monitor.service.impl + * Description: + */ +@Service +public class TreeServiceImpl implements TreeService { + private static final Logger log = LoggerFactory.getLogger(TreeServiceImpl.class); + @Resource + private RegionMapper regionMapper; + @Resource + private SubstationMapper substationMapper; + @Resource + private NvrMapper nvrMapper; + @Resource + private CameraMapper cameraMapper; + + @Override + public List buildTree() { + QueryWrapper rootRegionWrapper = new QueryWrapper(); + rootRegionWrapper.eq("parent_id", 0); + List rootRegions = regionMapper.selectListByQuery(rootRegionWrapper); + List treeRoots = new ArrayList<>(); + for (Region rootRegion : rootRegions) { + TreeNodeVO rootNode = new TreeNodeVO(rootRegion.getId(), rootRegion.getName(), 0, null); + List childrenOfRoot = loadChildrenForRegion(rootRegion.getId()); + rootNode.setChildren(childrenOfRoot); + treeRoots.add(rootNode); + } + return treeRoots; + } + + @Override + public List buildTreePreview() { + // 查询出所有的边电站 + List substationList = substationMapper.selectAll(); + List treeRootList = new ArrayList<>(); + for (Substation substation : substationList) { + TreeNodeVO rootNode = new TreeNodeVO(substation.getId(), substation.getName(), 1, null); + List nvrChildren = loadChildrenForNvrByPreview(substation.getId()); + rootNode.setChildren(nvrChildren); + treeRootList.add(rootNode); + } + return treeRootList; + } + + private List loadChildrenForRegion(Long id) { + QueryWrapper childRegionQuery = new QueryWrapper(); + childRegionQuery.eq("parent_id", id); + List childRegions = regionMapper.selectListByQuery(childRegionQuery); + List children = new ArrayList<>(); + for (Region childRegion : childRegions) { + TreeNodeVO childRegionNode = new TreeNodeVO(childRegion.getId(), childRegion.getName(), 0, null); + List substationChildren = loadChildrenForSubstation(childRegion.getId()); + childRegionNode.setChildren(substationChildren ); + children.add(childRegionNode); + } + QueryWrapper specialSubstationQuery = new QueryWrapper(); + specialSubstationQuery.eq("region_id", id).eq("type", 2); // Assuming type 2 is 超高压 + List specialSubstations = substationMapper.selectListByQuery(specialSubstationQuery); + + for (Substation specialSubstation : specialSubstations) { + TreeNodeVO specialSubstationNode = new TreeNodeVO(specialSubstation.getId(), specialSubstation.getName(), 1, null); + List nvrChildren = loadChildrenForNvr(specialSubstation.getId()); + specialSubstationNode.setChildren(nvrChildren); + children.add(specialSubstationNode); + } + return children; + } + private List loadChildrenForSubstation(Long id) { + QueryWrapper substationQuery = new QueryWrapper(); + substationQuery.eq("region_id", id); + List substations = substationMapper.selectListByQuery(substationQuery); + List children = new ArrayList<>(); + for (Substation substation : substations) { + TreeNodeVO substationNode = new TreeNodeVO(substation.getId(), substation.getName(), 1, null); + List nvrChildren = loadChildrenForNvr(substation.getId()); + substationNode.setChildren(nvrChildren); + children.add(substationNode); + } + return children; + } + + private List loadChildrenForNvrByPreview(Long id) { + QueryWrapper nvrQuery = new QueryWrapper(); + nvrQuery.eq("station_id", id); + List nvrList = nvrMapper.selectListByQuery(nvrQuery); + List children = new ArrayList<>(); + for (Nvr nvr : nvrList) { + NvrNodeVO nvrNode = new NvrNodeVO(nvr.getId(), + nvr.getName(), + nvr.getIp(), + nvr.getPort(), + nvr.getDriver(), + nvr.getStatus()); + List cameraChildren = loadChildrenForCamera(nvr.getId()); + nvrNode.setChildren(cameraChildren); + children.add(nvrNode); + } + return children; + } + private List loadChildrenForNvr(Long id) { + QueryWrapper nvrQuery = new QueryWrapper(); + nvrQuery.eq("station_id", id); + List nvrList = nvrMapper.selectListByQuery(nvrQuery); + List children = new ArrayList<>(); + for (Nvr nvr : nvrList) { + NvrNodeVO nvrNode = new NvrNodeVO(nvr.getId(), + nvr.getName(), + nvr.getIp(), + nvr.getPort(), + nvr.getDriver(), + nvr.getStatus()); + children.add(nvrNode); + } + return children; + } + + private List loadChildrenForCamera(Long nvrId) { + QueryWrapper wrapper = QueryWrapper.create() + .select() + .from(Camera.class) + .eq(Camera::getNvrId, nvrId); + List cameraList = cameraMapper.selectListByQuery(wrapper); + List children = new ArrayList<>(); + for (Camera camera : cameraList) { + CameraNodeVO cameraNodeVO = new CameraNodeVO(); + cameraNodeVO.setStatus(camera.getStatus()); + cameraNodeVO.setId(camera.getId()); + cameraNodeVO.setName(camera.getName()); + cameraNodeVO.setType(3); + children.add(cameraNodeVO); + } + return children; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/task/ScheduledTask.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/task/ScheduledTask.java new file mode 100644 index 0000000..22036a0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/task/ScheduledTask.java @@ -0,0 +1,192 @@ +package com.sz.admin.monitor.task; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.UUID; +import com.alibaba.fastjson.JSON; +import com.sz.admin.monitor.enums.AlarmReportEnums; +import com.sz.admin.monitor.mapper.CameraAlarmMapper; +import com.sz.admin.monitor.mapper.CameraMapper; +import com.sz.admin.monitor.mapper.NvrMapper; +import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto; +import com.sz.admin.monitor.pojo.po.Camera; +import com.sz.admin.monitor.pojo.po.CameraAlarm; +import com.sz.admin.monitor.pojo.po.Nvr; +import com.sz.admin.monitor.pojo.po.Preset; +import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO; +import com.sz.admin.monitor.sdk.ManageNVR; +import com.sz.admin.monitor.service.CameraService; +import com.sz.admin.monitor.service.CameraSnapshotService; +import com.sz.admin.monitor.service.ForwardService; +import com.sz.admin.monitor.service.PresetService; +import com.sz.admin.monitor.utils.ImageNameUtils; +import com.sz.admin.monitor.utils.OffsetCalculator; +import com.sz.admin.monitor.utils.RobustImageMatcherUtil; +import com.sz.admin.system.pojo.dto.sysmessage.Message; +import com.sz.admin.system.service.SysMessageService; +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.enums.MessageTransferScopeEnum; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.redis.WebsocketRedisService; +import com.sz.security.core.util.LoginUtils; +import jakarta.annotation.Resource; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * ClassName: ScheduleTask + * Package: com.sz.admin.monitor.task + * Description: 周期任务类 + */ +@Component +@Slf4j +public class ScheduledTask { + @Resource + private PresetService presetService; + @Resource + private CameraService cameraService; + @Resource + private ManageNVR manageNVR; + @Resource + private NvrMapper nvrMapper; + @Resource + private CameraSnapshotService cameraSnapshotService; + @Resource + private CameraAlarmMapper cameraAlarmMapper; + @Resource + private WebsocketRedisService websocketRedisService; + @Resource + private SysMessageService sysMessageService; + @Resource + private ForwardService forwardService; + + + // @Scheduled(cron = "0/5 * * * * ?") + public void test() + { + SocketMessage bean = new SocketMessage(); + Map data = new HashMap<>(); + data.put("title", "移位报警"); + data.put("content", "摄像头[" +33 + "]发生异常,请及时处理!"); + bean.setData(JSON.toJSONString(data)); + bean.setChannel(SocketChannelEnum.MESSAGE); + bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT); + TransferMessage msg = new TransferMessage(); + msg.setMessage(bean); + msg.setFromUser("system"); + msg.setToPushAll(true); + websocketRedisService.sendServiceToWs(msg); + } + // 定期检查 + @Scheduled(cron = "0/20 * * * * ?") + @SneakyThrows + public void executeInspection() { + // 从摄像头表中获取设置了抓图对比和在线的摄像头 + List cameraList = cameraService.selectListByInspection(); + // 然后根据摄像头id查询设置为标准位的预置位, + List cameraIds = cameraList.stream().map(Camera::getId).toList(); + if(CollectionUtil.isEmpty(cameraIds)) + { + // 如果为空,则表示没有摄像头开启巡检功能,直接返回 + return; + } + List presetList = presetService.selectByCameraIds(cameraIds); + for (Preset preset : presetList) { + // 调用SDK让摄像头回归到该预置位 + boolean ok = manageNVR.ptzPresets(preset.getCameraId().intValue(), 39, String.valueOf(preset.getPresetId()), preset.getPresetName()); + // 延时5秒 + Thread.sleep(5000); + if (ok) { + // 抓取一张图片 + String filename = ImageNameUtils.generateFileName("CAPTURE",preset.getCameraId()); + //String image2 = "D:\\work\\images\\CAPTURE_367_20260212092406664_2d117293.jpg"; + // String image2 = "D:\\work\\images\\CAPTURE_19_20260302152457977_db33f5a8.jpg"; + String image2 = manageNVR.capturePic(preset.getCameraId().intValue(), filename); + // 从图片表中,根据预置位,摄像机id,类型为巡检为条件查询出基准图 + CameraSnapshotVO cameraSnapshotVO = cameraSnapshotService.selectByCameraIdAndPresetIndex(preset.getCameraId(), preset.getPresetId()); + if (cameraSnapshotVO == null || cameraSnapshotVO.getImagePath() == null) { + log.warn("摄像机[{}] 未设置基准图,无法对比", preset.getCameraId()); + continue; + } + // 调用图片对比算法,校验摄像头是否移位 + // 基准图 + String image1 = cameraSnapshotVO.getImagePath(); + // 对比 + Map map = RobustImageMatcherUtil.calculateOffset(image1, image2); + log.info("图片对比结果:{}", map); + // 判断结果并报警 + handleAnalysisResult(preset, cameraSnapshotVO.getImagePath(), image2, map); + } + } + + } + + //判断结果并报警 + private void handleAnalysisResult(Preset preset, String imagePath, String image2, Map map) throws IOException { + int value = (int) map.get("value"); + if (value == 1) { + // 发生了偏移,需要保存报警信息等人工处理 + Camera camera = cameraService.getById(preset.getCameraId()); + CameraAlarm cameraAlarm = new CameraAlarm(); + cameraAlarm.setCameraId(camera.getId()); + // 设置告警区域 + // 根据摄像头查询它对应的nvr + Nvr nvr = nvrMapper.selectOneById(camera.getNvrId()); + // 设置告警区域 + cameraAlarm.setAlarmAreaId(nvr.getStationId()); + cameraAlarm.setChannelId(camera.getChannelId()); + cameraAlarm.setCameraName(camera.getName()); + cameraAlarm.setPresetIndex(preset.getPresetId()); + // 标记为移位报警 + cameraAlarm.setAlarmType(1); + cameraAlarm.setBaseImage(imagePath); + cameraAlarm.setCaptureImage(image2); + // 算法的结果 + cameraAlarm.setAlgoResult((String) map.get("description")); + // 状态为未处理 + cameraAlarm.setStatus(0); + cameraAlarmMapper.insert(cameraAlarm); + log.info("生成移位报警: 通道{}, 偏移信息: {}", preset.getChannelId(), map.get("description")); + // 向前端主动推送消息 + SocketMessage bean = new SocketMessage(); + Map data = new HashMap<>(); + data.put("title", "摄像头报警"); + data.put("content", "摄像头[" + preset.getCameraId() + "]发生移位,请及时处理!"); + bean.setData(JSON.toJSONString(data)); + bean.setChannel(SocketChannelEnum.MESSAGE); + bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT); + TransferMessage msg = new TransferMessage(); + msg.setMessage(bean); + msg.setFromUser("system"); + msg.setToPushAll(true); + websocketRedisService.sendServiceToWs(msg); + // 统一处理报警信息后,将摄像头信息+报警信息上报给别人服务器 + BoxAlarmReportDto reportDto = new BoxAlarmReportDto(); + reportDto.setAlarmReportTime(LocalDateTime.now()); + reportDto.setAlarmReportType(AlarmReportEnums.DISPLACEMENT_ALARM.getAlarmDescription()); + reportDto.setDescription("摄像头发生移位"); + byte[] BaseFileContent = Files.readAllBytes(Paths.get(imagePath)); + reportDto.setBaseImage(Base64.getEncoder().encodeToString(BaseFileContent)); + byte[] CaptureFileContent = Files.readAllBytes(Paths.get(image2)); + reportDto.setCaptureImage(Base64.getEncoder().encodeToString(CaptureFileContent)); + reportDto.setUrl(preset.getPresetUrl()); + reportDto.setCameraName(camera.getName()); + reportDto.setCameraId(camera.getId()); + reportDto.setCameraNo(camera.getCameraNo()); + forwardService.enrichAndForward(reportDto); + } + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/AiBoxRequestUtil.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/AiBoxRequestUtil.java new file mode 100644 index 0000000..0db41ce --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/AiBoxRequestUtil.java @@ -0,0 +1,303 @@ +package com.sz.admin.monitor.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.sz.admin.monitor.constant.MediaConstant; +import com.sz.admin.monitor.pojo.dto.edgebox.AlgorithmTaskDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.SetupChannelDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.exception.common.BusinessException; +import com.sz.core.util.JsonUtils; +import com.sz.platform.enums.AdminResponseEnum; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * ClassName: AiBoxRequestUtil + * Package: com.sz.admin.monitor.utils + * Description: + */ +@Component +@Slf4j +public class AiBoxRequestUtil { + @Value("${edgeBox.connectTimeout}") + private Long connectTimeout; + + @Value("${edgeBox.readTimeout}") + private Long readTimeout; + + @Value("${edgeBox.maxIdleConnections}") + private Integer maxIdleConnections; + + @Value("${edgeBox.keepAliveDuration}") + private Long keepAliveDuration; + private OkHttpClient client; + + // 回调操作 + public interface RequestCallback { + void run(JSONObject response); + } + + /** + * 获取OkHttpClient + * + * @return 返回客户端 + */ + private OkHttpClient getClient() { + if (Objects.isNull(client)) { + // 设置构造参数 + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); + // 设置连接超时时间 + httpClientBuilder.connectTimeout(connectTimeout, TimeUnit.SECONDS); + // 设置读取超时时间 + httpClientBuilder.readTimeout(readTimeout, TimeUnit.SECONDS); + // 设置连接池 + httpClientBuilder.connectionPool(new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MINUTES)); + client = httpClientBuilder.build(); + } + return client; + } + + /** + * 发送post请求 + * + * @param api 路径 + * @param param 参数 + * @return 请求结果 + */ + public AlgMediaConfigResponse sendPost(String ip, String port, String api, Map param) { + return sendPost(ip, port, api, param, null); + } + + /** + * 发送post请求 + * + * @param api 路径 + * @param param 参数 + * @param callback 回调 + * @return 请求结果 + */ + public AlgMediaConfigResponse sendPost(String ip, String port, String api, Map param, AiBoxRequestUtil.RequestCallback callback) { + OkHttpClient okHttpClient = getClient(); + String url = String.format(MediaConstant.HTTP_Edge_URL, ip, port, api); + log.info("请求的url:{}", url); + JSONObject responseJSON = new JSONObject(); + responseJSON.put("code", CommonResponseEnum.MEDIA_HTTP_FAIL.getCode()); + responseJSON.put("msg", CommonResponseEnum.MEDIA_HTTP_FAIL.getMessage()); + + MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8"); + String jsonString = ""; + if (param != null) { + jsonString = JSON.toJSONString(param); + } + log.info("请求体 JSON: {}", jsonString); + + RequestBody body = RequestBody.create(jsonString, JSON_TYPE); + // 构造 Request + Request request = new Request.Builder() + .url(url) + .post(body) + .build(); + // 判断是否有回调 + if (callback == null) { + try { + Response response = okHttpClient.newCall(request).execute(); + if (response.isSuccessful()) { + ResponseBody responseBody = response.body(); + if (responseBody != null) { + String responseStr = responseBody.string(); + responseJSON = JSON.parseObject(responseStr); + } else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + } + } catch (IOException e) { + log.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); + //读取超时超时异常 + if (e instanceof SocketTimeoutException) { + log.error(String.format("读取edgeBox数据超时失败: %s, %s", url, e.getMessage())); + } + //判断连接异常 + if (e instanceof ConnectException) { + log.error(String.format("连接edgeBox连接失败: %s, %s", url, e.getMessage())); + } + } + } else { + // 进入队列 + okHttpClient.newCall(request).enqueue(new Callback() { + // 监听成功 + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + if (response.isSuccessful()) { + try { + String responseStr = Objects.requireNonNull(response.body()).string(); + callback.run(JSON.parseObject(responseStr)); + } catch (IOException e) { + log.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); + } + + } else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + } + + // 监听失败 + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + log.error(String.format("连接edgeBox失败: %s, %s", call.request(), e.getMessage())); + + if (e instanceof SocketTimeoutException) { + //读取超时超时异常 + log.error(String.format("读取连接edgeBox失败数据失败: %s, %s", call.request(), e.getMessage())); + } + if (e instanceof ConnectException) { + //判断连接异常,我这里是报Failed to connect to 10.7.5.144 + log.error(String.format("连接连接edgeBox失败: %s, %s", call.request(), e.getMessage())); + } + } + }); + } + AlgMediaConfigResponse response = JsonUtils.parseObject(responseJSON.toJSONString(), AlgMediaConfigResponse.class); + if(response.getResult().getCode()!=0) + { + throw new BusinessException(AdminResponseEnum.OPERATION_FAIL,null, response.getResult().getDesc()); + } + return response; + } + +// ###################################请求方法########################################### + + /** + * 配置视频通道 + * + * @param setupChannelDTO 参数对象 + * @return 返回值 + */ + public AlgMediaConfigResponse setupVideoChannel(String ip, String port, SetupChannelDTO setupChannelDTO) { + Map map = new HashMap<>(); + map.put("MediaName", setupChannelDTO.getMediaName()); + map.put("MediaUrl", setupChannelDTO.getMediaUrl()); + map.put("GBTransport", false); + map.put("RtspTransport", false); + map.put("MediaDesc", setupChannelDTO.getMediaDesc()); + map.put("ProtocolType", 0); + return sendPost(ip, port, "/alg_media_config", map, null); + } + + /** + * 查询视频通道列表 + */ + public List getVideoChannelList(String ip, String port) { + AlgMediaConfigResponse response = sendPost(ip, port, "/alg_media_fetch", null, null); + return response.getContent(); + } + /** + * 删除视频通道 + * @param mediaName 通道名称 + * @return + */ + public AlgMediaConfigResponse deleteVideoChannel(String ip, String port, String mediaName) { + Map map = new HashMap<>(); + map.put("MediaName",mediaName); + return sendPost(ip, port, "/alg_media_delete", map, null); + } + + /** + * 配置任务 + */ + public AlgMediaConfigResponse setupTask(String ip, String port, AlgorithmTaskDTO algTaskConfigDto) { + Map map = new HashMap<>(); + map.put("AlgTaskSession", algTaskConfigDto.getAlgTaskSession()); + map.put("MediaName", algTaskConfigDto.getMediaName()); + map.put("TaskDesc", algTaskConfigDto.getTaskDesc()); + map.put("AlgInfo",algTaskConfigDto.getAlgInfo()); + // TODO 暂时写死 + map.put("MetadataUrl", "http://192.168.2.123:9991/api/admin/algorithm-task/alarm"); + map.put("Restart", true); + map.put("UserData", algTaskConfigDto.getUserData()); + return sendPost(ip, port, "/alg_task_config", map, null); + } + /** + * 控制设备视频任务 + * @param algTaskSession 会话编号 + * @param controlCommand 0 关闭 1开启 + * @return + */ + public AlgMediaConfigResponse controlTask(String ip, String port, String algTaskSession, int controlCommand) { + Map map = new HashMap<>(); + map.put("AlgTaskSession", algTaskSession); + map.put("ControlCommand", controlCommand); + return sendPost(ip, port, "/alg_task_control", map, null); + } + /** + * 删除设备视频任务 + */ + public AlgMediaConfigResponse deleteTask(String ip, String port, String algTaskSession) { + Map map = new HashMap<>(); + map.put("AlgTaskSession",algTaskSession); + return sendPost(ip, port, "/alg_task_delete", map, null); + } + /** + * 创建人脸库 + */ + public AlgMediaConfigResponse createFaceLibrary(String ip, String port, String name) { + Map map = new HashMap<>(); + map.put("albumName",name); + return sendPost(ip, port, "/api_repository_create", map, null); + } + /** + * 人脸库的删除 + */ + public AlgMediaConfigResponse deleteFaceLibrary(String ip, String port, String name) { + Map map = new HashMap<>(); + map.put("albumName",name); + return sendPost(ip, port, "/api_repository_delete", map, null); + } + /** + * 注册到人脸库 + */ + public AlgMediaConfigResponse registerFaceLibrary(String ip, String port, String albumName, String faceSign, String realName, String image) { + Map map = new HashMap<>(); + map.put("albumName",albumName); + map.put("name",faceSign); + map.put("realName",realName); + map.put("image",image); + return sendPost(ip, port, "/api_register_face", map, null); + } + /** + * 注册到人脸库 + */ + public AlgMediaConfigResponse registerFaceLibrary(String ip, String port, String albumName, String faceSign, String realName, String image, String featureName) { + Map map = new HashMap<>(); + map.put("albumName",albumName); + map.put("name",faceSign); + map.put("realName",realName); + map.put("image",image); + map.put("featureName",featureName); + return sendPost(ip, port, "/api_register_face", map, null); + } + /** + * 删除注册到人脸库的信息 + */ + public AlgMediaConfigResponse deleteFaceInfo(String ip, String port, String faceSign, String name) { + Map map = new HashMap<>(); + map.put("albumName",name); + map.put("photoName",faceSign); // 用户标识 + return sendPost(ip, port, "/api_face_delete", map, null); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/AlgMediaConfigResponse.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/AlgMediaConfigResponse.java new file mode 100644 index 0000000..62c3f31 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/AlgMediaConfigResponse.java @@ -0,0 +1,46 @@ +package com.sz.admin.monitor.utils; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class AlgMediaConfigResponse { + + @JsonProperty("BoardId") + private String boardId; + + @JsonProperty("BoardIp") + private String boardIp; + + @JsonProperty("Event") + private String event; + + private Integer albumId; + private String albumName; + + @JsonProperty("Result") + private ResultInfo result; + + @JsonProperty("Content") + private List content; + + @Data + public static class MediaStreamInfo { + @JsonProperty("MediaDesc") + private String mediaDesc; + @JsonProperty("MediaName") + private String mediaName; + @JsonProperty("MediaUrl") + private String mediaUrl; + } + + @Data + public static class ResultInfo { + @JsonProperty("Code") + private Integer code; + @JsonProperty("Desc") + private String desc; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/Hik3DptzChecker.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/Hik3DptzChecker.java new file mode 100644 index 0000000..fa49495 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/Hik3DptzChecker.java @@ -0,0 +1,60 @@ +package com.sz.admin.monitor.utils; + + +import com.sun.jna.Memory; +import com.sun.jna.Pointer; +import com.sun.jna.ptr.IntByReference; +import com.sz.admin.monitor.sdk.hkSdk.HCNetSDK; + +import java.nio.charset.Charset; + +/** + * @author zxsong + * @date 2026/11/31 + * 描述:检查摄像头是否支持3D PTZ + */ +public class Hik3DptzChecker { + + private static final int DEVICE_SOFTHARDWARE_ABILITY = 0x001; + + public static boolean isSupport3DPTZ(HCNetSDK sdk, int lUserID) { + int outSize = 64 * 1024; + Memory outBuf = new Memory(outSize); + outBuf.clear(); + + IntByReference pRetLen = new IntByReference(0); + + boolean ok = sdk.NET_DVR_GetDeviceAbility( + lUserID, + DEVICE_SOFTHARDWARE_ABILITY, + Pointer.NULL, + 0, + outBuf, + outSize + ); + + if (!ok) { + return false; + } + + int realLen = pRetLen.getValue(); + if (realLen <= 0) realLen = cStringLen(outBuf, outSize); + + byte[] bytes = outBuf.getByteArray(0, realLen); + + String xml = new String(bytes, Charset.forName("UTF-8")).trim(); + if (xml.isEmpty() || !xml.contains("Support3DPTZ")) { + xml = new String(bytes, Charset.forName("GBK")).trim(); + } + + return xml.contains("1") + || xml.contains("true"); + } + + private static int cStringLen(Memory mem, int max) { + for (int i = 0; i < max; i++) { + if (mem.getByte(i) == 0) return i; + } + return max; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/HikHdd.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/HikHdd.java new file mode 100644 index 0000000..d0fb601 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/HikHdd.java @@ -0,0 +1,168 @@ +package com.sz.admin.monitor.utils; + + +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.Credentials; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.apache.hc.core5.util.Timeout; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathFactory; +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +public class HikHdd { + + /** + * 仅 HTTP 版本:请求 /ISAPI/ContentMgmt/Storage/hdd,解析 XML,返回汇总信息。 + * @throws Exception 网络/认证/XML 解析失败时抛出 + */ + public static HddSummary fetchHddSummaryHttp(String ip, int port, String user, String pass) throws Exception { + String url = "http://" + ip + ":" + port + "/ISAPI/ContentMgmt/Storage/hdd"; + + HttpHost target = new HttpHost("http", ip, port); + Credentials creds = new UsernamePasswordCredentials(user, pass.toCharArray()); + + BasicCredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials(new AuthScope(target.getHostName(), target.getPort()), creds); + + var cm = PoolingHttpClientConnectionManagerBuilder.create().build(); + RequestConfig rc = RequestConfig.custom() + .setConnectionRequestTimeout(Timeout.ofSeconds(10)) + .setConnectTimeout(Timeout.ofSeconds(6)) + .setResponseTimeout(Timeout.ofSeconds(10)) + .build(); + + try (CloseableHttpClient client = HttpClients.custom() + .setDefaultCredentialsProvider(provider) // 401 后自动协商 Digest/Basic + .setConnectionManager(cm) + .setDefaultRequestConfig(rc) + .build()) { + + var get = new org.apache.hc.client5.http.classic.methods.HttpGet(URI.create(url)); + try (ClassicHttpResponse resp = client.executeOpen(null, get, null)) { + int code = resp.getCode(); + String body = EntityUtils.toString(resp.getEntity()); + if (code < 200 || code >= 300) { + throw new RuntimeException("HTTP " + code + " body: " + body); + } + return parseHddXml(body); + } + } + } + + private static HddSummary parseHddXml(String xml) throws Exception { + DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); + f.setNamespaceAware(true); + Document doc = f.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes())); + + XPath xp = XPathFactory.newInstance().newXPath(); + NodeList hdds = (NodeList) xp.evaluate("//*[local-name()='hdd']", doc, XPathConstants.NODESET); + + List list = new ArrayList<>(); + long totalMb = 0, freeMb = 0; + + for (int i = 0; i < hdds.getLength(); i++) { + var n = hdds.item(i); + String id = text(xp, "./*[local-name()='id']", n); + String status = text(xp, "./*[local-name()='status']", n); + String model = text(xp, "./*[local-name()='hddModel']", n); + + long capMb = parseLongSafe(text(xp, "./*[local-name()='capacity']", n)); // MB + long free = parseLongSafe(text(xp, "./*[local-name()='freeSpace']", n)); // MB + + totalMb += capMb; + freeMb += free; + + list.add(new Disk(id, status, model, capMb, free)); + } + + long usedMb = Math.max(0, totalMb - freeMb); + return new HddSummary(list, totalMb, freeMb, usedMb); + } + + private static String text(XPath xp, String expr, org.w3c.dom.Node ctx) throws Exception { + String s = (String) xp.evaluate(expr, ctx, XPathConstants.STRING); + return (s == null || s.isEmpty()) ? null : s.trim(); + } + + private static long parseLongSafe(String s) { + if (s == null || s.isEmpty()) return 0L; + try { return Long.parseLong(s.trim()); } catch (Exception e) { return 0L; } + } + + + public static class Disk { + public final String id; + public final String status; + public final String model; + public final long capacityMiB; + public final long freeMiB; + + public Disk(String id, String status, String model, long capacityMiB, long freeMiB) { + this.id = id; + this.status = status; + this.model = model; + this.capacityMiB = capacityMiB; + this.freeMiB = freeMiB; + } + + public double capacityGiB() { return capacityMiB / 1024.0; } + public double freeGiB() { return freeMiB / 1024.0; } + public double usedGiB() { return (capacityMiB - freeMiB) / 1024.0; } + } + + public static class HddSummary { + public final List disks; + public final long totalMiB; + public final long freeMiB; + public final long usedMiB; + + public final int diskCount; // 总硬盘数量 + public final int okCount; // status=ok 的数量 + + public HddSummary(List disks, long totalMiB, long freeMiB, long usedMiB) { + this.disks = disks; + this.totalMiB = totalMiB; + this.freeMiB = freeMiB; + this.usedMiB = usedMiB; + this.diskCount = disks.size(); + this.okCount = (int) disks.stream().filter(d -> "ok".equalsIgnoreCase(d.status)).count(); + } + + public double totalTiB() { return totalMiB / 1048576.0; } + public double freeTiB() { return freeMiB / 1048576.0; } + public double usedTiB() { return usedMiB / 1048576.0; } + + @Override public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("=== HDD Summary ===\n"); + for (Disk d : disks) { + sb.append(String.format( + "Disk[%s] status=%s model=%s total=%.2f GiB free=%.2f GiB used=%.2f GiB%n", + d.id, d.status, d.model == null ? "-" : d.model, + d.capacityGiB(), d.freeGiB(), d.usedGiB())); + } + sb.append(String.format( + "TOTAL: %.2f TiB, FREE: %.2f GiB, USED: %.2f GiB%n", totalTiB(), freeTiB(), usedTiB())); + sb.append(String.format( + "Disk count=%d, status=ok count=%d%n", + diskCount, okCount)); + return sb.toString(); + } + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ImageNameUtils.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ImageNameUtils.java new file mode 100644 index 0000000..883392c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ImageNameUtils.java @@ -0,0 +1,31 @@ +package com.sz.admin.monitor.utils; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +public class ImageNameUtils { + + private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"); + + /** + * 生成标准图片文件名 + * + * @param type 业务类型 (如: ALARM, CAPTURE) + * @param deviceId 设备ID + * @return 文件名 (不含路径) + */ + public static String generateFileName(String type, Long deviceId) { + String timeStr = LocalDateTime.now().format(TIME_FORMAT); + String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8); + return String.format("%s_%d_%s_%s.jpg", type, deviceId, timeStr, uuid); + } + public static String generateFileName(String type, String suffix) { + String timeStr = LocalDateTime.now().format(TIME_FORMAT); + String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8); + return String.format("%s_%s_%s%s", type, timeStr, uuid, suffix); + } + public static void main(String[] args) { + System.out.println(generateFileName("ALARM", 10086L)); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/OffsetCalculator.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/OffsetCalculator.java new file mode 100644 index 0000000..f87283a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/OffsetCalculator.java @@ -0,0 +1,176 @@ +package com.sz.admin.monitor.utils; + +import com.sz.admin.monitor.pojo.vo.offset.OffsetVO; +import com.sz.core.util.JsonUtils; +import org.bytedeco.javacpp.DoublePointer; +import org.bytedeco.javacpp.FloatPointer; +import org.bytedeco.opencv.opencv_core.*; +import org.bytedeco.opencv.opencv_features2d.BFMatcher; +import org.bytedeco.opencv.opencv_features2d.SIFT; + +import java.util.*; + +import static org.bytedeco.opencv.global.opencv_calib3d.RANSAC; +import static org.bytedeco.opencv.global.opencv_calib3d.findHomography; +import static org.bytedeco.opencv.global.opencv_core.CV_32FC2; +import static org.bytedeco.opencv.global.opencv_core.NORM_L2; +import static org.bytedeco.opencv.global.opencv_imgcodecs.imread; +import static org.bytedeco.opencv.global.opencv_imgproc.COLOR_BGR2GRAY; +import static org.bytedeco.opencv.global.opencv_imgproc.cvtColor; + +// 图片向量偏移对比工具类型 +public class OffsetCalculator { + + public static Map calculateOffset(String img1Path, String img2Path) { + Mat srcPts = null; + Mat dstPts = null; + Mat H = null; + Mat mask = null; + Mat img1 = null; + Mat img2 = null; + Mat gray1 = null; + Mat gray2 = null; + Mat des1 = null; + Mat des2 = null; + try { + // 加载图片 + img1 = imread(img1Path); + img2 = imread(img2Path); + + if (img1.empty() || img2.empty()) { + System.err.println("错误:无法加载图片"); + return null; + } + + // 转灰度图 + gray1 = new Mat(); + gray2 = new Mat(); + cvtColor(img1, gray1, COLOR_BGR2GRAY); + cvtColor(img2, gray2, COLOR_BGR2GRAY); + + // SIFT 特征检测 + SIFT sift = SIFT.create(); + // 记录图片1的每个特征点的坐标 + KeyPointVector kp1 = new KeyPointVector(); + // 记录图片2的每个特征点的坐标 + KeyPointVector kp2 = new KeyPointVector(); + // 存放图片1的描述特征点的容量 + des1 = new Mat(); + // 存放图片2的描述特征点的容量 + des2 = new Mat(); + // 查找灰度图1的特征点,并且找到每个特征点计算出描述保存到des容器中 + sift.detectAndCompute(gray1, new Mat(), kp1, des1); + // 查找灰度图2的特征点,并且找到每个特征点计算出描述保存到des容器中 + sift.detectAndCompute(gray2, new Mat(), kp2, des2); + + // 特征匹配 (KNN) + // 暴力匹配器,拿着图1中的特征点去图2中的每个特征点进行比较 + BFMatcher matcher = new BFMatcher(NORM_L2, false); + DMatchVectorVector matches = new DMatchVectorVector(); + // 对于图1的特征点,去图2中找1到2个最相似的特征点 + matcher.knnMatch(des1, des2, matches, 2); + + // 筛选 Good Matches + // 先把好的匹配暂存到一个 Java List 里,避免操作复杂的 Vector + List goodMatchList = new ArrayList<>(); + for (long i = 0; i < matches.size(); i++) { + DMatchVector currentMatch = matches.get(i); + if (currentMatch.size() < 2) continue; + // 最像的特征点 + DMatch m = currentMatch.get(0); + // 第2像的特征点 + DMatch n = currentMatch.get(1); + // 最像的特征点的距离,必须小于第2像的特征点距离的 75% + if (m.distance() < 0.75 * n.distance()) { + goodMatchList.add(m); + } + } + + // 检查数量 + int count = goodMatchList.size(); + if (count < 4) { + System.out.println("匹配点不足 (" + count + "),无法计算偏移"); + return null; + } + + // 准备纯 Java 数组 (大小 = 点数 * 2,因为有 x 和 y) + float[] srcData = new float[count * 2]; + float[] dstData = new float[count * 2]; + + // 在 Java 内存中填好数据 + for (int i = 0; i < count; i++) { + DMatch match = goodMatchList.get(i); + // 获取匹配对在图1中的坐标 + Point2f p1 = kp1.get(match.queryIdx()).pt(); + // 获取匹配对在图2中的坐标 + Point2f p2 = kp2.get(match.trainIdx()).pt(); + // 将二维数组转一维数组 + // 保存x坐标 + srcData[2 * i] = p1.x(); + // 保存y坐标 + srcData[2 * i + 1] = p1.y(); + // 保存x坐标 + dstData[2 * i] = p2.x(); + // 保存y坐标 + dstData[2 * i + 1] = p2.y(); + } + + // 创建一个矩阵对象,固定为1列,count行,每个点位存放32位的浮点数,每个点位存放两个数字 + srcPts = new Mat(count, 1, CV_32FC2); + dstPts = new Mat(count, 1, CV_32FC2); + + // 将Java内存中的数据保存到C++申请到的内存中 + new FloatPointer(srcPts.data()).put(srcData); + new FloatPointer(dstPts.data()).put(dstData); + + // 计算单应性矩阵 H + mask = new Mat(); + H = findHomography(srcPts, dstPts, RANSAC, 5.0, mask, 2000, 0.995); + + if (H.empty()) { + System.out.println("无法计算单应性矩阵"); + return null; + } + // 计算偏移的像素 + double[] hData = new double[9]; + // 把 C++中h矩阵的数据复制回 Java 数组 + new DoublePointer(H.data()).get(hData); + //水平方向的平移量 + double dx = hData[2]; // 第0行第2列 + // 垂直方向的平移量 + double dy = hData[5]; // 第1行第2列 + String dxStr = String.format("%.2f", dx); + String dyStr = String.format("%.2f", dy); + // 如果水平偏移量和垂直偏移量都小于10,那么就是没有没有问题 value=0 + // 如果其中有一个大于10,那么就是有问题 value=1 + int value = (Math.abs(dx) < 10 && Math.abs(dy) < 10) ? 0 : 1; + + Map resultItem = new HashMap<>(); + resultItem.put("type", "tx_yzwpy"); + resultItem.put("value", value); + resultItem.put("code", "2000"); + resultItem.put("location", new ArrayList<>()); + resultItem.put("confidence", 1); + OffsetVO offsetVO = new OffsetVO(); + offsetVO.setX(dxStr); + offsetVO.setY(dyStr); + offsetVO.setUnit("px"); + resultItem.put("description", JsonUtils.toJsonString(offsetVO)); + return resultItem; + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + // 显式释放 Native 内存 + srcPts.close(); + dstPts.close(); + H.close(); + mask.close(); + img1.close(); + img2.close(); + gray1.close(); + gray2.close(); + des1.close(); + des2.close(); + } + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/RobustImageMatcherUtil.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/RobustImageMatcherUtil.java new file mode 100644 index 0000000..88fb97d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/RobustImageMatcherUtil.java @@ -0,0 +1,424 @@ +package com.sz.admin.monitor.utils; + +import com.alibaba.fastjson.JSON; +import com.sz.admin.monitor.pojo.vo.offset.OffsetVO; +import com.sz.core.util.JsonUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.bytedeco.javacpp.*; +import org.bytedeco.javacpp.indexer.DoubleIndexer; +import org.bytedeco.javacpp.indexer.FloatIndexer; +import org.bytedeco.opencv.opencv_core.*; +import org.bytedeco.opencv.opencv_features2d.BFMatcher; +import org.bytedeco.opencv.opencv_features2d.ORB; +import org.bytedeco.opencv.opencv_imgproc.CLAHE; + +import java.io.File; +import java.util.*; +import java.util.Arrays; + +import static org.bytedeco.opencv.global.opencv_calib3d.RANSAC; +import static org.bytedeco.opencv.global.opencv_calib3d.estimateAffinePartial2D; +import static org.bytedeco.opencv.global.opencv_core.*; +import static org.bytedeco.opencv.global.opencv_imgcodecs.imread; +import static org.bytedeco.opencv.global.opencv_imgproc.*; +import static org.bytedeco.opencv.global.opencv_photo.fastNlMeansDenoising; +import static org.bytedeco.opencv.global.opencv_video.calcOpticalFlowFarneback; + +/** + * ClassName: RobustImageMatcherUtil + * Package: com.sz.admin.monitor.utils + * Description: 图片移位和检测工具类(生产环境优化版) + */ +@Slf4j +public class RobustImageMatcherUtil { + + public static class MatchResult { + public String method; + public boolean success = false; + public double offsetX = 0; + public double offsetY = 0; + public double confidence = 0; + + public MatchResult(String method) { + this.method = method; + } + } + + private static Mat[] preprocess(Mat img1, Mat img2) { + Mat gray1 = new Mat(); + Mat gray2 = new Mat(); + cvtColor(img1, gray1, COLOR_BGR2GRAY); + cvtColor(img2, gray2, COLOR_BGR2GRAY); + + if (gray1.cols() != gray2.cols() || gray1.rows() != gray2.rows()) { + Mat resizedGray2 = new Mat(); + resize(gray2, resizedGray2, new Size(gray1.cols(), gray1.rows())); + gray2 = resizedGray2; + } + + Mat denoised1 = new Mat(); + Mat denoised2 = new Mat(); + fastNlMeansDenoising(gray1, denoised1, 3.0f, 7, 21); + fastNlMeansDenoising(gray2, denoised2, 3.0f, 7, 21); + + CLAHE clahe = createCLAHE(2.0, new Size(8, 8)); + Mat final1 = new Mat(); + Mat final2 = new Mat(); + clahe.apply(denoised1, final1); + clahe.apply(denoised2, final2); + + // 注意:无需手动 close,外层的 PointerScope 会在整个流程结束时自动且安全地回收所有对象 + return new Mat[]{final1, final2}; + } + + private static boolean isSameScene(Mat gray1, Mat gray2) { + Mat hist1 = new Mat(); + Mat hist2 = new Mat(); + + IntPointer channels = new IntPointer(1).put(0); + IntPointer histSize = new IntPointer(1).put(256); + FloatPointer ranges = new FloatPointer(2).put(0.0f, 256.0f); + PointerPointer histRanges = new PointerPointer<>(1).put(ranges); + + Mat mask = new Mat(); + + calcHist(gray1, 1, channels, mask, hist1, 1, histSize, histRanges, true, false); + calcHist(gray2, 1, channels, mask, hist2, 1, histSize, histRanges, true, false); + + normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, new Mat()); + normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, new Mat()); + + double distance = compareHist(hist1, hist2, HISTCMP_BHATTACHARYYA); + + return distance < 0.5; + } + + private static MatchResult calcOpticalFlow(Mat gray1, Mat gray2) { + MatchResult result = new MatchResult("optical_flow"); + Mat flow = new Mat(); + calcOpticalFlowFarneback(gray1, gray2, flow, 0.5, 3, 15, 3, 5, 1.2, 0); + + FloatIndexer flowIdx = flow.createIndexer(); + try { + List dxList = new ArrayList<>(); + List dyList = new ArrayList<>(); + + for (int y = 0; y < flow.rows(); y += 2) { + for (int x = 0; x < flow.cols(); x += 2) { + double dx = flowIdx.get(y, x, 0); + double dy = flowIdx.get(y, x, 1); + if (Math.abs(dx) < 100 && Math.abs(dy) < 100) { + dxList.add(dx); + dyList.add(dy); + } + } + } + + if (dxList.size() < 100) return result; + + double stdDevX = calculateStdDev(dxList); + double stdDevY = calculateStdDev(dyList); + double avgStdDev = (stdDevX + stdDevY) / 2.0; + + Collections.sort(dxList); + Collections.sort(dyList); + result.offsetX = dxList.get(dxList.size() / 2); + result.offsetY = dyList.get(dyList.size() / 2); + + if (avgStdDev > 3.0) { + return result; + } + + result.success = true; + result.confidence = Math.max(0.1, 1.0 - (avgStdDev / 3.0)); + + } finally { + // Indexer 比较特殊,建议手动 release 释放视图映射 + flowIdx.release(); + } + return result; + } + + private static double calculateStdDev(List list) { + if (list.isEmpty()) return 0.0; + double sum = 0.0, sqSum = 0.0; + for (double num : list) { + sum += num; + } + double mean = sum / list.size(); + for (double num : list) { + sqSum += Math.pow(num - mean, 2); + } + return Math.sqrt(sqSum / list.size()); + } + + private static MatchResult gridMotionStatistics(Mat gray1, Mat gray2) { + MatchResult result = new MatchResult("grid_matching"); + int h = gray1.rows(); + int w = gray1.cols(); + int cellH = h / 10; + int cellW = w / 10; + + List dxList = new ArrayList<>(); + List dyList = new ArrayList<>(); + double totalScore = 0; + + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + int y1 = i * cellH, x1 = j * cellW; + int y2 = Math.min((i + 1) * cellH, h); + int x2 = Math.min((j + 1) * cellW, w); + + int margin = 5; + Rect roi1 = new Rect(Math.max(0, x1 - margin), Math.max(0, y1 - margin), + Math.min(w - x1 + margin, x2 - x1 + 2 * margin), + Math.min(h - y1 + margin, y2 - y1 + 2 * margin)); + + int searchRange = 30; + Rect roi2 = new Rect(Math.max(0, x1 - searchRange), Math.max(0, y1 - searchRange), + Math.min(w - x1 + searchRange, x2 - x1 + 2 * searchRange), + Math.min(h - y1 + searchRange, y2 - y1 + 2 * searchRange)); + + if (roi1.width() <= 0 || roi1.height() <= 0 || roi2.width() <= roi1.width() || roi2.height() <= roi1.height()) { + continue; + } + + Mat template = new Mat(gray1, roi1); + Mat searchArea = new Mat(gray2, roi2); + Mat matchRes = new Mat(); + + matchTemplate(searchArea, template, matchRes, TM_CCOEFF_NORMED); + + DoublePointer minVal = new DoublePointer(1); + DoublePointer maxVal = new DoublePointer(1); + Point minLoc = new Point(); + Point maxLoc = new Point(); + + minMaxLoc(matchRes, minVal, maxVal, minLoc, maxLoc, null); + + if (maxVal.get() > 0.6) { + dxList.add((double) ((roi2.x() + maxLoc.x()) - roi1.x())); + dyList.add((double) ((roi2.y() + maxLoc.y()) - roi1.y())); + totalScore += maxVal.get(); + } + } + } + + if (dxList.size() > 5) { + double stdDevX = calculateStdDev(dxList); + double stdDevY = calculateStdDev(dyList); + double avgStdDev = (stdDevX + stdDevY) / 2.0; + + if (avgStdDev < 5.0) { + Collections.sort(dxList); + Collections.sort(dyList); + result.success = true; + result.offsetX = dxList.get(dxList.size() / 2); + result.offsetY = dyList.get(dyList.size() / 2); + + double avgScore = totalScore / dxList.size(); + result.confidence = avgScore * Math.max(0.1, 1.0 - (avgStdDev / 5.0)); + } + } + return result; + } + + private static MatchResult robustFeatureMatch(Mat gray1, Mat gray2) { + MatchResult result = new MatchResult("feature_matching"); + ORB orb = ORB.create(5000, 1.2f, 8, 31, 0, 2, ORB.HARRIS_SCORE, 31, 20); + + KeyPointVector kp1 = new KeyPointVector(); + KeyPointVector kp2 = new KeyPointVector(); + Mat desc1 = new Mat(); + Mat desc2 = new Mat(); + + orb.detectAndCompute(gray1, new Mat(), kp1, desc1, false); + orb.detectAndCompute(gray2, new Mat(), kp2, desc2, false); + + if (kp1.size() < 10 || kp2.size() < 10 || desc1.empty() || desc2.empty()) { + return result; + } + + BFMatcher matcher = new BFMatcher(NORM_HAMMING, true); + DMatchVector matches = new DMatchVector(); + matcher.match(desc1, desc2, matches); + + long numMatches = matches.size(); + if (numMatches < 10) return result; + + Mat srcPts = new Mat((int)numMatches, 1, CV_32FC2); + Mat dstPts = new Mat((int)numMatches, 1, CV_32FC2); + FloatIndexer srcIdx = srcPts.createIndexer(); + FloatIndexer dstIdx = dstPts.createIndexer(); + + try { + for (int i = 0; i < numMatches; i++) { + Point2f p1 = kp1.get(matches.get(i).queryIdx()).pt(); + Point2f p2 = kp2.get(matches.get(i).trainIdx()).pt(); + srcIdx.put(i, 0, 0, p1.x()); + srcIdx.put(i, 0, 1, p1.y()); + dstIdx.put(i, 0, 0, p2.x()); + dstIdx.put(i, 0, 1, p2.y()); + } + } finally { + srcIdx.release(); + dstIdx.release(); + } + + Mat inliers = new Mat(); + Mat affine = estimateAffinePartial2D(srcPts, dstPts, inliers, RANSAC, 5.0, 2000, 0.99, 10); + + if (!affine.empty()) { + DoubleIndexer affIdx = affine.createIndexer(); + try { + result.offsetX = affIdx.get(0, 2); + result.offsetY = affIdx.get(1, 2); + + int inlierCount = countNonZero(inliers); + double ratio = (double) inlierCount / numMatches; + + if (ratio > 0.3) { + result.success = true; + result.confidence = ratio; + } + } finally { + affIdx.release(); + } + } + + return result; + } + + private static MatchResult consistencyCheck(List results) { + List valids = new ArrayList<>(); + for (MatchResult r : results) { + if (r.success) valids.add(r); + } + + if (valids.isEmpty()) return new MatchResult("none"); + if (valids.size() == 1) return valids.get(0); + + MatchResult finalRes = new MatchResult("fusion"); + double sumX = 0, sumY = 0, sumConf = 0; + List methods = new ArrayList<>(); + + for (MatchResult r : valids) { + sumX += r.offsetX * r.confidence; + sumY += r.offsetY * r.confidence; + sumConf += r.confidence; + methods.add(r.method); + } + + finalRes.success = true; + finalRes.offsetX = sumX / sumConf; + finalRes.offsetY = sumY / sumConf; + finalRes.method = String.join("+", methods); + finalRes.confidence = Math.min(1.0, (sumConf / valids.size()) * 1.1); + return finalRes; + } + + private static Map formatResult(MatchResult result, Mat img1, Mat img2) { + Map map = new LinkedHashMap<>(); + map.put("type", "tx_yzwpy"); + + if (!result.success || result.confidence < 0.2) { + log.warn("图像配准失败或置信度过低"); + map.put("value", 1); + map.put("code", "4000"); + OffsetVO offsetVO = new OffsetVO(); + offsetVO.setDescription("图像存在偏移"); + map.put("description", JsonUtils.toJsonString(offsetVO)); + return map; + } + + double dx = result.offsetX * 2; + double dy = result.offsetY * 2; + + int status = (Math.abs(dx) < 5 && Math.abs(dy) < 5 && result.confidence > 0.5) ? 0 : 1; + + map.put("value", status); + // 注:原代码此处为 status >= 0,由于 status 只能是 0 或 1,此处必定为 "2000",这里保持原逻辑。 + map.put("code", status >= 0 ? "2000" : "4000"); + map.put("pos", Arrays.asList((int) Math.round(dx), (int) Math.round(dy))); + map.put("conf", Double.parseDouble(String.format("%.3f", result.confidence))); + String dxStr = String.format("%.2f", dx); + String dyStr = String.format("%.2f", dy); + OffsetVO offsetVO = new OffsetVO(); + offsetVO.setX(dxStr); + offsetVO.setY(dyStr); + offsetVO.setDescription(status == 0 ? "图像基本一致" : "图像存在偏移"); + offsetVO.setUnit("px"); + map.put("description", JsonUtils.toJsonString(offsetVO)); + return map; + } + + /** + * 计算两张图像的偏移量 (生产环境安全入口) + */ + public static Map calculateOffset(String path1, String path2) { + if (StringUtils.isBlank(path1) || StringUtils.isBlank(path2)) { + throw new RuntimeException("图像路径不能为空"); + } + + File file1 = new File(path1); + File file2 = new File(path2); + if (!file1.exists() || !file2.exists()) { + log.error("图像文件不存在: path1={}, path2={}", path1, path2); + throw new RuntimeException("参与对比的图像文件不存在"); + } + + // 核心改造:使用 PointerScope 包裹整个处理流程 + // 任何在这个 try 块内创建的 JavaCPP 对象(Mat, Pointer等),都会在退出大括号时自动释放底层 C++ 内存。 + try (PointerScope scope = new PointerScope()) { + + Mat img1 = imread(path1); + Mat img2 = imread(path2); + + if (img1.empty() || img2.empty()) { + log.error("无法加载图片内容: path1={}, path2={}", path1, path2); + throw new RuntimeException("无法加载图片内容,文件可能已损坏"); + } + + Mat smallImg1 = new Mat(); + Mat smallImg2 = new Mat(); + resize(img1, smallImg1, new Size(), 0.5, 0.5, INTER_LINEAR); + resize(img2, smallImg2, new Size(), 0.5, 0.5, INTER_LINEAR); + + Mat[] preprocessed = preprocess(smallImg1, smallImg2); + Mat gray1 = preprocessed[0]; + Mat gray2 = preprocessed[1]; + + if (!isSameScene(gray1, gray2)) { + log.warn("图像差异过大,非同一场景: path1={}, path2={}", path1, path2); + return null; + } + + MatchResult flowResult = calcOpticalFlow(gray1, gray2); + MatchResult gridResult = gridMotionStatistics(gray1, gray2); + MatchResult featureResult = robustFeatureMatch(gray1, gray2); + + MatchResult finalResult = consistencyCheck(Arrays.asList(flowResult, gridResult, featureResult)); + + return formatResult(finalResult, img1, img2); + + } catch (Exception e) { + log.error("计算图像偏移量时发生异常: ", e); + throw new RuntimeException("图像偏移计算失败: " + e.getMessage()); + } + } + + public static void main(String[] args) { + // 图片完全不同 value 1 +// String img1Path = "D:\\work\\images\\CAPTURE_118_20260306140433490_7c323ce1.jpg"; +// String img2Path = "D:\\work\\images\\CAPTURE_118_20260306140650426_556115aa.jpg"; + // 相同的图片 value 0 +// String img1Path = "D:\\work\\images\\CAPTURE_118_20260306140433490_7c323ce1.jpg"; +// String img2Path = "D:\\work\\images\\CAPTURE_118_20260306140555121_0a31347e.jpg"; + // 出现移位的图片 value 1 + String img1Path="D:\\work\\images\\CAPTURE_118_20260306140328178_7f050439.jpg"; + String img2Path="D:\\work\\images\\CAPTURE_118_20260306140433490_7c323ce1.jpg"; + Map map = RobustImageMatcherUtil.calculateOffset(img1Path, img2Path); + System.out.println(map); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/RtspUtil.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/RtspUtil.java new file mode 100644 index 0000000..3e618b2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/RtspUtil.java @@ -0,0 +1,83 @@ +package com.sz.admin.monitor.utils; + + + + +import com.sz.admin.monitor.enums.DriverEnums; + +import java.util.HashMap; +import java.util.Map; + +public class RtspUtil { + + + /** + * 获取rtsp地址 + * + * @param device 驱动类型 海康 大华 + * @param username 用户名 + * @param password 密码 + * @param ip ip地址 + * @param channelNumber 通道号 + * @return rtsp地址 + */ + public static Map getRtsp(Integer driver, String username, String password, String ip, int channelNumber) { + Map map = new HashMap<>(); + if (DriverEnums.HKSDK.ordinal() == driver) { + String rtsp = "rtsp://#{username}:#{password}@#{ip}:554/ch#{channelNumber}/#{mode}/av_stream"; + rtsp = rtsp.replace("#{username}", username).replace("#{password}", password).replace("#{ip}", ip).replace("#{channelNumber}", String.valueOf(channelNumber)); + String mainRtsp = rtsp.replace("#{mode}", "main"); // 主码流 + String subRtsp = rtsp.replace("#{mode}", "sub"); // 子码流 + map.put("mainRtsp", mainRtsp); + map.put("subRtsp", subRtsp); + return map; + } + // 大华的rtsp流拼接 + else if (DriverEnums.DHSDK.ordinal() == driver) { + String rtsp = "rtsp://#{username}:#{password}@#{ip}:554/cam/realmonitor?channel=#{channelNumber}&subtype" + + "=#{mode}"; + rtsp = rtsp.replace("#{username}", username).replace("#{password}", password).replace("#{ip}", ip).replace("#{channelNumber}", String.valueOf(channelNumber)); + String mainRtsp = rtsp.replace("#{mode}", "0"); // 主码流 + String subRtsp = rtsp.replace("#{mode}", "1"); // 子码流 + map.put("mainRtsp", mainRtsp); + map.put("subRtsp", subRtsp); + return map; + } + return null; + } + + public static Map getRtsp(Integer driver, String username, String password, Integer channelNumber, String ip, Integer port) { + Map urlMap = new HashMap<>(); + if (DriverEnums.HKSDK.ordinal() == driver) { + String rtsp = "rtsp://#{username}:#{password}@#{ip}:#{port}/Streaming/Channels/#{videoType}#{mode}"; + rtsp = rtsp + .replace("#{username}", username) + .replace("#{password}", password) + .replace("#{ip}", ip) + .replace("#{port}",String.valueOf(port)) + .replace("#{videoType}",String.valueOf(channelNumber)); + String mainRtsp = rtsp.replace("#{mode}", "01"); + String subRtsp = rtsp.replace("#{mode}", "02"); + urlMap.put("mainRtsp", mainRtsp); + urlMap.put("subRtsp", subRtsp); + return urlMap; + } else if (DriverEnums.DHSDK.ordinal() == driver) { + String rtsp = "rtsp://#{username}:#{password}@#{ip}:554/cam/realmonitor?channel=#{channelNumber}&subtype" + + "=#{mode}"; + rtsp = rtsp.replace("#{username}", username).replace("#{password}", password).replace("#{ip}", ip).replace("#{channelNumber}", String.valueOf(channelNumber)); + String mainRtsp = rtsp.replace("#{mode}", "0"); + String subRtsp = rtsp.replace("#{mode}", "1"); + urlMap.put("mainRtsp", mainRtsp); + urlMap.put("subRtsp", subRtsp); + return urlMap; + } + return null; + } + +// public static void main(String[] args) { +// Map admin = getRtsp(0, "admin", "bdz13579.", 1, "192.168.1.11", 554); +// System.out.println(admin); +// Map admin1 = getRtsp(0, "admin", "bdz13579.", 24, "192.168.2.221", 554); +// System.out.println(admin1); +// } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ThreeDPtz.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ThreeDPtz.java new file mode 100644 index 0000000..3d35d60 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ThreeDPtz.java @@ -0,0 +1,80 @@ +package com.sz.admin.monitor.utils; + +/** + * @author zxsong + */ +public class ThreeDPtz { + /* + * 该结构体中的坐标值与当前预览显示框的大小有关,现假设预览显示框为352*288,我们规定原点为预览显示框左上角的顶点,前四个参数计算方法如下: + * xTop=鼠标当前所选区域的起始点坐标的值*255/352; + * xBottom =鼠标当前所选区域的结束点坐标的值*255/352; + * yTop=鼠标当前所选区域的起始点坐标的值*255/288; + * yBottom=鼠标当前所选区域的结束点坐标的值*255/288; + * 缩小条件:×Top减去xBottom的值大于2。放大条件:xTop小于xBottom. + * + * desc: 屏幕左下角为坐标原点 + */ + private double xTop; + private double xBottom; + private double yTop; + private double yBottom; + private double bCounter; + private int realPlayWndWidth; + private int realPlayWndHeight; + + public double getxTop() { + return xTop; + } + + public void setxTop(double xTop) { + this.xTop = xTop; + } + + public double getxBottom() { + return xBottom; + } + + public void setxBottom(double xBottom) { + this.xBottom = xBottom; + } + + public double getyTop() { + return yTop; + } + + public void setyTop(double yTop) { + this.yTop = yTop; + } + + public double getyBottom() { + return yBottom; + } + + public void setyBottom(double yBottom) { + this.yBottom = yBottom; + } + + public double getbCounter() { + return bCounter; + } + + public void setbCounter(double bCounter) { + this.bCounter = bCounter; + } + + public int getRealPlayWndWidth() { + return realPlayWndWidth; + } + + public void setRealPlayWndWidth(int realPlayWndWidth) { + this.realPlayWndWidth = realPlayWndWidth; + } + + public int getRealPlayWndHeight() { + return realPlayWndHeight; + } + + public void setRealPlayWndHeight(int realPlayWndHeight) { + this.realPlayWndHeight = realPlayWndHeight; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/UrlConvert.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/UrlConvert.java new file mode 100644 index 0000000..8872072 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/UrlConvert.java @@ -0,0 +1,25 @@ +package com.sz.admin.monitor.utils; + +import java.io.File; + +/** + * ClassName: UrlConvert + * Package: com.sz.admin.monitor.utils + * Description: + */ +public class UrlConvert { + private static final String RESOURCE_PREFIX = "/save/"; + /** + * 将本地绝对路径转换为网络相对路径 + * @param localPath D:\work\sz-admin\images\test.jpg + * @return /save/test.jpg + */ + public static String convertToUrl(String localPath) { + if (localPath == null || localPath.isEmpty()) { + return null; + } + String fileName = new File(localPath).getName(); + // 2. 拼接映射前缀 + return RESOURCE_PREFIX + fileName; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/VcrlUserIdContainer.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/VcrlUserIdContainer.java new file mode 100644 index 0000000..abb2494 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/VcrlUserIdContainer.java @@ -0,0 +1,35 @@ +package com.sz.admin.monitor.utils; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * lUserId的容器 + * + * @Author zxsong + * @since 2023-11-02 9:16 + */ + +@Component +public class VcrlUserIdContainer { + private final ConcurrentHashMap dataMap = new ConcurrentHashMap<>(); + + public void addData(Integer key, Object object) { + dataMap.put(key, object); + } + + public Object getlUserId(Integer key) { + return dataMap.get(key); + } + public List> getAllEntries() { + return new ArrayList<>(dataMap.entrySet()); + } + public void removelUserId(Integer key) { + dataMap.remove(key); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ZLMediaKitUtils.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ZLMediaKitUtils.java new file mode 100644 index 0000000..dae5292 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/ZLMediaKitUtils.java @@ -0,0 +1,244 @@ +package com.sz.admin.monitor.utils; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.sz.admin.monitor.constant.MediaConstant; +import com.sz.core.common.enums.CommonResponseEnum; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +@Component +@Slf4j +public class ZLMediaKitUtils { + + @Value("${ZLMediaKit.ip}") + private String ip; + + @Value("${ZLMediaKit.port}") + private String port; + + @Value("${ZLMediaKit.secret}") + private String secret; + + @Value("${ZLMediaKit.connectTimeout}") + private Long connectTimeout; + + @Value("${ZLMediaKit.readTimeout}") + private Long readTimeout; + + @Value("${ZLMediaKit.maxIdleConnections}") + private Integer maxIdleConnections; + + @Value("${ZLMediaKit.keepAliveDuration}") + private Long keepAliveDuration; + + @Value("${ZLMediaKit.vhost}") + private String vhost; + + @Value("${ZLMediaKit.app}") + private String app; + + private OkHttpClient client; + + // 回调操作 + public interface RequestCallback { + void run(JSONObject response); + } + + /** + * 获取OkHttpClient + * + * @return 返回客户端 + */ + private OkHttpClient getClient() { + if (Objects.isNull(client)) { + // 设置构造参数 + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); + // 设置连接超时时间 + httpClientBuilder.connectTimeout(connectTimeout, TimeUnit.SECONDS); + // 设置读取超时时间 + httpClientBuilder.readTimeout(readTimeout, TimeUnit.SECONDS); + // 设置连接池 + httpClientBuilder.connectionPool(new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MINUTES)); + client = httpClientBuilder.build(); + } + return client; + } + + /** + * 发送post请求 + * + * @param api 路径 + * @param param 参数 + * @return 请求结果 + */ + public JSONObject sendPost(String api, Map param) { + return sendPost(api, param, null); + } + + /** + * 发送post请求 + * + * @param api 路径 + * @param param 参数 + * @param callback 回调 + * @return 请求结果 + */ + public JSONObject sendPost(String api, Map param, RequestCallback callback) { + OkHttpClient okHttpClient = getClient(); + String url = String.format(MediaConstant.HTTP_MEDIA_URL, ip, port, api); + JSONObject responseJSON = new JSONObject(); + responseJSON.put("code", CommonResponseEnum.MEDIA_HTTP_FAIL.getCode()); + responseJSON.put("msg", CommonResponseEnum.MEDIA_HTTP_FAIL.getMessage()); + + // 构造form表单 + FormBody.Builder builder = new FormBody.Builder(); + builder.add("secret", secret); + if (param != null && !param.keySet().isEmpty()) { + for (String key : param.keySet()) { + if (param.get(key) != null) { + builder.add(key, param.get(key).toString()); + } + } + } + + // 构造请求 + FormBody body = builder.build(); + Request request = new Request.Builder() + .post(body) + .url(url) + .build(); + + // 判断是否有回调 + if (callback == null) { + try { + Response response = okHttpClient.newCall(request).execute(); + if (response.isSuccessful()) { + ResponseBody responseBody = response.body(); + if (responseBody != null) { + String responseStr = responseBody.string(); + responseJSON = JSON.parseObject(responseStr); + } else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + } + } catch (IOException e) { + log.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); + //读取超时超时异常 + if (e instanceof SocketTimeoutException) { + log.error(String.format("读取ZLM数据超时失败: %s, %s", url, e.getMessage())); + } + //判断连接异常 + if (e instanceof ConnectException) { + log.error(String.format("连接ZLM连接失败: %s, %s", url, e.getMessage())); + } + } + } else { + // 进入队列 + okHttpClient.newCall(request).enqueue(new Callback() { + + // 监听成功 + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + if (response.isSuccessful()) { + try { + String responseStr = Objects.requireNonNull(response.body()).string(); + callback.run(JSON.parseObject(responseStr)); + } catch (IOException e) { + log.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); + } + + } else { + response.close(); + Objects.requireNonNull(response.body()).close(); + } + } + + // 监听失败 + @Override + public void onFailure(@NotNull Call call, @NotNull IOException e) { + log.error(String.format("连接ZLM失败: %s, %s", call.request(), e.getMessage())); + + if (e instanceof SocketTimeoutException) { + //读取超时超时异常 + log.error(String.format("读取ZLM数据失败: %s, %s", call.request(), e.getMessage())); + } + if (e instanceof ConnectException) { + //判断连接异常,我这里是报Failed to connect to 10.7.5.144 + log.error(String.format("连接ZLM失败: %s, %s", call.request(), e.getMessage())); + } + } + }); + } + + return responseJSON; + } + /*-------------------------------------------------以下为zlm的post请求列举----------------------------------------------------- */ + + /** + * /index/api/addStreamProxy + * + * @param stream 流ID(唯一标识) + * @param url 源流地址(需包含协议前缀) + * @return 请求结果(包含key等重要信息) + */ + public JSONObject addStreamProxy(String stream, String url) { + Map params = new HashMap<>(); + params.put("vhost", vhost); + params.put("app", app); + params.put("stream", stream); + params.put("url", url); + return sendPost("/addStreamProxy", params, null); + } + + /** + * /index/api/delStreamProxy + * + * @param key 代理流的唯一标识(由addStreamProxy返回) + * @return 包含操作状态的JSON对象 + */ + public JSONObject delStreamProxy(String key) { + Map params = new HashMap<>(); + params.put("key", key); + return sendPost("/delStreamProxy", params, null); + } + + /** + * /index/api/close_streams + * + * @param stream 流 id + * @return 包含操作状态的JSON对象 + */ + public JSONObject CloseStreamProxy(String stream) { + Map params = new HashMap<>(); + params.put("stream", stream); + params.put("vhost", vhost); + params.put("app", app); + params.put("force", true); + return sendPost("/close_streams", params, null); + } + /** + * + * @param stream 流id + * @return http访问地址 + */ + public String getPlayUrl(String stream) { + // http://192.168.2.128:8080/index/api/webrtc?app=live&stream=33&type=play + // 测试地址 + // return "http://192.168.2.128:8080/index/api/webrtc?app=live&stream=test&type=play"; + return String.format("http://%s:%s/index/api/webrtc?app=live&stream=%s&type=play", ip, port, stream); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/osSelect.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/osSelect.java new file mode 100644 index 0000000..5c4f89d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/monitor/utils/osSelect.java @@ -0,0 +1,17 @@ +package com.sz.admin.monitor.utils; + +/** + * @author jiangxin + * @create 2022-01-19-16:40 + */ +public class osSelect { + + public static boolean isLinux() { + return System.getProperty("os.name").toLowerCase().contains("linux"); + } + + public static boolean isWindows() { + return System.getProperty("os.name").toLowerCase().contains("windows"); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/CaptchaController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/CaptchaController.java new file mode 100644 index 0000000..47dfa91 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/CaptchaController.java @@ -0,0 +1,67 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.sz.admin.system.service.CaptchaService; +import com.sz.core.common.annotation.Debounce; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.SliderPuzzle; +import com.sz.core.common.entity.CheckPuzzle; +import com.sz.core.util.SysConfigUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +/** + * 验证码controller + * + * @author sz + * @since 2025/01/07 19:07 + * @version 1.0 + */ +@Tag(name = "验证码") +@RestController +@RequestMapping("/captcha") +@RequiredArgsConstructor +@Slf4j +public class CaptchaController { + + private final CaptchaService captchaService; + + @SaIgnore + @Debounce() + @GetMapping("status") + @Operation(summary = "验证码是否启用") + public ApiResult captchaStatus() { + String value = SysConfigUtils.getConfValue("sys.captcha.state"); + return ApiResult.success(Boolean.parseBoolean(value)); + } + + @SaIgnore + @Debounce() + @Operation(summary = "获取验证码") + @PostMapping(value = "/get") + public ApiResult getImageCode(HttpServletRequest request) { + return ApiResult.success(captchaService.getImageCode(request)); + } + + @SaIgnore + @Debounce() + @Operation(summary = "校验滑块拼图验证码") + @PostMapping(value = "/check") + public ApiResult captchaCheck(@RequestBody CheckPuzzle checkPuzzle) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + captchaService.checkImageCode(checkPuzzle); + return ApiResult.success(); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/CommonController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/CommonController.java new file mode 100644 index 0000000..ae78491 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/CommonController.java @@ -0,0 +1,79 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaIgnore; +import com.sz.admin.system.pojo.dto.common.ProxyDownloadDTO; +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.vo.common.ChallengeVO; +import com.sz.admin.system.pojo.vo.common.SelectorVO; +import com.sz.admin.system.service.CommonService; +import com.sz.core.common.annotation.Debounce; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; + +/** + * 通用controller + * + * @author sz + * @version 1.0 + * @since 2023/12/25 10:07 + */ +@Tag(name = "通用API") +@RestController +@RequestMapping("/common") +@RequiredArgsConstructor +@Slf4j +public class CommonController { + + private final CommonService commonService; + + @Operation(summary = "模板下载") + @GetMapping("/download/templates") + public void fileDownload(@RequestParam(value = "templateName", required = false) String templateName, + @RequestParam(value = "alias", required = false) String alias, HttpServletResponse response) { + try { + commonService.tempDownload(templateName, alias, response); + } catch (Exception e) { + log.error("模板下载文件下载失败", e); + } + } + + @Operation(summary = "多维选择器查询") + @GetMapping("/selector") + public ApiResult querySelector(SelectorQueryDTO dto) { + return ApiResult.success(commonService.querySelector(dto)); + } + + @SaIgnore + @Debounce + @GetMapping("/auth/challenge") + @Operation(summary = "一次性认证参数,用于登录密码加密传输场景") + public ApiResult challenge() { + return ApiResult.success(commonService.challenge()); + } + + @SaCheckLogin + @GetMapping("oss/objects/private-url") + @Operation(summary = "获取OSS私有文件访问URL") + public ApiResult getOssPrivateUrl( + @Parameter(description = "OSS Bucket 名称,若不传则使用系统默认 Bucket", required = false, example = "my-bucket") @RequestParam(value = "bucket", required = false) String bucket, + @Parameter(description = "存储在 OSS 中的原始对象地址(可为完整 URL 或 objectKey 对应的 URL)", required = true, example = "https://oss-example.com/my-bucket/path/to/file.png") @RequestParam("url") String url) { + return ApiResult.success(commonService.ossPrivateUrl(bucket, url)); + } + + @SaCheckLogin + @Operation(summary = "文件下载") + @PostMapping("/files/download") + public void proxyDownload(@RequestBody ProxyDownloadDTO dto, HttpServletResponse response) throws IOException { + commonService.urlDownload(dto.getUrl(), response); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/ProductController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/ProductController.java new file mode 100644 index 0000000..23cb00e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/ProductController.java @@ -0,0 +1,94 @@ +package com.sz.admin.system.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import lombok.RequiredArgsConstructor; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.admin.system.service.ProductService; +import com.sz.admin.system.pojo.dto.ProductCreateDTO; +import com.sz.admin.system.pojo.dto.ProductUpdateDTO; +import com.sz.admin.system.pojo.dto.ProductListDTO; +import com.sz.admin.system.pojo.vo.ProductVO; +import com.sz.core.common.entity.ImportExcelDTO; +import jakarta.servlet.http.HttpServletResponse; + +/** + *

+ * 商品信息表 Controller + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Tag(name = "商品信息表") +@RestController +@RequestMapping("sys-product") +@RequiredArgsConstructor +public class ProductController { + + private final ProductService productService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "sys.product.create") + @PostMapping + public ApiResult create(@RequestBody ProductCreateDTO dto) { + productService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "sys.product.update") + @PutMapping + public ApiResult update(@RequestBody ProductUpdateDTO dto) { + productService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "sys.product.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + productService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.product.query_table") + @GetMapping + public ApiResult> list(ProductListDTO dto) { + return ApiPageResult.success(productService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.product.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(productService.detail(id)); + } + + @Operation(summary = "导入") + @Parameters({ + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true), + }) + @SaCheckPermission(value = "sys.product.import") + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + productService.importExcel(dto); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "sys.product.export") + @PostMapping("/export") + public void exportExcel(@RequestBody ProductListDTO dto, HttpServletResponse response) { + productService.exportExcel(dto, response); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysClientController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysClientController.java new file mode 100644 index 0000000..b69ea3b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysClientController.java @@ -0,0 +1,74 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.system.pojo.dto.sysclient.SysClientCreateDTO; +import com.sz.admin.system.pojo.dto.sysclient.SysClientListDTO; +import com.sz.admin.system.pojo.dto.sysclient.SysClientUpdateDTO; +import com.sz.admin.system.pojo.vo.sysclient.SysClientVO; +import com.sz.admin.system.service.SysClientService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.security.pojo.ClientVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 系统授权表 Controller + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Tag(name = "系统授权表") +@RestController +@RequestMapping("sys-client") +@RequiredArgsConstructor +public class SysClientController { + + private final SysClientService sysClientService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "sys.client.create", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@RequestBody SysClientCreateDTO dto) { + sysClientService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "sys.client.update", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@RequestBody SysClientUpdateDTO dto) { + sysClientService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "sys.client.remove", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysClientService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.client.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(SysClientListDTO dto) { + return ApiPageResult.success(sysClientService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.client.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(sysClientService.detail(id)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysConfigController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysConfigController.java new file mode 100644 index 0000000..6f0b040 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysConfigController.java @@ -0,0 +1,81 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigCreateDTO; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigListDTO; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigUpdateDTO; +import com.sz.admin.system.pojo.po.SysConfig; +import com.sz.admin.system.service.SysConfigService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + *

+ * 参数配置表 前端控制器 + *

+ * + * @author sz + * @since 2023-11-23 + */ +@Tag(name = "参数配置") +@RestController +@RequestMapping("/sys-config") +@RequiredArgsConstructor +public class SysConfigController { + + private final SysConfigService sysConfigService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "sys.config.add_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@RequestBody SysConfigCreateDTO dto) { + sysConfigService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "sys.config.update_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@RequestBody SysConfigUpdateDTO dto) { + sysConfigService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "sys.config.delete_btn", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysConfigService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.config.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(SysConfigListDTO dto) { + return ApiPageResult.success(sysConfigService.list(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.config.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(sysConfigService.detail(id)); + } + + @Operation(summary = "前端获取参数列表") + @GetMapping("/frontend-configs") + public ApiResult> listFrontendConfigs() { + return ApiResult.success(sysConfigService.getConfigVO()); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDataRoleController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDataRoleController.java new file mode 100644 index 0000000..0796c51 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDataRoleController.java @@ -0,0 +1,88 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleCreateDTO; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleListDTO; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleUpdateDTO; +import com.sz.admin.system.pojo.vo.sysdatarole.SysDataRoleMenuVO; +import com.sz.admin.system.pojo.vo.sysdatarole.SysDataRoleVO; +import com.sz.admin.system.service.SysDataRoleService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 数据权限管理 Controller + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Tag(name = "数据权限管理") +@RestController +@RequestMapping("sys-data-role") +@RequiredArgsConstructor +@Deprecated(since = "v1.4.0-beta") +public class SysDataRoleController { + + private final SysDataRoleService sysDataRoleService; + + @Deprecated(since = "v1.4.0-beta") + @Operation(summary = "新增") + @SaCheckPermission(value = "sys.data.role.create", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@RequestBody SysDataRoleCreateDTO dto) { + sysDataRoleService.create(dto); + return ApiResult.success(); + } + + @Deprecated(since = "v1.4.0-beta") + @Operation(summary = "修改") + @SaCheckPermission(value = "sys.data.role.update", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@RequestBody SysDataRoleUpdateDTO dto) { + sysDataRoleService.update(dto); + return ApiResult.success(); + } + + @Deprecated(since = "v1.4.0-beta") + @Operation(summary = "删除") + @SaCheckPermission(value = "sys.data.role.remove", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysDataRoleService.remove(dto); + return ApiResult.success(); + } + + @Deprecated(since = "v1.4.0-beta") + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.data.role.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(SysDataRoleListDTO dto) { + return ApiPageResult.success(sysDataRoleService.page(dto)); + } + + @Deprecated(since = "v1.4.0-beta") + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.data.role.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(sysDataRoleService.detail(id)); + } + + @Deprecated(since = "v1.4.0-beta") + @Operation(summary = "数据权限角色菜单信息查询") + @SaCheckPermission(value = "sys.data.role.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("/menu") + public ApiResult findRoleMenuByRoleId() { + return ApiResult.success(sysDataRoleService.queryDataRoleMenu()); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDeptController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDeptController.java new file mode 100644 index 0000000..58f3a45 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDeptController.java @@ -0,0 +1,108 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptCreateDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptListDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptRoleDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptUpdateDTO; +import com.sz.admin.system.pojo.vo.sysdept.DeptTreeVO; +import com.sz.admin.system.pojo.vo.sysdept.SysDeptLeaderVO; +import com.sz.admin.system.pojo.vo.sysdept.SysDeptRoleVO; +import com.sz.admin.system.pojo.vo.sysdept.SysDeptVO; +import com.sz.admin.system.service.SysDeptService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 部门表 Controller + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Tag(name = "部门表") +@RestController +@RequestMapping("sys-dept") +@RequiredArgsConstructor +public class SysDeptController { + + private final SysDeptService sysDeptService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "sys.dept.create", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@RequestBody SysDeptCreateDTO dto) { + sysDeptService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "sys.dept.update", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@RequestBody SysDeptUpdateDTO dto) { + sysDeptService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "sys.dept.remove", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysDeptService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.dept.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(SysDeptListDTO dto) { + return ApiResult.success(sysDeptService.list(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.dept.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(sysDeptService.detail(id)); + } + + @Operation(summary = "树形列表") + @GetMapping("/tree") + public ApiResult> tree(@Parameter(description = "需要排除的节点ID") @RequestParam(required = false) Integer excludeNodeId, + @Parameter(description = "是否添加根节点") @RequestParam(required = false) Boolean appendRoot) { + return ApiResult.success(sysDeptService.getDeptTree(excludeNodeId, appendRoot, false)); + } + + @Operation(summary = "负责人穿梭框-全部用户") + @GetMapping("/leader") + public ApiResult leader() { + return ApiResult.success(sysDeptService.findSysUserDeptLeader()); + } + + @Operation(summary = "部门角色信息查询-(穿梭框)") + @SaCheckPermission(value = "sys.dept.role_set_btn", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("role") + public ApiResult findDeptRole(@NotZero @RequestParam Long deptId) { + return ApiResult.success(sysDeptService.findSysDeptRole(deptId)); + } + + @Operation(summary = "部门角色信息修改 -(穿梭框)") + @SaCheckPermission(value = "sys.dept.role_set_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping("role") + public ApiResult changeDeptRole(@Valid @RequestBody SysDeptRoleDTO dto) { + sysDeptService.changeSysDeptRole(dto); + return ApiResult.success(); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDictController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDictController.java new file mode 100644 index 0000000..67ae3f8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDictController.java @@ -0,0 +1,95 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.system.pojo.dto.sysdict.SysDictCreateDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictListDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictUpdateDTO; +import com.sz.admin.system.pojo.po.SysDict; +import com.sz.admin.system.service.SysDictService; +import com.sz.core.common.annotation.DebounceIgnore; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + *

+ * 字典表 前端控制器 + *

+ * + * @author sz + * @since 2023-08-18 + */ +@Tag(name = "字典管理") +@RestController +@RequestMapping("/sys-dict") +@RequiredArgsConstructor +public class SysDictController { + + private final SysDictService sysDictService; + + @Operation(summary = "字典新增") + @SaCheckPermission(value = "sys.dict.add_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@Valid @RequestBody SysDictCreateDTO dto) { + sysDictService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "字典修改") + @SaCheckPermission(value = "sys.dict.update_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@Valid @RequestBody SysDictUpdateDTO dto) { + sysDictService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "批量删除") + @SaCheckPermission(value = "sys.dict.delete_btn", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysDictService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.dict.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(@Valid SysDictListDTO dto) { + return ApiPageResult.success(sysDictService.list(dto)); + } + + @DebounceIgnore + @Operation(summary = "系统字典查询-全部") + @GetMapping("dict") + public ApiResult>> listDict() { + return ApiResult.success(sysDictService.dictAll()); + } + + @Operation(summary = "指定类型系统字典查询") + @GetMapping("dict/{typeCode}") + public ApiResult> getDictDataByType(@PathVariable String typeCode) { + return ApiResult.success(sysDictService.getDictByType(typeCode)); + } + + @Operation(summary = "导出sql") + @SaCheckPermission(value = "sys.dict.sql_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping("sql/export") + public ApiResult exportDictSql(@RequestBody SelectIdsDTO dto) { + return ApiResult.success(sysDictService.exportDictSql(dto)); + } + + @DebounceIgnore + @Operation(summary = "系统字典查询-根据类型查询") + @GetMapping("code") + public ApiResult>> listDictByCode(@RequestParam("typeCode") List typeCodes) { + return ApiResult.success(sysDictService.getDictByCode(typeCodes)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDictTypeController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDictTypeController.java new file mode 100644 index 0000000..89ea22f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysDictTypeController.java @@ -0,0 +1,82 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeAddDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeListDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeUpDTO; +import com.sz.admin.system.pojo.po.SysDictType; +import com.sz.core.common.dict.DictTypeVO; +import com.sz.admin.system.service.SysDictTypeService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 字典类型 前端控制器 + *

+ * + * @author sz + * @since 2023-08-18 + */ +@Tag(name = "字典类型管理") +@RestController +@RequestMapping("/sys-dict-type") +@RequiredArgsConstructor +public class SysDictTypeController { + + private final SysDictTypeService sysDictTypeService; + + @Operation(summary = "字典类型新增") + @SaCheckPermission(value = "sys.dict.add_type_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@Valid @RequestBody SysDictTypeAddDTO dto) { + sysDictTypeService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "字典类型修改") + @SaCheckPermission(value = "sys.dict.update_type_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@Valid @RequestBody SysDictTypeUpDTO dto) { + sysDictTypeService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除、批量删除") + @SaCheckPermission(value = "sys.dict.delete_type_btn", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult disable(@RequestBody SelectIdsDTO dto) { + sysDictTypeService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "字段类型详情查询") + @GetMapping("{id}") + public ApiResult detail(@PathVariable Long id) { + return ApiResult.success(sysDictTypeService.detail(id)); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.dict.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(SysDictTypeListDTO dto) { + return ApiPageResult.success(sysDictTypeService.list(dto)); + } + + @Operation(summary = "下拉字典类型查询") + @GetMapping("selectOptionsType") + public ApiResult> selectOptionType() { + return ApiResult.success(sysDictTypeService.selectDictTypeOptions()); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysFileController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysFileController.java new file mode 100644 index 0000000..4bde041 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysFileController.java @@ -0,0 +1,85 @@ +package com.sz.admin.system.controller; + +import com.sz.admin.system.pojo.dto.sysfile.SysFileListDTO; +import com.sz.admin.system.pojo.po.SysFile; +import com.sz.admin.system.service.SysFileService; +import com.sz.core.common.annotation.DebounceIgnore; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + *

+ * 公共文件 前端控制器 + *

+ * + * @author sz + * @since 2023-08-31 + */ +@Tag(name = "系统公共文件管理") +@RequiredArgsConstructor +@RestController +@RequestMapping("/sys-file") +@Slf4j +public class SysFileController { + + private final SysFileService sysFileService; + + @Operation(summary = "列表查询") + @GetMapping + public ApiPageResult> list(SysFileListDTO dto) { + return ApiPageResult.success(sysFileService.fileList(dto)); + } + + @DebounceIgnore + @Operation(summary = "上传文件") + @PostMapping("/upload") + public ApiResult upload(@RequestParam MultipartFile file, @RequestParam(value = "dirTag") String dirTag) throws Exception { + return ApiResult.success(sysFileService.uploadFile(file, dirTag, "")); + } + + @Operation(summary = "批量上传文件") + @PostMapping("/batchUpload") + public ApiResult> batchUpload(HttpServletRequest request, + @Parameter(description = "目录标识(用于区分业务目录/存储路径,例如用户头像、合同附件等)", required = true, example = "user-avatar") @RequestParam(value = "dirTag") String dirTag, + @Parameter(description = "场景标识,可选参数,当参数为richtext时将使用富文本编辑器oss.richtextBucketName 作为bucket", required = false, example = "richtext") @RequestParam(value = "scene", required = false) String scene) { + List urlList = new ArrayList<>(); + try { + // 从 request 中获取 MultipartFile 数组 + MultipartFile[] files = getMultipartFiles(request); + for (MultipartFile file : files) { + UploadResult uploadResult = sysFileService.uploadFile(file, dirTag, scene); + urlList.add(uploadResult); + } + } catch (Exception e) { + log.error("文件上传失败:", e); + } + return ApiResult.success(urlList); + } + + private MultipartFile[] getMultipartFiles(HttpServletRequest request) { + MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + List multipartFiles = new ArrayList<>(); + Iterator fileNames = multipartRequest.getFileNames(); + while (fileNames.hasNext()) { + String fileName = fileNames.next(); + multipartFiles.addAll(multipartRequest.getFiles(fileName)); + } + return multipartFiles.toArray(new MultipartFile[0]); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysLoginLogController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysLoginLogController.java new file mode 100644 index 0000000..f69debc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysLoginLogController.java @@ -0,0 +1,79 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.system.pojo.dto.SysLoginLogCreateDTO; +import com.sz.admin.system.pojo.dto.SysLoginLogListDTO; +import com.sz.admin.system.pojo.dto.SysLoginLogUpdateDTO; +import com.sz.admin.system.pojo.vo.SysLoginLogVO; +import com.sz.admin.system.service.SysLoginLogService; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 登陆日志表 Controller + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +@Tag(name = "登陆日志表") +@RestController +@RequestMapping("sys-login-log") +@RequiredArgsConstructor +public class SysLoginLogController { + + private final SysLoginLogService sysLoginLogService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "sys.login.log.create") + @PostMapping + public ApiResult create(@RequestBody SysLoginLogCreateDTO dto) { + sysLoginLogService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "sys.login.log.update") + @PutMapping + public ApiResult update(@RequestBody SysLoginLogUpdateDTO dto) { + sysLoginLogService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "sys.login.log.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysLoginLogService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.login.log.query_table") + @GetMapping + public ApiResult> list(SysLoginLogListDTO dto) { + return ApiPageResult.success(sysLoginLogService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.login.log.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(sysLoginLogService.detail(id)); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "sys.login.log.export") + @PostMapping("/export") + public void exportExcel(@RequestBody SysLoginLogListDTO dto, HttpServletResponse response) { + sysLoginLogService.exportExcel(dto, response); + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysMenuController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysMenuController.java new file mode 100644 index 0000000..d80fcf1 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysMenuController.java @@ -0,0 +1,135 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.stp.StpUtil; +import com.sz.admin.system.pojo.dto.sysmenu.MenuPermissionDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysMenuCreateDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysMenuListDTO; +import com.sz.admin.system.pojo.po.SysMenu; +import com.sz.admin.system.pojo.vo.sysmenu.MenuPermissionVO; +import com.sz.admin.system.pojo.vo.sysmenu.MenuTreeVO; +import com.sz.admin.system.pojo.vo.sysmenu.SysMenuVO; +import com.sz.admin.system.service.SysMenuService; +import com.sz.admin.system.service.SysPermissionService; +import com.sz.core.common.annotation.DebounceIgnore; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.SelectIdsDTO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + *

+ * 系统菜单表 前端控制器 + *

+ * + * @author sz + * @since 2022-10-01 + */ + +@Tag(name = "系统菜单管理") +@RequiredArgsConstructor +@RestController +@RequestMapping("/sys-menu") +public class SysMenuController { + + private final SysMenuService sysMenuService; + + private final SysPermissionService sysPermissionService; + + @Operation(summary = "添加菜单") + @SaCheckPermission(value = "sys.menu.create_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@Valid @RequestBody SysMenuCreateDTO dto) { + sysMenuService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改菜单") + @SaCheckPermission(value = "sys.menu.update_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@Valid @RequestBody SysMenuCreateDTO dto) { + sysMenuService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "批量删除") + @SaCheckPermission(value = "sys.menu.delete_btn", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysMenuService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.menu.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(SysMenuListDTO dto) { + return ApiResult.success(sysMenuService.menuList(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.menu.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("{id}") + public ApiResult detail(@PathVariable String id) { + return ApiResult.success(sysMenuService.detail(id)); + } + + @Operation(summary = "查询上级菜单") + @GetMapping("tree") + public ApiResult> queryParentListTree(@RequestParam(required = false) String nodeId) { + return ApiResult.success(sysMenuService.getSimpleMenuTree(nodeId)); + } + + @DebounceIgnore + @Operation(summary = "查询用户具有的菜单") + @GetMapping("/menu") + public ApiResult> queryMenuByUserId() { + Long userId = StpUtil.getLoginIdAsLong(); + List menuList = sysMenuService.findMenuListByUserId(userId); + return ApiResult.success(menuList); + } + + @Operation(summary = "查询菜单按钮权限是否存在") + @GetMapping("/btn/exists") + public ApiResult findBtnPermission(MenuPermissionDTO dto) { + return ApiResult.success(sysMenuService.hasExistsPermissions(dto)); + } + + @DebounceIgnore + @Operation(summary = "查询全部按钮权限") + @GetMapping("/btn/permissions") + public ApiResult> findBtnPermission() { + return ApiResult.success(sysMenuService.findPermission()); + } + + @Operation(summary = "导出sql") + @SaCheckPermission(value = "sys.menu.sql_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping("sql/export") + public ApiResult exportMenuSql(@RequestBody SelectIdsDTO dto) { + return ApiResult.success(sysMenuService.exportMenuSql(dto)); + } + + @DebounceIgnore + @Operation(summary = "查询用户角色", description = "如果用户是超级管理员(user_tag_cd='1001002'),输出 'admin';否则输出用户的角色id") + @GetMapping("/user/roles") + public ApiResult> findUserRoles() { + Set roles = sysPermissionService.getRoles(StpUtil.getLoginIdAsLong()); + return ApiResult.success(new ArrayList<>(roles)); + } + + @Operation(summary = "修改数据权限状态") + @SaCheckPermission(value = "sys.menu.update_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping("/datarole/change/{id}") + public ApiResult changeDataRole(@PathVariable String id) { + sysMenuService.changeMenuDataScope(id); + return ApiResult.success(); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysMessageController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysMessageController.java new file mode 100644 index 0000000..264a1fd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysMessageController.java @@ -0,0 +1,64 @@ +package com.sz.admin.system.controller; + +import com.sz.admin.system.pojo.dto.sysmessage.SysMessageListDTO; +import com.sz.admin.system.pojo.vo.sysmessage.MessageCountVO; +import com.sz.admin.system.pojo.vo.sysmessage.SysMessageVO; +import com.sz.admin.system.service.SysMessageService; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 消息管理 Controller + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Tag(name = "系统消息") +@RestController +@RequestMapping("sys-message") +@RequiredArgsConstructor +public class SysMessageController { + + private final SysMessageService sysMessageService; + + @Operation(summary = "我的未读消息数量") + @GetMapping("/count") + public ApiResult countMyMessage() { + return ApiResult.success(sysMessageService.countMyUnreadMessages()); + } + + @Operation(summary = "我的待办消息") + @GetMapping("list/todo") + public ApiResult> listTodo() { + SysMessageListDTO dto = new SysMessageListDTO("todo"); + return ApiResult.success(sysMessageService.list(dto)); + } + + @Operation(summary = "我的消息") + @GetMapping("list/msg") + public ApiResult> listMsg() { + SysMessageListDTO dto = new SysMessageListDTO("msg"); + return ApiResult.success(sysMessageService.list(dto)); + } + + @Operation(summary = "列表查询") + @GetMapping + public ApiResult> list(SysMessageListDTO dto) { + return ApiPageResult.success(sysMessageService.page(dto)); + } + + @Operation(summary = "详情") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(sysMessageService.detail(id)); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysRoleController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysRoleController.java new file mode 100644 index 0000000..ec773bd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysRoleController.java @@ -0,0 +1,89 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleCreateDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleListDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleUpdateDTO; +import com.sz.admin.system.pojo.dto.sysrolemenu.SysRoleMenuDTO; +import com.sz.admin.system.pojo.po.SysRole; +import com.sz.admin.system.pojo.vo.sysrolemenu.SysRoleMenuVO; +import com.sz.admin.system.service.SysRoleMenuService; +import com.sz.admin.system.service.SysRoleService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 系统角色表 前端控制器 + *

+ * + * @author sz + * @since 2022-10-01 + */ +@Tag(name = "角色管理") +@RestController +@RequestMapping("/sys-role") +@RequiredArgsConstructor +public class SysRoleController { + + private final SysRoleService sysRoleService; + + private final SysRoleMenuService sysRoleMenuService; + + @Operation(summary = "角色新增") + @SaCheckPermission(value = "sys.role.create_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@Valid @RequestBody SysRoleCreateDTO dto) { + sysRoleService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "角色修改") + @SaCheckPermission(value = "sys.role.update_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@Valid @RequestBody SysRoleUpdateDTO dto) { + sysRoleService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除、批量删除") + @SaCheckPermission(value = "sys.role.delete_btn", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysRoleService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.role.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> listPage(SysRoleListDTO dto) { + return ApiPageResult.success(sysRoleService.list(dto)); + } + + @Operation(summary = "角色菜单配置") + @SaCheckPermission(value = {"sys.role.setting_btn", "sys.role.update_btn"}, mode = SaMode.AND, orRole = GlobalConstant.SUPER_ROLE) + @PutMapping("/menu") + public ApiResult changeRoleMenu(@RequestBody SysRoleMenuDTO dto) { + sysRoleMenuService.change(dto); + return ApiResult.success(); + } + + @Operation(summary = "角色菜单信息查询") + @SaCheckPermission(value = {"sys.role.setting_btn", "sys.role.update_btn"}, mode = SaMode.AND, orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("/menu") + public ApiResult findRoleMenuByRoleId(@NotZero @RequestParam Long roleId) { + return ApiResult.success(sysRoleMenuService.queryRoleMenu(roleId)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysTempFileController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysTempFileController.java new file mode 100644 index 0000000..ae58726 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysTempFileController.java @@ -0,0 +1,82 @@ +package com.sz.admin.system.controller; + +import com.sz.core.common.annotation.DebounceIgnore; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.admin.system.service.SysTempFileService; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileCreateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileUpdateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileListDTO; +import com.sz.admin.system.pojo.vo.systempfile.SysTempFileVO; +import org.springframework.web.multipart.MultipartFile; + +/** + *

+ * 模版文件表 Controller + *

+ * + * @author sz + * @since 2024-12-05 + */ +@Tag(name = "模版文件表") +@RestController +@RequestMapping("sys-temp-file") +@RequiredArgsConstructor +public class SysTempFileController { + + private final SysTempFileService sysTempFileService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "sys.temp.file.create") + @PostMapping + public ApiResult create(@RequestBody SysTempFileCreateDTO dto) { + sysTempFileService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "sys.temp.file.update") + @PutMapping + public ApiResult update(@RequestBody SysTempFileUpdateDTO dto) { + sysTempFileService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "sys.temp.file.remove") + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysTempFileService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "sys.temp.file.query_table") + @GetMapping + public ApiResult> list(SysTempFileListDTO dto) { + return ApiPageResult.success(sysTempFileService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "sys.temp.file.query_table") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Object id) { + return ApiResult.success(sysTempFileService.detail(id)); + } + + @DebounceIgnore + @Operation(summary = "上传模板文件") + @PostMapping("/upload") + public ApiResult upload(@RequestParam MultipartFile file) { + return ApiResult.success(sysTempFileService.uploadFile(file)); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysTempFileHistoryController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysTempFileHistoryController.java new file mode 100644 index 0000000..b260597 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysTempFileHistoryController.java @@ -0,0 +1,36 @@ +package com.sz.admin.system.controller; + +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileHistoryListDTO; +import com.sz.admin.system.pojo.po.SysTempFileHistory; +import com.sz.admin.system.service.SysTempFileHistoryService; +import com.sz.core.common.entity.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; + +/** + *

+ * 模版文件历史表 Controller + *

+ * + * @author sz-admin + * @since 2024-12-14 + */ +@Tag(name = "模版文件历史表") +@RestController +@RequestMapping("sys-temp-file-history") +@RequiredArgsConstructor +public class SysTempFileHistoryController { + + private final SysTempFileHistoryService sysTempFileHistoryService; + + @Operation(summary = "模板文件历史查询") + @SaCheckPermission(value = "sys.temp.file.query_table") + @GetMapping("history") + public ApiResult> list(SysTempFileHistoryListDTO dto) { + return ApiPageResult.success(sysTempFileHistoryService.historyList(dto)); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysUserController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysUserController.java new file mode 100644 index 0000000..7c112c4 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/controller/SysUserController.java @@ -0,0 +1,173 @@ +package com.sz.admin.system.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import com.sz.admin.system.pojo.dto.sysmenu.SysUserRoleDTO; +import com.sz.admin.system.pojo.dto.sysuser.*; +import com.sz.admin.system.pojo.vo.sysdept.DeptTreeVO; +import com.sz.admin.system.pojo.vo.sysuser.SysUserRoleVO; +import com.sz.admin.system.pojo.vo.sysuser.SysUserVO; +import com.sz.admin.system.pojo.vo.sysuser.UserOptionVO; +import com.sz.admin.system.service.SysDeptService; +import com.sz.admin.system.service.SysUserDataRoleService; +import com.sz.admin.system.service.SysUserService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.*; +import com.sz.core.common.valid.annotation.NotZero; +import com.sz.redis.WebsocketRedisService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 系统用户表 前端控制器 + *

+ * + * @author sz + * @since 2022-10-01 + */ +@Tag(name = "用户管理") +@RestController +@RequestMapping("/sys-user") +@RequiredArgsConstructor +public class SysUserController { + + private final SysUserService sysUserService; + + private final WebsocketRedisService websocketRedisService; + + private final SysDeptService sysDeptService; + + private final SysUserDataRoleService sysUserDataRoleService; + + @Operation(summary = "添加用户") + @SaCheckPermission(value = "sys.user.create_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@Valid @RequestBody SysUserCreateDTO dto) { + sysUserService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改用户") + @SaCheckPermission(value = "sys.user.update_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@Valid @RequestBody SysUserUpdateDTO dto) { + sysUserService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "批量删除") + @SaCheckPermission(value = "sys.user.delete_btn", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + sysUserService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "查询分页列表") + @SaCheckPermission(value = "sys.user.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiPageResult> listPage(SysUserListDTO dto) { + return ApiPageResult.success(sysUserService.page(dto)); + } + + @Operation(summary = "用户详情") + @SaCheckPermission(value = "sys.user.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("{id}") + public ApiResult detail(@PathVariable Long id) { + return ApiResult.success(sysUserService.detail(id)); + } + + @Operation(summary = "用户角色信息查询-(穿梭框)") + @SaCheckPermission(value = "sys.user.role_set_btn", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("role") + public ApiResult findUserRole(@NotZero @RequestParam Long userId) { + return ApiResult.success(sysUserService.findSysUserRole(userId)); + } + + @Operation(summary = "用户角色信息修改 -(穿梭框)") + @SaCheckPermission(value = "sys.user.role_set_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping("role") + public ApiResult changeUserRole(@Valid @RequestBody SysUserRoleDTO dto) { + sysUserService.changeSysUserRole(dto); + return ApiResult.success(); + } + + @Operation(summary = "登录信息查询") + @GetMapping("/userinfo") + public ApiResult getUserInfo() { + return ApiResult.success(sysUserService.getUserInfo()); + } + + @Operation(summary = "(个人)修改密码") + @PutMapping("/password") + public ApiResult changePassword(@Valid @RequestBody SysUserPasswordDTO dto) { + sysUserService.changePassword(dto); + return ApiResult.success(); + } + + @Operation(summary = "重置账户密码") + @PutMapping("/reset/password/{userId}") + public ApiResult resetPassword(@PathVariable Long userId) { + sysUserService.resetPassword(userId); + return ApiResult.success(); + } + + @Operation(summary = "账户解锁") + @SaCheckPermission(value = "sys.user.unlock_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping("unlock") + public ApiResult unlock(@RequestBody SelectIdsDTO dto) { + sysUserService.unlock(dto); + return ApiResult.success(); + } + + @Operation(summary = "绑定(批量)用户和部门") + @SaCheckPermission(value = "sys.user.dept_set_btn", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping("/dept/bind") + public ApiResult bindDept(@RequestBody UserDeptDTO dto) { + sysUserService.bindUserDept(dto); + return ApiResult.success(); + } + + @GetMapping("/dept/tree") + @Operation(summary = "账户管理-部门树形列表") + public ApiResult> tree() { + return ApiResult.success(sysDeptService.getDepartmentTreeWithAdditionalNodes()); + } + + @Operation(summary = "用户信息-下拉列表") + @SaCheckPermission(value = {"sys.user.query_table", "sys.dept.query_table"}, mode = SaMode.OR, orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("options") + public ApiResult> getUserOptions() { + return ApiResult.success(sysUserService.getUserOptions()); + } + + @Operation(summary = "用户数据角色信息查询-(穿梭框)") + @SaCheckPermission(value = "sys.user.data_role_set_btn", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("datarole") + public ApiResult findUserDataRole(@NotZero @RequestParam Long userId) { + return ApiResult.success(sysUserDataRoleService.queryRoleMenu(userId)); + } + + @Operation(summary = "用户数据角色信息修改 -(穿梭框)") + @SaCheckPermission(value = "sys.user.data_role_set_btn", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping("datarole") + public ApiResult changeDataUserRole(@Valid @RequestBody SysUserRoleDTO dto) { + sysUserDataRoleService.changeRole(dto); + return ApiResult.success(); + } + + @Operation(summary = "用户类型设置") + @SaCheckPermission(value = "sys.user.admin_set_btn") + @PostMapping("changeset/usertag") + public ApiResult changeUserTag(@RequestBody SysUserTagDTO dto) { + sysUserService.changeUserTag(dto); + return ApiResult.success(); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/CommonFileMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/CommonFileMapper.java new file mode 100644 index 0000000..4fedb02 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/CommonFileMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysFile; + +/** + *

+ * Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-31 + */ +public interface CommonFileMapper extends BaseMapper { + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/ProductMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/ProductMapper.java new file mode 100644 index 0000000..67834c8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/ProductMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.Product; + +/** + *

+ * 商品信息表 Mapper 接口 + *

+ * + * @author Lz + * @since 2026-01-22 + */ +public interface ProductMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysClientMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysClientMapper.java new file mode 100644 index 0000000..cfb8b2c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysClientMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysClient; + +/** + *

+ * 系统授权表 Mapper 接口 + *

+ * + * @author sz + * @since 2024-01-22 + */ +public interface SysClientMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysConfigMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..979d259 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysConfigMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysConfig; + +/** + *

+ * 参数配置表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-11-23 + */ +public interface SysConfigMapper extends BaseMapper { + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleMapper.java new file mode 100644 index 0000000..d957cab --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleMapper.java @@ -0,0 +1,17 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDataRole; + +/** + *

+ * 数据权限管理 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Deprecated(since = "v1.4.0-beta") +public interface SysDataRoleMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleMenuMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleMenuMapper.java new file mode 100644 index 0000000..de9b29d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleMenuMapper.java @@ -0,0 +1,17 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDataRoleMenu; + +/** + *

+ * 系统数据角色-菜单表 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +@Deprecated(since = "v1.4.0-beta") +public interface SysDataRoleMenuMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleRelationMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleRelationMapper.java new file mode 100644 index 0000000..25d6153 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDataRoleRelationMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDataRoleRelation; + +/** + *

+ * 系统数据角色-关联表 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +public interface SysDataRoleRelationMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptClosureMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptClosureMapper.java new file mode 100644 index 0000000..fceb961 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptClosureMapper.java @@ -0,0 +1,61 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDeptClosure; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 部门祖籍关系表 Mapper 接口 + *

+ * + * @author sz + * @since 2024-03-28 + */ +public interface SysDeptClosureMapper extends BaseMapper { + + /** + * 分离子树 + * + * @param nodeId + * 节点ID + * @return 分离的节点数 + */ + @Delete(" DELETE " + " FROM " + " sys_dept_closure t " + " WHERE" + " EXISTS (" + " SELECT" + " 1 " + " FROM" + " sys_dept_closure d " + " WHERE" + + " d.ancestor_id = #{nodeId} and t.descendant_id = d.descendant_id " + " ) " + " and " + + " EXISTS( select 1 from sys_dept_closure a where a.descendant_id = #{nodeId} and a.ancestor_id != a.descendant_id and t.ancestor_id = a.ancestor_id )") + Integer detach(@Param("nodeId") Integer nodeId); + + /** + * 查询指定节点的子树 + * + * @param nodeId + * 节点ID + * @return 子树 + */ + @Select(" SELECT ancestor_id,descendant_id,depth FROM sys_dept_closure " + " WHERE EXISTS (" + " SELECT 1 " + " FROM sys_dept_closure d " + + " WHERE d.ancestor_id = #{nodeId} " + " AND sys_dept_closure.descendant_id = d.descendant_id" + ")" + " AND EXISTS (" + " SELECT 1 " + + " FROM sys_dept_closure a " + " WHERE a.descendant_id = #{nodeId} " + " AND a.ancestor_id != a.descendant_id " + + " AND sys_dept_closure.ancestor_id = a.ancestor_id " + " );") + List selectDetachTree(@Param("nodeId") Long nodeId); + + /** + * 嫁接子树 + * + * @param nodeId + * 节点ID + * @param newNodeId + * 新节点ID + * @return 嫁接的节点数 + */ + @Insert("INSERT INTO sys_dept_closure ( ancestor_id, descendant_id, depth ) SELECT" + " super.ancestor_id," + " sub.descendant_id,(" + + " super.depth + sub.depth + 1 " + " ) " + " FROM" + " sys_dept_closure super" + " CROSS JOIN sys_dept_closure sub " + " WHERE" + + " super.descendant_id = #{newNodeId} " + " AND sub.ancestor_id = #{nodeId}") + Integer graft(@Param("nodeId") Long nodeId, @Param("newNodeId") Long newNodeId); + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptLeaderMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptLeaderMapper.java new file mode 100644 index 0000000..920be3e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptLeaderMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDeptLeader; + +/** + *

+ * 部门领导人表 Mapper 接口 + *

+ * + * @author sz + * @since 2024-03-26 + */ +public interface SysDeptLeaderMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptMapper.java new file mode 100644 index 0000000..5f68900 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptMapper.java @@ -0,0 +1,36 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDept; +import com.sz.admin.system.pojo.vo.sysdept.TotalDeptVO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 部门表 Mapper 接口 + *

+ * + * @author sz + * @since 2024-03-20 + */ +public interface SysDeptMapper extends BaseMapper { + + /** + * (向上递归)查询指定层级的祖籍id + * + * @param deptId + * 部门id + * @return 祖籍id集合 + */ + List iterUpDeptAncestors(@Param("deptId") Integer deptId); + + /** + * 统计分配部门的用户数量 + * + * @return 部门用户数量 + */ + List countUsersPerDept(); + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptRoleMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptRoleMapper.java new file mode 100644 index 0000000..bcc3fda --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDeptRoleMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDeptRole; + +/** + *

+ * 系统部门-角色关联表 Mapper 接口 + *

+ * + * @author sz + * @since 2025-07-15 + */ +public interface SysDeptRoleMapper extends BaseMapper { + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDictMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDictMapper.java new file mode 100644 index 0000000..8655c6c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDictMapper.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDict; +import com.sz.core.common.entity.DictVO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 字典表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-18 + */ +public interface SysDictMapper extends BaseMapper { + + List listDict(@Param("typeCode") String typeCode); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDictTypeMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDictTypeMapper.java new file mode 100644 index 0000000..9cb520f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysDictType; + +/** + *

+ * 字典类型 Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-18 + */ +public interface SysDictTypeMapper extends BaseMapper { + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysLoginLogMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysLoginLogMapper.java new file mode 100644 index 0000000..00d0b22 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysLoginLogMapper.java @@ -0,0 +1,19 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysLoginLog; +import org.apache.ibatis.annotations.Param; + +/** + *

+ * 登陆日志表 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +public interface SysLoginLogMapper extends BaseMapper { + + Long insertLoginLog(@Param("loginLog") SysLoginLog loginLog); + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMenuMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..d928d56 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMenuMapper.java @@ -0,0 +1,49 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysMenu; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 系统菜单表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-21 + */ +public interface SysMenuMapper extends BaseMapper { + + List getMenuAndChildrenIds(@Param("menuId") String menuId, @Param("isShowButton") boolean isShowButton); + + /** + * 更新has_children + */ + void syncTreeHasChildren(); + + /** + * 更新deep + */ + void syncTreeDeep(); + + /** + * 删除自己及子节点 + */ + void removeTree(@Param("nodeId") String nodeId); + + /** + * @param ids + * ids + */ + void updateMenuAndChildrenIsDelete(List ids); + + /** + * @param ids + * ids + * @return 递归下边的子节点id集合 + */ + List selectMenuAndChildrenIds(List ids); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMessageMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMessageMapper.java new file mode 100644 index 0000000..41b2683 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMessageMapper.java @@ -0,0 +1,15 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysMessage; + +/** + *

+ * 消息管理 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +public interface SysMessageMapper extends BaseMapper { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMessageUserMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMessageUserMapper.java new file mode 100644 index 0000000..61d3fd7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysMessageUserMapper.java @@ -0,0 +1,15 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysMessageUser; + +/** + *

+ * 消息接收用户表 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +public interface SysMessageUserMapper extends BaseMapper { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysRoleMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..ac2c628 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysRoleMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysRole; + +/** + *

+ * 系统角色表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-21 + */ +public interface SysRoleMapper extends BaseMapper { + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysRoleMenuMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..b655b32 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysRoleMenu; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 系统角色-菜单表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-21 + */ +public interface SysRoleMenuMapper extends BaseMapper { + + void insertBatchSysRoleMenu(@Param("menuIds") List menuIds, @Param("roleId") Long roleId, @Param("permissionType") String permissionType, + @Param("dataScopeCd") String dataScopeCd); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysTempFileHistoryMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysTempFileHistoryMapper.java new file mode 100644 index 0000000..dab1df9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysTempFileHistoryMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysTempFileHistory; + +/** + *

+ * 模版文件历史 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +public interface SysTempFileHistoryMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysTempFileMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysTempFileMapper.java new file mode 100644 index 0000000..30483a7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysTempFileMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysTempFile; + +/** + *

+ * 模版文件表 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +public interface SysTempFileMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserDataRoleMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserDataRoleMapper.java new file mode 100644 index 0000000..f02738c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserDataRoleMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysUserDataRole; + +/** + *

+ * 系统用户-数据角色关联表 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +public interface SysUserDataRoleMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserDeptMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserDeptMapper.java new file mode 100644 index 0000000..cc70914 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserDeptMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysUserDept; + +/** + *

+ * 用户-部门关系表 Mapper 接口 + *

+ * + * @author sz + * @since 2024-04-02 + */ +public interface SysUserDeptMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..ec80285 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserMapper.java @@ -0,0 +1,75 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.dto.sysuser.SysUserListDTO; +import com.sz.admin.system.pojo.po.SysUser; +import com.sz.admin.system.pojo.vo.sysuser.SysUserVO; +import org.apache.ibatis.annotations.Select; + +import java.util.List; + +/** + *

+ * 系统用户表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-18 + */ +public interface SysUserMapper extends BaseMapper { + + @Select(" select sr.role_name from sys_user_role sur left join sys_role sr on sur.role_id = sr.id where sur.user_id =#{userId} ") + List queryUserRoles(Integer userId); + + /** + * 验证用户名是否存在 + * + * @param username + * 用户名 + * @return 用户数量 + */ + @Select(" select count(id) from sys_user where username = #{username} ") + int validUsername(String username); + + /** + * 查询全部部门的用户列表 + * + * @param dto + * 查询条件 + * @return 用户列表 + */ + List queryAllSysUserList(SysUserListDTO dto); + + /** + * 查询全部部门的用户名称列表 + * + * @param ids + * 用户id + * @return 用户名称列表 + */ + List queryAllSysUserNameList(String[] ids); + + /** + * 查询(部门)用户列表 + * + * @param dto + * 查询条件 + * @return 用户列表 + */ + List querySysUserListByDept(SysUserListDTO dto); + + /** + * 查询(未分配部门)用户列表 + * + * @param dto + * 查询条件 + * @return 用户列表 + */ + List querySysUserListNotDept(SysUserListDTO dto); + + /** + * 查询(未分配部门)用户数量 + */ + Integer countSysUserListNotDept(); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserRoleMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..d5343a9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,25 @@ +package com.sz.admin.system.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.system.pojo.po.SysUserRole; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + *

+ * 系统用户-角色关联表 Mapper 接口 + *

+ * + * @author sz + * @since 2023-08-29 + */ +public interface SysUserRoleMapper extends BaseMapper { + + void insertBatchSysUserRole(@Param("roleIds") List roleIds, @Param("userId") Long userId); + + List queryMenuIdByUserId(@Param("userId") Long userId); + + List queryPermissionByUserId(@Param("userId") Long userId); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductCreateDTO.java new file mode 100644 index 0000000..b06d31f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductCreateDTO.java @@ -0,0 +1,33 @@ +package com.sz.admin.system.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Product添加DTO + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Data +@Schema(description = "Product添加DTO") +public class ProductCreateDTO { + + @Schema(description = "商品名称") + private String productName; + + @Schema(description = "价格") + private BigDecimal price; + + @Schema(description = "状态(0停用 1启用)") + private Integer status; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductImportDTO.java new file mode 100644 index 0000000..eee4962 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductImportDTO.java @@ -0,0 +1,37 @@ +package com.sz.admin.system.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Product导入DTO + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Data +@Schema(description = "Product导入DTO") +public class ProductImportDTO { + + @ExcelProperty(value = "商品名称") + @Schema(description = "商品名称") + private String productName; + + @ExcelProperty(value = "价格") + @Schema(description = "价格") + private BigDecimal price; + + @ExcelProperty(value = "状态(0停用 1启用)") + @Schema(description = "状态(0停用 1启用)") + private Integer status; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductListDTO.java new file mode 100644 index 0000000..c614666 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductListDTO.java @@ -0,0 +1,34 @@ +package com.sz.admin.system.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import com.sz.core.common.entity.PageQuery; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Product查询DTO + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Data +@Schema(description = "Product查询DTO") +public class ProductListDTO extends PageQuery { + + @Schema(description = "商品名称") + private String productName; + + @Schema(description = "价格") + private BigDecimal price; + + @Schema(description = "状态(0停用 1启用)") + private Integer status; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductUpdateDTO.java new file mode 100644 index 0000000..8583d3c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/ProductUpdateDTO.java @@ -0,0 +1,36 @@ +package com.sz.admin.system.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Product修改DTO + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Data +@Schema(description = "Product修改DTO") +public class ProductUpdateDTO { + + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "商品名称") + private String productName; + + @Schema(description = "价格") + private BigDecimal price; + + @Schema(description = "状态(0停用 1启用)") + private Integer status; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogCreateDTO.java new file mode 100644 index 0000000..e32f8ca --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogCreateDTO.java @@ -0,0 +1,50 @@ +package com.sz.admin.system.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * SysLoginLog添加DTO + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +@Data +@Accessors(chain = true) +@Schema(description = "SysLoginLog添加DTO") +public class SysLoginLogCreateDTO { + + @Schema(description = "用户名") + private String userName; + + @Schema(description = "登陆状态") + private String loginStatus; + + @Schema(description = "登陆时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime loginTime; + + @Schema(description = "登陆ip地址") + private String ipAddress; + + @Schema(description = "登陆地点") + private String loginLocation; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "提示消息") + private String msg; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogListDTO.java new file mode 100644 index 0000000..4f7ee74 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogListDTO.java @@ -0,0 +1,36 @@ +package com.sz.admin.system.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import com.sz.core.common.entity.PageQuery; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; +/** + *

+ * SysLoginLog查询DTO + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +@Data +@Accessors(chain = true) +@Schema(description = "SysLoginLog查询DTO") +public class SysLoginLogListDTO extends PageQuery { + + @Schema(description = "用户名") + private String userName; + + @Schema(description = "登陆状态") + private String loginStatus; + + @Schema(description = "登陆时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime loginTimeStart; + + @Schema(description = "登陆时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime loginTimeEnd; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogUpdateDTO.java new file mode 100644 index 0000000..acaafaf --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/SysLoginLogUpdateDTO.java @@ -0,0 +1,53 @@ +package com.sz.admin.system.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * SysLoginLog修改DTO + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +@Data +@Accessors(chain = true) +@Schema(description = "SysLoginLog修改DTO") +public class SysLoginLogUpdateDTO { + + @Schema(description = "登陆ID") + private Integer id; + + @Schema(description = "用户名") + private String userName; + + @Schema(description = "登陆状态") + private String loginStatus; + + @Schema(description = "登陆时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime loginTime; + + @Schema(description = "登陆ip地址") + private String ipAddress; + + @Schema(description = "登陆地点") + private String loginLocation; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "提示消息") + private String msg; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/common/ProxyDownloadDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/common/ProxyDownloadDTO.java new file mode 100644 index 0000000..fa40121 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/common/ProxyDownloadDTO.java @@ -0,0 +1,10 @@ +package com.sz.admin.system.pojo.dto.common; + +import lombok.Data; + +@Data +public class ProxyDownloadDTO { + + private String url; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/common/SelectorQueryDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/common/SelectorQueryDTO.java new file mode 100644 index 0000000..f808f54 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/common/SelectorQueryDTO.java @@ -0,0 +1,30 @@ +package com.sz.admin.system.pojo.dto.common; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SelectorQueryDTO - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/5 + */ +@Schema(description = "多维选择器查询DTO") +@Data +public class SelectorQueryDTO extends PageQuery { + + @Schema(description = "类型", allowableValues = {"user", "role", "department"}, requiredMode = Schema.RequiredMode.REQUIRED) + private String type; + + @Schema(description = "关键字") + private String keyword; + + @Schema(description = "父级维度 ID,用于 user 时代表 deptId,department 时代表上级部门 ID") + private Object parentId; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientCreateDTO.java new file mode 100644 index 0000000..d7f8608 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientCreateDTO.java @@ -0,0 +1,44 @@ +package com.sz.admin.system.pojo.dto.sysclient; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + *

+ * SysClient添加DTO + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Data +@Schema(description = "SysClient添加DTO") +public class SysClientCreateDTO { + + @Schema(description = "客户端key") + private String clientKey; + + @Schema(description = "授权类型数组") + private List grantTypeCdList; + + @Schema(description = "授权类型") + private String grantTypeCd; + + @Schema(description = "设备类型") + private String deviceTypeCd; + + @Schema(description = "token活跃超时时间") + private Integer activeTimeout; + + @Schema(description = "token固定超时") + private Integer timeout; + + @Schema(description = "状态") + private String clientStatusCd; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientImportDTO.java new file mode 100644 index 0000000..6a6462f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientImportDTO.java @@ -0,0 +1,17 @@ +package com.sz.admin.system.pojo.dto.sysclient; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +/** + *

+ * SysClient导入DTO + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Data +@Schema(description = "SysClient导入DTO") +public class SysClientImportDTO { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientListDTO.java new file mode 100644 index 0000000..ccc849e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientListDTO.java @@ -0,0 +1,34 @@ +package com.sz.admin.system.pojo.dto.sysclient; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

+ * SysClient添加DTO + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Data +@Schema(description = "SysClient查询DTO") +public class SysClientListDTO extends PageQuery { + + @Schema(description = "客户端key") + private String clientKey; + + @Schema(description = "客户端秘钥") + private String clientSecret; + + @Schema(description = "授权类型") + private String grantTypeCd; + + @Schema(description = "设备类型") + private String deviceTypeCd; + + @Schema(description = "token活跃超时时间") + private Integer activeTimeout; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientUpdateDTO.java new file mode 100644 index 0000000..27cafbc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysclient/SysClientUpdateDTO.java @@ -0,0 +1,44 @@ +package com.sz.admin.system.pojo.dto.sysclient; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + *

+ * SysClient添加DTO + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Data +@Schema(description = "SysClient修改DTO") +public class SysClientUpdateDTO { + + @Schema(description = "客户端id") + private String clientId; + + @Schema(description = "授权类型数组") + private List grantTypeCdList; + + @Schema(description = "授权类型") + private String grantTypeCd; + + @Schema(description = "设备类型") + private String deviceTypeCd; + + @Schema(description = "token活跃超时时间") + private Integer activeTimeout; + + @Schema(description = "token固定超时") + private Integer timeout; + + @Schema(description = "状态") + private String clientStatusCd; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigCreateDTO.java new file mode 100644 index 0000000..a9d480b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigCreateDTO.java @@ -0,0 +1,25 @@ +package com.sz.admin.system.pojo.dto.sysconfig; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "参数添加") +public class SysConfigCreateDTO { + + @Schema(description = "参数名") + private String configName; + + @Schema(description = "key") + private String configKey; + + @Schema(description = "value") + private String configValue; + + @Schema(description = "该参数是否需要前端加载、缓存及使用") + private String frontendVisible; + + @Schema(description = "备注") + private String remark; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigListDTO.java new file mode 100644 index 0000000..a6e942e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigListDTO.java @@ -0,0 +1,17 @@ +package com.sz.admin.system.pojo.dto.sysconfig; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "列表查询") +public class SysConfigListDTO extends PageQuery { + + @Schema(description = "参数名", example = "test") + private String configName; + + @Schema(description = "参数Key", example = "key1") + private String configKey; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigUpdateDTO.java new file mode 100644 index 0000000..718fea2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysconfig/SysConfigUpdateDTO.java @@ -0,0 +1,30 @@ +package com.sz.admin.system.pojo.dto.sysconfig; + +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "参数修改") +public class SysConfigUpdateDTO { + + @NotZero + @Schema(description = "参数id", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "参数名") + private String configName; + + @Schema(description = "key") + private String configKey; + + @Schema(description = "value") + private String configValue; + + @Schema(description = "该参数是否需要前端加载、缓存及使用") + private String frontendVisible; + + @Schema(description = "备注") + private String remark; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleCreateDTO.java new file mode 100644 index 0000000..a976610 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleCreateDTO.java @@ -0,0 +1,37 @@ +package com.sz.admin.system.pojo.dto.sysdatarole; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * SysDataRole添加DTO + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataRole添加DTO") +public class SysDataRoleCreateDTO { + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "数据范围") + private String dataScopeCd; + + @Schema(description = "选中的菜单id数组") + private List selectMenuIds = new ArrayList<>(); + + @Schema(description = "选中的部门id数组") + private List selectDeptIds = new ArrayList<>(); + + @Schema(description = "(自定义)选中的用户id数组") + private List userOptions; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleListDTO.java new file mode 100644 index 0000000..b86b9da --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleListDTO.java @@ -0,0 +1,26 @@ +package com.sz.admin.system.pojo.dto.sysdatarole; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.sz.core.common.entity.PageQuery; + +/** + *

+ * SysDataRole查询DTO + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataRole查询DTO") +public class SysDataRoleListDTO extends PageQuery { + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "是否锁定") + private String isLock; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleUpdateDTO.java new file mode 100644 index 0000000..0a3ee01 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatarole/SysDataRoleUpdateDTO.java @@ -0,0 +1,40 @@ +package com.sz.admin.system.pojo.dto.sysdatarole; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * SysDataRole修改DTO + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataRole修改DTO") +public class SysDataRoleUpdateDTO { + + @Schema(description = "角色id") + private Long id; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "数据范围") + private String dataScopeCd; + + @Schema(description = "选中的菜单id数组") + private List selectMenuIds = new ArrayList<>(); + + @Schema(description = "选中的部门id数组") + private List selectDeptIds = new ArrayList<>(); + + @Schema(description = "(自定义)选中的用户id数组") + private List userOptions; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatascope/SysDataScopeListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatascope/SysDataScopeListDTO.java new file mode 100644 index 0000000..3896b64 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatascope/SysDataScopeListDTO.java @@ -0,0 +1,29 @@ +package com.sz.admin.system.pojo.dto.sysdatascope; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +/** + *

+ * SysDataScope查询DTO + *

+ * + * @author sz-admin + * @since 2024-07-01 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataScope查询DTO") +@RequiredArgsConstructor +@AllArgsConstructor +public class SysDataScopeListDTO { + + @Schema(description = "关联类型,data_scope_relation_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "1007001") + private String relationTypeCd; + + @Schema(description = "关联表id,与关联类型联动。例relationTypeCd=1007001代表部门权限,relationId代表deptId;relationTypeCd=1007002代表个人权限,relationId代表userId", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long relationId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatascope/SysDataScopeUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatascope/SysDataScopeUpdateDTO.java new file mode 100644 index 0000000..6238c55 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdatascope/SysDataScopeUpdateDTO.java @@ -0,0 +1,40 @@ +package com.sz.admin.system.pojo.dto.sysdatascope; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +/** + *

+ * SysDataScope修改DTO + *

+ * + * @author sz-admin + * @since 2024-07-01 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataScope修改DTO") +@RequiredArgsConstructor +@AllArgsConstructor +public class SysDataScopeUpdateDTO { + + @Schema(description = "关联类型,data_scope_relation_type") + private String relationTypeCd; + + @Schema(description = "关联表id") + private Long relationId; + + @Schema(description = "关联部门") + private List deptOptions; + + @Schema(description = "关联用户") + private List userOptions; + + @Schema(description = "数据权限") + private String dataScope; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptCreateDTO.java new file mode 100644 index 0000000..2c4bf7b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptCreateDTO.java @@ -0,0 +1,34 @@ +package com.sz.admin.system.pojo.dto.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.util.List; + +/** + *

+ * SysDept添加DTO + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Data +@Schema(description = "SysDept添加DTO") +public class SysDeptCreateDTO { + + @Schema(description = "部门名称") + private String name; + + @Schema(description = "父级id") + private Long pid; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "负责人") + private List leaders; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptImportDTO.java new file mode 100644 index 0000000..52bbc5c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptImportDTO.java @@ -0,0 +1,18 @@ +package com.sz.admin.system.pojo.dto.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

+ * SysDept导入DTO + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Data +@Schema(description = "SysDept导入DTO") +public class SysDeptImportDTO { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptListDTO.java new file mode 100644 index 0000000..ad160d7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptListDTO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.dto.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.sz.core.common.entity.PageQuery; + +/** + *

+ * SysDept添加DTO + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Data +@Schema(description = "SysDept查询DTO") +public class SysDeptListDTO extends PageQuery { + + @Schema(description = "部门名称") + private String name; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptRoleDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptRoleDTO.java new file mode 100644 index 0000000..49d41f2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptRoleDTO.java @@ -0,0 +1,24 @@ +package com.sz.admin.system.pojo.dto.sysdept; + +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2025/7/15 16:49 + */ +@Data +@Schema(description = "部门角色变更") +public class SysDeptRoleDTO { + + @Schema(description = "角色id数组") + private List roleIds; + + @NotZero(message = "部门id不能为空") + @Schema(description = "部门id", requiredMode = Schema.RequiredMode.REQUIRED) + private Long deptId; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptUpdateDTO.java new file mode 100644 index 0000000..6527703 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdept/SysDeptUpdateDTO.java @@ -0,0 +1,37 @@ +package com.sz.admin.system.pojo.dto.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.util.List; + +/** + *

+ * SysDept添加DTO + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Data +@Schema(description = "SysDept修改DTO") +public class SysDeptUpdateDTO { + + @Schema(description = "id") + private Long id; + + @Schema(description = "部门名称") + private String name; + + @Schema(description = "父级id") + private Long pid; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "负责人") + private List leaders; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictCreateDTO.java new file mode 100644 index 0000000..897b001 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictCreateDTO.java @@ -0,0 +1,36 @@ +package com.sz.admin.system.pojo.dto.sysdict; + +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +@Schema(description = "字典添加") +public class SysDictCreateDTO { + + @NotNull(message = "sysDictTypeId不能为空") + @Schema(description = "关联sys_dict_type id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Long sysDictTypeId; + + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "禁用") + private String codeName; + + @Schema(description = "字典别名") + private String alias; + + @Schema(description = "排序") + @NotZero(message = "排序不能为空或0") + @Min(1) + @Max(999999) + private Integer sort; + + @Schema(description = "回显样式") + private String callbackShowStyle; + + @Schema(description = "备注") + private String remark; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictListDTO.java new file mode 100644 index 0000000..c6d2458 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictListDTO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.dto.sysdict; + +import com.sz.core.common.entity.PageQuery; +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "列表查询") +public class SysDictListDTO extends PageQuery { + + @NotZero(message = "sysDictTypeId不能为空") + @Schema(description = "关联sys_dict_type id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Long sysDictTypeId; + + @Schema(description = "字典别名") + private String alias; + + @Schema(description = "字典名称", example = "禁用") + private String codeName; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeAddDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeAddDTO.java new file mode 100644 index 0000000..3c818dd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeAddDTO.java @@ -0,0 +1,25 @@ +package com.sz.admin.system.pojo.dto.sysdict; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +@Schema(description = "字典类型添加") +public class SysDictTypeAddDTO { + + @NotBlank(message = "字典名称不能为空") + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "账户状态") + private String typeName; + + @NotBlank(message = "字典码不能为空") + @Schema(description = "字典码(英文)", requiredMode = Schema.RequiredMode.REQUIRED, example = "account_status") + private String typeCode; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "字典类型") + private String type; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeListDTO.java new file mode 100644 index 0000000..95c798b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeListDTO.java @@ -0,0 +1,17 @@ +package com.sz.admin.system.pojo.dto.sysdict; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "字典类型查询参数") +public class SysDictTypeListDTO extends PageQuery { + + @Schema(description = "字典类型名字") + private String typeName; + + @Schema(description = "字典类型码") + private String typeCode; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeSelectDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeSelectDTO.java new file mode 100644 index 0000000..e199a61 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeSelectDTO.java @@ -0,0 +1,15 @@ +package com.sz.admin.system.pojo.dto.sysdict; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +@Schema(description = "字典类型批量操作") +public class SysDictTypeSelectDTO { + + @Schema(description = "字典类型id数组") + private List ids; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeUpDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeUpDTO.java new file mode 100644 index 0000000..b839c1e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictTypeUpDTO.java @@ -0,0 +1,30 @@ +package com.sz.admin.system.pojo.dto.sysdict; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +@Schema(description = "字典类型修改") +public class SysDictTypeUpDTO { + + @NotNull(message = "id不能为") + @Schema(description = "id") + private Long id; + + @NotBlank(message = "字典名称不能为空") + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "账户状态") + private String typeName; + + @NotBlank(message = "字典码不能为空") + @Schema(description = "字典码(英文)", requiredMode = Schema.RequiredMode.REQUIRED, example = "account_status") + private String typeCode; + + @Schema(description = "是否显示", allowableValues = "T,F", example = "T") + private String isShow; + + @Schema(description = "备注") + private String remark; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictUpdateDTO.java new file mode 100644 index 0000000..f1c2856 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysdict/SysDictUpdateDTO.java @@ -0,0 +1,40 @@ +package com.sz.admin.system.pojo.dto.sysdict; + +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +@Schema(description = "字典修改") +public class SysDictUpdateDTO { + + @NotNull(message = "id不能为空") + @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Long id; + + @NotNull(message = "sysDictTypeId不能为空") + @Schema(description = "关联sys_dict_type id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") + private Long sysDictTypeId; + + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "禁用") + private String codeName; + + @Schema(description = "字典别名") + private String alias; + + @Schema(description = "排序") + @NotZero(message = "排序不能为空或0") + @Min(1) + @Max(999999) + private Integer sort; + + @Schema(description = "回显样式") + private String callbackShowStyle; + + @Schema(description = "备注") + private String remark; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysfile/SysFileListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysfile/SysFileListDTO.java new file mode 100644 index 0000000..f9e04fd --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysfile/SysFileListDTO.java @@ -0,0 +1,19 @@ +package com.sz.admin.system.pojo.dto.sysfile; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SysFileQueryDTO + * + * @author sz + * @since 2023/8/31 0031 + */ +@Data +@Schema(description = "公共文件搜索") +public class SysFileListDTO extends PageQuery { + + @Schema(description = "文件名") + private String filename; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/MenuPermissionDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/MenuPermissionDTO.java new file mode 100644 index 0000000..f4ca8e0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/MenuPermissionDTO.java @@ -0,0 +1,20 @@ +package com.sz.admin.system.pojo.dto.sysmenu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2023/9/1 14:07 + */ +@Data +@Schema(description = "菜单权限查询") +public class MenuPermissionDTO { + + @Schema(description = "菜单id") + private String id; + + @Schema(description = "权限标识", requiredMode = Schema.RequiredMode.REQUIRED) + private String permissions; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysMenuCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysMenuCreateDTO.java new file mode 100644 index 0000000..146a48e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysMenuCreateDTO.java @@ -0,0 +1,101 @@ +package com.sz.admin.system.pojo.dto.sysmenu; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * SysMenuAddDTO + * + * @author sz + * @since 2023/8/21 + */ +@Data +@Schema(description = "菜单添加") +public class SysMenuCreateDTO { + + @Schema(description = "菜单id(修改菜单时必填)") + private String id; + + @NotNull(message = "菜单名称不能为空") + @Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String title; + + /** + * 父级id + */ + private String pid; + + /** + * 路径 + */ + private String path; + + private String name; + + /** + * icon图标 + */ + private String icon; + + /** + * 组件路径 + */ + private String component; + + /** + * redirect地址 + */ + private String redirect; + + /** + * 排序 + */ + private Integer sort; + + /** + * 层级 + */ + private Integer deep; + + /** + * 菜单类型 (字典表menu_type) + */ + private String menuTypeCd; + + /** + * 按钮权限 + */ + private String permissions; + + /** + * 是否隐藏 + */ + private String isHidden; + + /** + * 是否有子级 + */ + private String hasChildren; + + /** + * 路由外链时填写的访问地址 + */ + private String isLink; + + /** + * 菜单是否全屏 + */ + private String isFull; + + /** + * 菜单是否固定在标签页 + */ + private String isAffix; + + /** + * 当前路由是否缓存 + */ + private String isKeepAlive; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysMenuListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysMenuListDTO.java new file mode 100644 index 0000000..10c42c6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysMenuListDTO.java @@ -0,0 +1,17 @@ +package com.sz.admin.system.pojo.dto.sysmenu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SysMenuQueryDTO + * + * @author sz + * @since 2023/8/21 + */ +@Data +public class SysMenuListDTO { + + @Schema(description = "是否查询按钮") + private boolean isShowButton = true; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysUserRoleDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysUserRoleDTO.java new file mode 100644 index 0000000..2972735 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmenu/SysUserRoleDTO.java @@ -0,0 +1,24 @@ +package com.sz.admin.system.pojo.dto.sysmenu; + +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2023/8/28 15:49 + */ +@Data +@Schema(description = "用户角色变更") +public class SysUserRoleDTO { + + @Schema(description = "角色id数组") + private List roleIds; + + @NotZero(message = "用户id不能为空") + @Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED) + private Long userId; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/Message.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/Message.java new file mode 100644 index 0000000..458169a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/Message.java @@ -0,0 +1,31 @@ +package com.sz.admin.system.pojo.dto.sysmessage; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Schema(description = "SysMessage添加DTO") +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Message { + + @Schema(description = "消息类型") + private String messageTypeCd; + + @Schema(description = "发送人ID") + private Long senderId; + + @Schema(description = "消息标题") + private String title; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "接收人id") + private List receiverIds; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/PayloadBody.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/PayloadBody.java new file mode 100644 index 0000000..030f34d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/PayloadBody.java @@ -0,0 +1,24 @@ +package com.sz.admin.system.pojo.dto.sysmessage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * PayloadBody - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/4/21 + */ +@Data +public class PayloadBody { + + @Schema(description = "标题") + private String title; + + @Schema(description = "消息内容") + private String content; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/SysMessageListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/SysMessageListDTO.java new file mode 100644 index 0000000..7553886 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysmessage/SysMessageListDTO.java @@ -0,0 +1,29 @@ +package com.sz.admin.system.pojo.dto.sysmessage; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

+ * SysMessage查询DTO + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Data +@Schema(description = "SysMessage查询DTO") +public class SysMessageListDTO extends PageQuery { + + public SysMessageListDTO(String messageTypeCd) { + this.messageTypeCd = messageTypeCd; + } + + @Schema(description = "消息类型", allowableValues = {"", "msg", "todo"}) + private String messageTypeCd; + + @Schema(description = "已读未读", allowableValues = {"", "read", "unread"}) + private String readType; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleCreateDTO.java new file mode 100644 index 0000000..e5a8a2a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleCreateDTO.java @@ -0,0 +1,26 @@ +package com.sz.admin.system.pojo.dto.sysrole; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2023/8/24 15:28 + */ +@Data +@Schema(description = "角色添加") +public class SysRoleCreateDTO { + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "标识") + private String permissions; + + @Schema(description = "数据权限范围") + private String dataScopeCd; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleListDTO.java new file mode 100644 index 0000000..d2489a5 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleListDTO.java @@ -0,0 +1,18 @@ +package com.sz.admin.system.pojo.dto.sysrole; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2023/8/24 15:28 + */ +@Data +@Schema(description = "角色查询") +public class SysRoleListDTO extends PageQuery { + + @Schema(description = "角色名称") + private String roleName; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleUpdateDTO.java new file mode 100644 index 0000000..01e4a4d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrole/SysRoleUpdateDTO.java @@ -0,0 +1,31 @@ +package com.sz.admin.system.pojo.dto.sysrole; + +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2023/8/24 15:28 + */ +@Data +@Schema(description = "角色添加") +public class SysRoleUpdateDTO { + + @NotZero + @Schema(description = "角色id", requiredMode = Schema.RequiredMode.REQUIRED) + private Long id; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "标识") + private String permissions; + + @Schema(description = "数据权限范围") + private String dataScopeCd; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrolemenu/SysRoleMenuDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrolemenu/SysRoleMenuDTO.java new file mode 100644 index 0000000..da5714e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysrolemenu/SysRoleMenuDTO.java @@ -0,0 +1,51 @@ +package com.sz.admin.system.pojo.dto.sysrolemenu; + +import com.sz.core.common.valid.annotation.NotZero; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2023/8/28 15:49 + */ +@Data +@Schema(description = "角色菜单变更") +public class SysRoleMenuDTO { + + @NotZero(message = "角色id不能为空") + @Schema(description = "角色id", requiredMode = Schema.RequiredMode.REQUIRED) + private Long roleId; + + @Schema(description = "功能权限配置") + private Menu menu; + + @Schema(description = "数据权限配置") + private List scope; + + @Data + public static class Scope { + + @Schema(description = "数据权限范围") + private String dataScope; + + @Schema(description = "部门id数组") + private List deptIds; + + @Schema(description = "用户id数组") + private List userIds; + + @Schema(description = "菜单id") + private String menuId; + + } + + @Data + public static class Menu { + + @Schema(description = "菜单id数组") + private List menuIds; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileCreateDTO.java new file mode 100644 index 0000000..9db4f3e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileCreateDTO.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.pojo.dto.systempfile; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + *

+ * SysTempFile添加DTO + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Schema(description = "SysTempFile添加DTO") +public class SysTempFileCreateDTO { + + @Schema(description = "文件ID") + private Long sysFileId; + + @Schema(description = "模版名") + private String tempName; + + @Schema(description = "地址") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "标识") + private String alias; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileHistoryCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileHistoryCreateDTO.java new file mode 100644 index 0000000..fafbb40 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileHistoryCreateDTO.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.pojo.dto.systempfile; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + *

+ * SysTempFile添加DTO + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Schema(description = "SysTempFileHistory添加DTO") +public class SysTempFileHistoryCreateDTO { + + @Schema(description = "模板文件ID") + private Long sysTempFileId; + + @Schema(description = "文件ID") + private Long sysFileId; + + @Schema(description = "模版名") + private String tempName; + + @Schema(description = "地址") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileHistoryListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileHistoryListDTO.java new file mode 100644 index 0000000..ec4b5f4 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileHistoryListDTO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.dto.systempfile; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

+ * SysTempFileHistory查询DTO + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Schema(description = "SysTempFileHistory查询DTO") +public class SysTempFileHistoryListDTO extends PageQuery { + + @Schema(description = "模板文件ID") + private Long sysTempFileId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileListDTO.java new file mode 100644 index 0000000..4e3b212 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileListDTO.java @@ -0,0 +1,21 @@ +package com.sz.admin.system.pojo.dto.systempfile; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.sz.core.common.entity.PageQuery; +/** + *

+ * SysTempFile查询DTO + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Schema(description = "SysTempFile查询DTO") +public class SysTempFileListDTO extends PageQuery { + + @Schema(description = "模版名") + private String tempName; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileUpdateDTO.java new file mode 100644 index 0000000..3d72dc6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/systempfile/SysTempFileUpdateDTO.java @@ -0,0 +1,42 @@ +package com.sz.admin.system.pojo.dto.systempfile; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + *

+ * SysTempFile修改DTO + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Schema(description = "SysTempFile修改DTO") +public class SysTempFileUpdateDTO { + + @Schema(description = "ID") + private Long id; + + @Schema(description = "文件ID") + private Long sysFileId; + + @Schema(description = "模版名") + private String tempName; + + @Schema(description = "地址") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "标识") + private String alias; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/RegisterUserDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/RegisterUserDTO.java new file mode 100644 index 0000000..785d954 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/RegisterUserDTO.java @@ -0,0 +1,27 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2023/5/22 8:25 + * + */ +@Data +@Schema(description = "用户注册") +public class RegisterUserDTO { + + @Schema(description = "用户名", name = "username", example = "admin", requiredMode = Schema.RequiredMode.REQUIRED) + private String username; + + @Schema(description = "密码", name = "pwd", example = "admin123", requiredMode = Schema.RequiredMode.REQUIRED) + private String pwd; + + @Schema(description = "手机号", example = "15330331111") + private String phone; + + @Schema(description = "昵称") + private String nickName; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserCreateDTO.java new file mode 100644 index 0000000..cb48157 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserCreateDTO.java @@ -0,0 +1,51 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SysUserCreateDTO + * + * @author sz + * @since 2023/8/23 + */ +@Data +@Schema(description = "SysUser添加DTO") +public class SysUserCreateDTO { + + @Schema(description = "账户", requiredMode = Schema.RequiredMode.REQUIRED) + private String username; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "头像") + private String logo; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "性别") + private Integer sex; + + @Schema(description = "身份证") + private String idCard; + + @Schema(description = "邮箱地址") + private String email; + + @Schema(description = "状态") + private String accountStatusCd; + + @Schema(description = "标签") + private String userTagCd; + + @Schema(description = "生日") + private String birthday; + + @Schema(description = "部门ID") + private Long deptId = -1L; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserListDTO.java new file mode 100644 index 0000000..d90f311 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserListDTO.java @@ -0,0 +1,31 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import com.sz.core.common.entity.PageQuery; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SysUserQueryDTO + * + * @author sz + * @since 2023/8/23 + */ +@Data +public class SysUserListDTO extends PageQuery { + + @Schema(description = "账户") + private String username; + + @Schema(description = "姓名") + private String nickname; + + @Schema(description = "部门列表。0查询全部,-1 查询未分配部门的用户") + private Long deptId; + + @Schema(description = "是否只查询当前层级") + private Boolean isThisDeep; + + @Schema(description = "电话") + private String phone; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserPasswordDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserPasswordDTO.java new file mode 100644 index 0000000..182306d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserPasswordDTO.java @@ -0,0 +1,20 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SysUserPasswordDTO + * + * @author sz + * @since 2023/8/30 + */ +@Data +public class SysUserPasswordDTO { + + @Schema(description = "原始密码") + private String oldPwd; + + @Schema(description = "新密码") + private String newPwd; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserTagDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserTagDTO.java new file mode 100644 index 0000000..4b20513 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserTagDTO.java @@ -0,0 +1,18 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +@Data +@Schema(description = "用户类型") +public class SysUserTagDTO { + + @Schema(description = "用户ID") + private List userIds; + + @Schema(description = "用户类型") + private String userTagCd; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserUpdateDTO.java new file mode 100644 index 0000000..eb58350 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SysUserUpdateDTO.java @@ -0,0 +1,48 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SysUserUpdateDTO + * + * @author sz + * @since 2023/8/23 + */ +@Data +@Schema(description = "SysUser修改DTO") +public class SysUserUpdateDTO { + + @Schema(description = "用户id") + private Long id; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "头像") + private String logo; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "性别") + private Integer sex; + + @Schema(description = "身份证") + private String idCard; + + @Schema(description = "邮箱地址") + private String email; + + @Schema(description = "状态") + private String accountStatusCd; + + @Schema(description = "标签") + private String userTagCd; + + @Schema(description = "生日") + private String birthday; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SystemLoginDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SystemLoginDTO.java new file mode 100644 index 0000000..e340709 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/SystemLoginDTO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2022/5/21 19:30 + * + */ + +@Schema(description = "描述信息") +@Data +public class SystemLoginDTO { + + @Schema(description = "用户名", type = "String", name = "username", example = "admin", requiredMode = Schema.RequiredMode.REQUIRED) + private String username; + + @Schema(description = "密码", type = "String", name = "password", example = "admin", requiredMode = Schema.RequiredMode.REQUIRED) + private String password; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/UserDeptDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/UserDeptDTO.java new file mode 100644 index 0000000..6f99528 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/dto/sysuser/UserDeptDTO.java @@ -0,0 +1,24 @@ +package com.sz.admin.system.pojo.dto.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * UserDeptDTO + * + * @author sz + * @since 2024/4/2 9:44 + * @version 1.0 + */ +@Data +public class UserDeptDTO { + + @Schema(description = "用户id数组") + private List userIds = new ArrayList<>(); + + @Schema(description = "部门id数组") + private List deptIds = new ArrayList<>(); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/Product.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/Product.java new file mode 100644 index 0000000..e4f5b90 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/Product.java @@ -0,0 +1,48 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.io.Serial; + +import com.sz.mysql.EntityChangeListener; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + *

+ * 商品信息表 + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Data +@Table(value = "sys_product", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "商品信息表") +public class Product implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "主键ID") + private Long id; + + @Schema(description = "商品名称") + private String productName; + + @Schema(description = "价格") + private BigDecimal price; + + @Schema(description = "状态(0停用 1启用)") + private Integer status; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysClient.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysClient.java new file mode 100644 index 0000000..3daa214 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysClient.java @@ -0,0 +1,77 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +/** + *

+ * 系统授权表 + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Data +@Table(value = "sys_client", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "系统授权表") +public class SysClient implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id + @Schema(description = "客户端id") + private String clientId; + + @Schema(description = "客户端key") + private String clientKey; + + @Schema(description = "客户端秘钥") + private String clientSecret; + + @Schema(description = "授权类型") + private String grantTypeCd; + + @Schema(description = "设备类型") + private String deviceTypeCd; + + @Schema(description = "token活跃超时时间") + private Integer activeTimeout; + + @Schema(description = "token固定超时") + private Integer timeout; + + @Schema(description = "状态") + private String clientStatusCd; + + @Schema(description = "删除标志") + private String delFlag; + + @Schema(description = "创建部门") + private Integer createDept; + + @Schema(description = "创建者") + private Long createId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新者") + private Long updateId; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否锁定") + private String isLock; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysConfig.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysConfig.java new file mode 100644 index 0000000..95a5f43 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysConfig.java @@ -0,0 +1,60 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.platform.listener.TableSysConfigListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 参数配置表 + *

+ * + * @author sz + * @since 2023-11-23 + */ + +@Data +@Table(value = "sys_config", onInsert = TableSysConfigListener.class, onUpdate = TableSysConfigListener.class) +@Schema(description = "参数配置表") +public class SysConfig implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "id") + private Long id; + + @Schema(description = "参数名") + private String configName; + + @Schema(description = "参数key") + private String configKey; + + @Schema(description = "参数value") + private String configValue; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否锁定") + private String isLock; + + @Schema(description = "该参数是否需要前端加载、缓存及使用") + private String frontendVisible; + + private Long createId; + + private LocalDateTime createTime; + + private Long updateId; + + private LocalDateTime updateTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRole.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRole.java new file mode 100644 index 0000000..4469c87 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRole.java @@ -0,0 +1,63 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +/** + *

+ * 数据权限管理 + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Data +@Table(value = "sys_data_role", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "数据权限管理") +@Deprecated(since = "v1.4.0-beta") +public class SysDataRole implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "角色id") + private Long id; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "数据范围") + private String dataScopeCd; + + @Schema(description = "简介") + private String remark; + + @Column(isLogicDelete = true) + @Schema(description = "删除与否") + private String delFlag; + + @Schema(description = "是否锁定") + private String isLock; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建人") + private Long createId; + + @Schema(description = "更新人") + private Long updateId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRoleMenu.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRoleMenu.java new file mode 100644 index 0000000..58302b9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRoleMenu.java @@ -0,0 +1,37 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.*; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +/** + *

+ * 系统数据角色-菜单表 + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +@Data +@Table(value = "sys_data_role_menu") +@Schema(description = "系统数据角色-菜单表") +@Deprecated(since = "v1.4.0-beta") +public class SysDataRoleMenu implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "sys_data_role_id (数据角色表)") + private Long roleId; + + @Schema(description = "sys_menu_id (菜单表)") + private String menuId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRoleRelation.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRoleRelation.java new file mode 100644 index 0000000..4a85f78 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDataRoleRelation.java @@ -0,0 +1,44 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + *

+ * 系统数据角色-关联表 + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +@Data +@Table(value = "sys_data_role_relation") +@Schema(description = "系统数据角色-关联表") +public class SysDataRoleRelation implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "sys_role id(数据角色表)") + private Long roleId; + + @Schema(description = "关联类型,data_scope_relation_type") + private String relationTypeCd; + + @Schema(description = "关联表id,联动relation_type_cd") + private Long relationId; + + @Schema(description = "sys_menu id") + private String menuId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDept.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDept.java new file mode 100644 index 0000000..e9457ac --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDept.java @@ -0,0 +1,72 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.platform.listener.TableSysDeptListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 部门表 + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Data +@Table(value = "sys_dept", onInsert = TableSysDeptListener.class, onUpdate = TableSysDeptListener.class) +@Schema(description = "部门表") +public class SysDept implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "id") + private Long id; + + @Schema(description = "部门名称") + private String name; + + @Schema(description = "父级id") + private Long pid; + + @Schema(description = "层级") + private Integer deep; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "是否有子级") + private String hasChildren; + + @Schema(description = "是否锁定") + private String isLock; + + @Column(isLogicDelete = true) + @Schema(description = "删除标识") + private String delFlag; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建人") + private Long createId; + + @Schema(description = "更新人") + private Long updateId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptClosure.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptClosure.java new file mode 100644 index 0000000..750b904 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptClosure.java @@ -0,0 +1,36 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +/** + *

+ * 部门祖籍关系表 + *

+ * + * @author sz + * @since 2024-03-28 + */ +@Data +@Table(value = "sys_dept_closure") +@Schema(description = "部门祖籍关系表") +public class SysDeptClosure implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id + @Schema(description = "祖先节点ID") + private Long ancestorId; + + @Schema(description = "后代节点ID") + private Long descendantId; + + @Schema(description = "祖先节点到后代节点的距离") + private Integer depth; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptLeader.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptLeader.java new file mode 100644 index 0000000..cccbf73 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptLeader.java @@ -0,0 +1,37 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +/** + *

+ * 部门领导人表 + *

+ * + * @author sz + * @since 2024-03-26 + */ +@Data +@Table(value = "sys_dept_leader") +@Schema(description = "部门领导人表") +public class SysDeptLeader implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "dept_id") + private Long deptId; + + @Schema(description = "sys_user_id") + private Long leaderId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptRole.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptRole.java new file mode 100644 index 0000000..b682ef8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDeptRole.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; + +/** + *

+ * 系统部门-角色关联表 + *

+ * + * @author sz + * @since 2025-07-15 + */ +@Getter +@Setter +@Table("sys_dept_role") +@Schema(description = "系统部门-角色关联表") +public class SysDeptRole implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "id") + private Long id; + + @Schema(description = "角色id (sys_role_id)") + private Long roleId; + + @Schema(description = " 部门id(sys_dept_id)") + private Long deptId; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDict.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDict.java new file mode 100644 index 0000000..413d7c4 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDict.java @@ -0,0 +1,81 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.core.common.enums.TrueFalseEnum; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 字典表 + *

+ * + * @author sz + * @since 2023-08-20 + */ +@Data +@Table(value = "sys_dict", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "字典表") +public class SysDict implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "字典id(规则)") + private Long id; + + @Schema(description = "关联sys_dict_type id") + private Long sysDictTypeId; + + @Schema(description = "字典名称") + private String codeName; + + @Schema(description = "字典别名") + private String alias; + + @Schema(description = "排序(正序)") + private Integer sort; + + @Schema(description = "回显样式") + private String callbackShowStyle; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否锁定") + private TrueFalseEnum isLock; + + @Schema(description = "是否展示") + private TrueFalseEnum isShow; + + @Schema(description = "是否删除") + @Column(isLogicDelete = true) + private TrueFalseEnum delFlag; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "删除时间") + private LocalDateTime deleteTime; + + @Schema(description = "创建人ID") + private Long createId; + + @Schema(description = "更新人ID") + private Long updateId; + + @Schema(description = "删除人ID") + private Long deleteId; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDictType.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDictType.java new file mode 100644 index 0000000..120cab5 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysDictType.java @@ -0,0 +1,75 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.core.common.enums.TrueFalseEnum; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 字典类型 + *

+ * + * @author sz + * @since 2023-08-18 + */ +@Data +@Table(value = "sys_dict_type", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "字典类型") +public class SysDictType implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "字典类型id") + private Long id; + + @Schema(description = "字典类型名(中文)") + private String typeName; + + @Schema(description = "字典类型码(英文)") + private String typeCode; + + @Schema(description = "是否锁定,锁定的属性无法在页面进行修改") + private TrueFalseEnum isLock; + + @Schema(description = "显示与否") + private TrueFalseEnum isShow; + + @Schema(description = "是否删除") + @Column(isLogicDelete = true) + private TrueFalseEnum delFlag; + + @Schema(description = "描述") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "删除时间") + private LocalDateTime deleteTime; + + @Schema(description = "创建人ID") + private Long createId; + + @Schema(description = "更新人ID") + private Long updateId; + + @Schema(description = "删除人ID") + private Long deleteId; + + @Schema(description = "字典类型: system 系统, business 业务") + private String type; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysFile.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysFile.java new file mode 100644 index 0000000..47ea0bb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysFile.java @@ -0,0 +1,63 @@ +package com.sz.admin.system.pojo.po; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 文件表 + *

+ * + * @author sz-admin + * @since 2024-11-25 + */ +@Data +@Table(value = "sys_file", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "文件表") +public class SysFile implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "文件ID") + private Long id; + + @Schema(description = "文件名") + private String filename; + + @Schema(description = "目录标识") + private String dirTag; + + @Schema(description = "文件大小") + private Long size; + + @Schema(description = "文件域名") + private String url; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "对象名(唯一)") + private String objectName; + + @Schema(description = "文件类型") + private String contextType; + + @JsonProperty(value = "eTag") + @Schema(description = "eTag标识") + private String eTag; + + @Schema(description = "创建人") + private Long createId; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysLoginLog.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysLoginLog.java new file mode 100644 index 0000000..3304c84 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysLoginLog.java @@ -0,0 +1,64 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.*; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.io.Serializable; +import java.io.Serial; +import com.sz.mysql.EntityChangeListener; +import java.time.LocalDateTime; + +/** + *

+ * 登陆日志表 + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +@Data +@Accessors(chain = true) +@Table(value = "sys_login_log", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "登陆日志表") +public class SysLoginLog implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "登陆ID") + private Integer id; + + @Column(isLogicDelete = true) + @Schema(description = "删除标识") + private String delFlag; + + @Schema(description = "用户名") + private String userName; + + @Schema(description = "登陆状态") + private String loginStatus; + + @Schema(description = "登陆时间") + private LocalDateTime loginTime; + + @Schema(description = "登陆ip地址") + private String ipAddress; + + @Schema(description = "登陆地点") + private String loginLocation; + + @Schema(description = "浏览器类型") + private String browser; + + @Schema(description = "操作系统") + private String os; + + @Schema(description = "提示消息") + private String msg; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMenu.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMenu.java new file mode 100644 index 0000000..ae6b220 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMenu.java @@ -0,0 +1,105 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 系统菜单表 + *

+ * + * @author sz + * @since 2023-08-21 + */ +@Data +@Table("sys_menu") +@Schema(description = "系统菜单表") +public class SysMenu implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id + @Schema(description = "菜单表id") + private String id; + + @Schema(description = "父级id") + private String pid; + + @Schema(description = "路径") + private String path; + + @Schema(description = "name") + private String name; + + @Schema(description = "title") + private String title; + + @Schema(description = "icon图标") + private String icon; + + @Schema(description = "组件路径") + private String component; + + @Schema(description = "redirect地址") + private String redirect; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "层级") + private Integer deep; + + @Schema(description = "菜单类型 (字典表menu_type)") + private String menuTypeCd; + + @Schema(description = "按钮权限") + private String permissions; + + @Schema(description = "是否隐藏") + private String isHidden; + + @Schema(description = "是否有子级") + private String hasChildren; + + @Schema(description = "路由外链时填写的访问地址") + private String isLink; + + @Schema(description = "菜单是否全屏") + private String isFull; + + @Schema(description = "菜单是否固定在标签页") + private String isAffix; + + @Schema(description = "当前路由是否缓存") + private String isKeepAlive; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + @Schema(description = "创建人") + private Long createId; + + @Schema(description = "更新人") + private Long updateId; + + @Schema(description = "删除与否") + @Column(isLogicDelete = true) + private String delFlag; + + @Schema(description = "菜单是否开启数据权限") + private String useDataScope; + + @Schema(description = "删除人ID") + private Long deleteId; + + private LocalDateTime deleteTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMessage.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMessage.java new file mode 100644 index 0000000..197eddc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMessage.java @@ -0,0 +1,61 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.*; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import lombok.Data; + +/** + *

+ * 消息管理 + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Data +@Table(value = "sys_message", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "消息管理") +public class SysMessage implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "消息ID") + private Long id; + + @Schema(description = "消息类型") + private String messageTypeCd; + + @Schema(description = "发送人ID") + private Long senderId; + + @Schema(description = "消息标题") + private String title; + + @Schema(description = "消息内容") + private String content; + + @Column(isLogicDelete = true) + @Schema(description = "删除标识") + private String delFlag; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建人 ID") + private Long createId; + + @Schema(description = "更新人 ID") + private Long updateId; + + @Schema(description = "菜单路由地址") + private String menuRouter; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMessageUser.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMessageUser.java new file mode 100644 index 0000000..33cc53d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysMessageUser.java @@ -0,0 +1,46 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.*; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import lombok.Data; + +/** + *

+ * 消息接收用户表 + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Data +@Table(value = "sys_message_user", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "消息接收用户表") +public class SysMessageUser implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "消息ID") + private Long messageId; + + @Schema(description = "接收人ID") + private Long receiverId; + + @Schema(description = "是否已读") + private String isRead; + + @Schema(description = "阅读时间") + private LocalDateTime readTime; + + @Column(isLogicDelete = true) + @Schema(description = "删除标识") + private String delFlag; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysRole.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysRole.java new file mode 100644 index 0000000..86fe124 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysRole.java @@ -0,0 +1,63 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.platform.listener.TableSysRoleListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 系统角色表 + *

+ * + * @author sz + * @since 2023-08-21 + */ + +@Data +@Table(value = "sys_role", onInsert = TableSysRoleListener.class, onUpdate = TableSysRoleListener.class) +@Schema(description = "系统角色表") +public class SysRole implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "角色id") + private Long id; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "简介") + private String remark; + + @Column(isLogicDelete = true) + @Schema(description = "删除与否") + private String delFlag; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建人ID") + private Long createId; + + @Schema(description = "更新人ID") + private Long updateId; + + @Schema(description = "是否锁定") + private String isLock; + + @Schema(description = "标识,唯一") + private String permissions; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysRoleMenu.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysRoleMenu.java new file mode 100644 index 0000000..815ff19 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysRoleMenu.java @@ -0,0 +1,43 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + *

+ * 系统角色-菜单表 + *

+ * + * @author sz + * @since 2023-08-21 + */ +@Data +@Table("sys_role_menu") +@Schema(description = "系统角色-菜单表") +public class SysRoleMenu implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id + @Schema(description = "id") + private Long id; + + @Schema(description = "sys_menu_id (菜单表)") + private String menuId; + + @Schema(description = "sys_role_id (角色表)") + private Long roleId; + + @Schema(description = "权限类型(功能权限;数据权限)") + private String permissionType; + + @Schema(description = "数据权限范围") + private String dataScopeCd; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysTempFile.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysTempFile.java new file mode 100644 index 0000000..3456061 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysTempFile.java @@ -0,0 +1,66 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.*; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.io.Serializable; +import java.io.Serial; +import com.sz.mysql.EntityChangeListener; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 模版文件表 + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Table(value = "sys_temp_file", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "模版文件表") +public class SysTempFile implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "文件ID") + private Long sysFileId; + + @Schema(description = "模版名") + private String tempName; + + @Schema(description = "地址") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "备注") + private String remark; + + @Column(isLogicDelete = true) + @Schema(description = "逻辑删除") + private String delFlag; + + @Schema(description = "创建人") + private Long createId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新人") + private Long updateId; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "标识") + private String alias; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysTempFileHistory.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysTempFileHistory.java new file mode 100644 index 0000000..532819d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysTempFileHistory.java @@ -0,0 +1,62 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.*; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.io.Serializable; +import java.io.Serial; +import com.sz.mysql.EntityChangeListener; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 模版文件历史 + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Table(value = "sys_temp_file_history", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "模版文件历史") +public class SysTempFileHistory implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "模版文件ID") + private Integer sysTempFileId; + + @Schema(description = "文件ID") + private Integer sysFileId; + + @Schema(description = "模版名") + private String tempName; + + @Schema(description = "地址") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建人") + private Long createId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新人") + private Long updateId; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUser.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUser.java new file mode 100644 index 0000000..38e1629 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUser.java @@ -0,0 +1,90 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.platform.listener.TableSysUserListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + *

+ * 系统用户表 + *

+ * + * @author sz + * @since 2023-08-24 + */ +@Data +@Table(value = "sys_user", onInsert = TableSysUserListener.class, onUpdate = TableSysUserListener.class) +@Schema(description = "系统用户表") +public class SysUser implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "id") + private Long id; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "密码") + private String pwd; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "性别(0 未知 1 男 2 女)") + private Integer sex; + + @Schema(description = "生日") + private String birthday; + + @Schema(description = "头像地址") + private String logo; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "身份证") + private String idCard; + + @Schema(description = "邮箱地址") + private String email; + + @Schema(description = "账户状态 (如 冻结;禁言;正常。 关联字典表account_status)") + private String accountStatusCd; + + @Schema(description = "标签(自定义关联到字典表)") + private String userTagCd; + + @Schema(description = "最近一次登录时间") + private LocalDateTime lastLoginTime; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Column(isLogicDelete = true) + @Schema(description = "是否删除") + private String delFlag; + + @Schema(description = "创建人") + private Long createId; + + @Schema(description = "更新人") + private Long updateId; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserDataRole.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserDataRole.java new file mode 100644 index 0000000..958f3af --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserDataRole.java @@ -0,0 +1,37 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +/** + *

+ * 系统用户-数据角色关联表 + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +@Data +@Table(value = "sys_user_data_role") +@Schema(description = "系统用户-数据角色关联表") +public class SysUserDataRole implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "数据角色id (sys_data_role_id)") + private Long roleId; + + @Schema(description = "用户id(sys_user_id)") + private Long userId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserDept.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserDept.java new file mode 100644 index 0000000..0f6513f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserDept.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import com.sz.mysql.EntityChangeListener; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + *

+ * 用户-部门关系表 + *

+ * + * @author sz + * @since 2024-04-02 + */ +@Data +@Table(value = "sys_user_dept", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "用户-部门关系表") +public class SysUserDept implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Long id; + + @Schema(description = "sys_dept_id") + private Long deptId; + + @Schema(description = "sys_user_id") + private Long userId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserRole.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserRole.java new file mode 100644 index 0000000..e2d300a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/po/SysUserRole.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.pojo.po; + +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.KeyType; +import com.mybatisflex.annotation.Table; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serial; +import java.io.Serializable; + +/** + *

+ * 系统用户-角色关联表 + *

+ * + * @author sz + * @since 2023-08-29 + */ +@Getter +@Setter +@Table("sys_user_role") +@Schema(description = "系统用户-角色关联表") +public class SysUserRole implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "id") + private Long id; + + @Schema(description = "角色id (sys_role_id)") + private Long roleId; + + @Schema(description = " 用户id(sys_user_id)") + private Long userId; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/ProductVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/ProductVO.java new file mode 100644 index 0000000..024d275 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/ProductVO.java @@ -0,0 +1,47 @@ +package com.sz.admin.system.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * Product返回vo + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Data +@Schema(description = "Product返回vo") +public class ProductVO { + + @ExcelIgnore + @Schema(description = "主键ID") + private Long id; + + @ExcelProperty(value = "商品名称") + @Schema(description = "商品名称") + private String productName; + + @ExcelProperty(value = "价格") + @Schema(description = "价格") + private BigDecimal price; + + @ExcelProperty(value = "状态(0停用 1启用)") + @Schema(description = "状态(0停用 1启用)") + private Integer status; + + @ExcelProperty(value = "创建时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/SysLoginLogVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/SysLoginLogVO.java new file mode 100644 index 0000000..15e47f3 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/SysLoginLogVO.java @@ -0,0 +1,67 @@ +package com.sz.admin.system.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.experimental.Accessors; +import java.time.LocalDateTime; +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import com.sz.excel.annotation.DictFormat; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * SysLoginLog返回vo + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +@Data +@Accessors(chain = true) +@Schema(description = "SysLoginLog返回vo") +public class SysLoginLogVO { + + @ExcelIgnore + @Schema(description = "登陆ID") + private Integer id; + + @ExcelProperty(value = "用户名") + @Schema(description = "用户名") + private String userName; + + @ExcelProperty(value = "登陆状态") + @DictFormat(dictType = "login_status") + @Schema(description = "登陆状态") + private String loginStatus; + + @ExcelProperty(value = "登陆时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "登陆时间") + private LocalDateTime loginTime; + + @ExcelProperty(value = "登陆ip地址") + @Schema(description = "登陆ip地址") + private String ipAddress; + + @ExcelProperty(value = "登陆地点") + @Schema(description = "登陆地点") + private String loginLocation; + + @ExcelProperty(value = "浏览器类型") + @Schema(description = "浏览器类型") + private String browser; + + @ExcelProperty(value = "操作系统") + @Schema(description = "操作系统") + private String os; + + @ExcelProperty(value = "提示消息") + @Schema(description = "提示消息") + private String msg; + + @ExcelProperty(value = "备注") + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/ChallengeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/ChallengeVO.java new file mode 100644 index 0000000..28dae6d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/ChallengeVO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.vo.common; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Data +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "一次性认证返回信息") +public class ChallengeVO { + + @Schema(description = "请求id") + private String requestId; + + @Schema(description = "加密key") + private String secretKey; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/DepartmentVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/DepartmentVO.java new file mode 100644 index 0000000..3eec029 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/DepartmentVO.java @@ -0,0 +1,42 @@ +package com.sz.admin.system.pojo.vo.common; + +import com.sz.core.common.service.Treeable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * DepartmentVO - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/6 + */ +@Schema(description = "部门信息返回VO") +@Data +public class DepartmentVO implements Treeable { + + @Schema(description = "部门ID") + private Object id; + + @Schema(description = "父级部门ID") + private Object pid; + + @Schema(description = "部门名称") + private String name; + + @Schema(description = "子级部门列表") + private List children = new ArrayList<>(); + + @Schema(description = "层级") + private Long deep; + + @Schema(description = "排序") + private Long sort; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/RoleVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/RoleVO.java new file mode 100644 index 0000000..3261e83 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/RoleVO.java @@ -0,0 +1,28 @@ +package com.sz.admin.system.pojo.vo.common; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * RoleVO - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/6 + */ +@Data +public class RoleVO { + + @Schema(description = "角色ID") + private Object id; + + @Schema(description = "角色名称") + private String name; + + @Schema(description = "角色编码") + private String permissions; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/SelectorVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/SelectorVO.java new file mode 100644 index 0000000..7b8d963 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/SelectorVO.java @@ -0,0 +1,26 @@ +package com.sz.admin.system.pojo.vo.common; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * SelectorVO - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/6 + */ +@Schema(description = "多维选择器返回VO") +@Data +public class SelectorVO { + + @Schema(description = "类型", allowableValues = {"user", "role", "department"}, requiredMode = Schema.RequiredMode.REQUIRED) + private String type; + + @Schema(description = "结果数据") + private Object data; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/UserVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/UserVO.java new file mode 100644 index 0000000..c4269f0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/common/UserVO.java @@ -0,0 +1,29 @@ +package com.sz.admin.system.pojo.vo.common; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * UserVO -用户信息返回VO + * + * @author sz + * @version 1.0 + * @since 2025/7/6 + */ +@Schema(description = "用户信息返回VO") +@Data +public class UserVO { + + @Schema(description = "用户ID") + private Object id; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "用户昵称") + private String name; + + @Schema(description = "用户手机号") + private String phone; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysclient/SysClientVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysclient/SysClientVO.java new file mode 100644 index 0000000..27742a7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysclient/SysClientVO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.vo.sysclient; + +import com.sz.security.pojo.ClientVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

+ * SysClient查询返回 + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Data +@Schema(description = "SysClient返回vo") +public class SysClientVO extends ClientVO { + + @Schema(description = "是否锁定") + private String isLock; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysconfig/ConfigVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysconfig/ConfigVO.java new file mode 100644 index 0000000..9c7904e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysconfig/ConfigVO.java @@ -0,0 +1,19 @@ +package com.sz.admin.system.pojo.vo.sysconfig; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "前端Config返回vo") +public class ConfigVO { + + @Schema(description = "参数名") + private String configName; + + @Schema(description = "参数值") + private String configValue; + + @Schema(description = "参数Key") + private String configKey; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatarole/SysDataRoleMenuVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatarole/SysDataRoleMenuVO.java new file mode 100644 index 0000000..fc9fde6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatarole/SysDataRoleMenuVO.java @@ -0,0 +1,33 @@ +package com.sz.admin.system.pojo.vo.sysdatarole; + +import com.sz.admin.system.pojo.vo.sysdept.DeptTreeVO; +import com.sz.admin.system.pojo.vo.sysmenu.MenuTreeVO; +import com.sz.admin.system.pojo.vo.sysuser.UserOptionVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + *

+ * SysDataRole返回vo + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataRole返回vo") +public class SysDataRoleMenuVO { + + @Schema(description = "菜单列表") + private List menuLists; + + @Schema(description = "部门列表") + private List deptLists; + + @Schema(description = "用户列表") + private List userOptions; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatarole/SysDataRoleVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatarole/SysDataRoleVO.java new file mode 100644 index 0000000..d4d1de7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatarole/SysDataRoleVO.java @@ -0,0 +1,52 @@ +package com.sz.admin.system.pojo.vo.sysdatarole; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * SysDataRole返回vo + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataRole返回vo") +public class SysDataRoleVO { + + @Schema(description = "角色id") + private Long id; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "数据范围") + private String dataScopeCd; + + @Schema(description = "简介") + private String remark; + + @Schema(description = "是否锁定") + private String isLock; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "选中的菜单id数组") + private List selectMenuIds; + + @Schema(description = "选中的部门id数组") + private List selectDeptIds; + + @Schema(description = "(自定义)选中的用户id数组") + private List userOptions; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatascope/SysDataScopeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatascope/SysDataScopeVO.java new file mode 100644 index 0000000..5abb280 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdatascope/SysDataScopeVO.java @@ -0,0 +1,44 @@ +package com.sz.admin.system.pojo.vo.sysdatascope; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * SysDataScopeVO + * + * @author sz + * @since 2024/6/27 13:26 + * @version 1.0 + */ +@Deprecated(since = "v1.4.0-beta") +@Data +@Schema(description = "SysDataScope返回vo") +public class SysDataScopeVO { + + @Schema(description = "ID") + private Long id; + + @Schema(description = "关联类型,data_scope_relation_type") + private String relationTypeCd; + + @Schema(description = "关联表id") + + private Long relationId; + + @Schema(description = "数据权限") + private String dataScope; + + @Schema(description = "关联部门") + @Column(typeHandler = JacksonTypeHandler.class) + private List deptOptions = new ArrayList<>(); + + @Schema(description = "关联用户") + @Column(typeHandler = JacksonTypeHandler.class) + private List userOptions = new ArrayList<>(); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptOptionsVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptOptionsVO.java new file mode 100644 index 0000000..a573f5a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptOptionsVO.java @@ -0,0 +1,26 @@ +package com.sz.admin.system.pojo.vo.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * DeptOptionsVo - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/28 + */ +@Data +@Schema(description = "部门选项") +public class DeptOptionsVO { + + @Schema(description = "部门Id") + private Long id; + + @Schema(description = "部门名称") + private String name; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptRoleInfoVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptRoleInfoVO.java new file mode 100644 index 0000000..2c50257 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptRoleInfoVO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.vo.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * DeptRoleInfoVO + * + * @author sz + * @version 1.0 + * @since 2025/7/17 09:40 + */ +@Data +public class DeptRoleInfoVO { + + @Schema(description = "部门ID") + private Long deptId; + + @Schema(description = "角色信ID") + private String roleId; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptTreeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptTreeVO.java new file mode 100644 index 0000000..6209a8e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/DeptTreeVO.java @@ -0,0 +1,41 @@ +package com.sz.admin.system.pojo.vo.sysdept; + +import com.sz.core.common.service.Treeable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * DeptTreeVO + * + * @author sz + * @since 2024/3/22 9:59 + * @version 1.0 + */ + +@Data +public class DeptTreeVO implements Treeable { + + @Schema(description = "id") + private Long id; + + @Schema(description = "pid") + private Long pid; + + @Schema(description = "层级") + private Long deep; + + @Schema(description = "排序") + private Long sort; + + @Schema(description = "子级") + private List children; + + @Schema(description = "name") + private String name; + + @Schema(description = "用户数量") + private Long userTotal = 0L; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptLeaderVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptLeaderVO.java new file mode 100644 index 0000000..af69155 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptLeaderVO.java @@ -0,0 +1,32 @@ +package com.sz.admin.system.pojo.vo.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * SysDeptLeaderVO + * + * @author sz + * @since 2024/3/26 15:56 + * @version 1.0 + */ +@Data +public class SysDeptLeaderVO { + + @Schema(description = "负责人信息数组") + private List leaderInfoVOS = new ArrayList<>(); + + @Data + public static class LeaderInfoVO { + + @Schema(description = "负责人Id") + private Long id; + + @Schema(description = "负责人名称") + private String nickname; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptRoleVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptRoleVO.java new file mode 100644 index 0000000..69014ac --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptRoleVO.java @@ -0,0 +1,30 @@ +package com.sz.admin.system.pojo.vo.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2025/7/15 16:22 + */ +@Data +public class SysDeptRoleVO { + + @Schema(description = "选中id数组") + private List selectIds; + + @Schema(description = "角色信息数组") + private List roleInfoVOS; + + @Data + public static class RoleInfoVO { + + @Schema(description = "角色id") + private Long id; + + @Schema(description = "角色名称") + private String roleName; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptVO.java new file mode 100644 index 0000000..935f406 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/SysDeptVO.java @@ -0,0 +1,70 @@ +package com.sz.admin.system.pojo.vo.sysdept; + +import com.sz.core.common.service.Treeable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * SysDept查询返回 + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Data +@Schema(description = "SysDept返回vo") +public class SysDeptVO implements Treeable { + + @Schema(description = "ID") + private Long id; + + @Schema(description = "父级id") + private Long pid; + + @Schema(description = "部门名称") + private String name; + + @Schema(description = "层级") + private Long deep; + + @Schema(description = "排序") + private Long sort; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否锁定") + private String isLock; + + @Schema(description = "子级") + private List children; + + @Schema(description = "负责人") + private List leaders = new ArrayList<>(); + + @Schema(description = "负责人信息") + private String leaderIds; + + @Schema(description = "数据权限") + private String dataScopeCd; + + @Schema(description = "关联data_scope id") + private Long scopeId; + + @Schema(description = "数据权限-自定义: 部门项1") + private List deptIds = new ArrayList<>(); + + @Schema(description = "数据权限-自定义: 用户项") + private List userIds = new ArrayList<>(); + + @Schema(description = "角色信息") + private String roleInfo; + + @Schema(description = "角色ID,多个逗号分隔") + private String roleIds; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/TotalDeptVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/TotalDeptVO.java new file mode 100644 index 0000000..b21a53f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdept/TotalDeptVO.java @@ -0,0 +1,24 @@ +package com.sz.admin.system.pojo.vo.sysdept; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * TotalDeptVO + * + * @author sz + * @since 2024/4/8 14:21 + * @version 1.0 + */ +@Data +public class TotalDeptVO { + + @Schema(description = "部门ID") + private Long id; + + @Schema(description = "部门名称") + private String name; + + @Schema(description = "部门人员数统计") + private Long total; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdict/SysDictTypeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdict/SysDictTypeVO.java new file mode 100644 index 0000000..cb98471 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysdict/SysDictTypeVO.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.pojo.vo.sysdict; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Schema(description = "字典类型详情") +public class SysDictTypeVO { + + @Schema(description = "字典id", example = "修改时用") + private Long id; + + @Schema(description = "字典名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "账户状态") + private String typeName; + + @Schema(description = "字典码(英文)", requiredMode = Schema.RequiredMode.REQUIRED, example = "account_status") + private String typeCode; + + @Schema(description = "是否锁定,锁定的不可以再页面操作", allowableValues = "T,F", example = "F") + private String isLock; + + @Schema(description = "是否显示", allowableValues = "T,F", example = "F") + private String isShow; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "字典类型") + private String type; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/MenuPermissionVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/MenuPermissionVO.java new file mode 100644 index 0000000..d5dab78 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/MenuPermissionVO.java @@ -0,0 +1,16 @@ +package com.sz.admin.system.pojo.vo.sysmenu; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @author sz + * @since 2023/9/1 15:32 + */ +@Data +public class MenuPermissionVO { + + @Schema(description = "权限标识数量") + private int permissionCount = 0; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/MenuTreeVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/MenuTreeVO.java new file mode 100644 index 0000000..befc072 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/MenuTreeVO.java @@ -0,0 +1,48 @@ +package com.sz.admin.system.pojo.vo.sysmenu; + +import com.sz.core.common.service.Treeable; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * SysMenuVO + * + * @author sz + * @since 2023/8/21 + */ +@Data +public class MenuTreeVO implements Treeable { + + @Schema(description = "id") + private Object id; + + @Schema(description = "pid") + private Object pid; + + @Schema(description = "层级") + private Long deep; + + @Schema(description = "排序") + private Long sort; + + @Schema(description = "title") + private String title; + + @Schema(description = "菜单类型") + private String menuTypeCd; + + @Schema(description = "按钮权限") + private String permissions; + + @Schema(description = "路由名称") + private String name; + + @Schema(description = "是否使用数据权限") + private String useDataScope; + + @Schema(description = "子级") + private List children; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/SysMenuVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/SysMenuVO.java new file mode 100644 index 0000000..31f369a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmenu/SysMenuVO.java @@ -0,0 +1,101 @@ +package com.sz.admin.system.pojo.vo.sysmenu; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * SysMenuVO + * + * @author sz + * @since 2023/8/21 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@Data +public class SysMenuVO { + + @Schema(description = "id") + private String id; + + @Schema(description = "pid") + private String pid; + + @Schema(description = "路径") + private String path; + + private String name; + + private Integer sort; + + @JsonIgnore + private String redirect; + + @Schema(description = "组件路径") + private String component; + + @JsonIgnore + private String icon; + + @JsonIgnore + private String title; + + @JsonIgnore + private String isLink; + + @JsonIgnore + private String isHidden; + + @JsonIgnore + private String isFull; + + @JsonIgnore + private String isAffix; + + @JsonIgnore + private String useDataScope; + + @JsonIgnore + private String isKeepAlive; + + @Schema(description = "元数据") + private Meta meta; + + private List children; + + @Schema(description = "权限标识") + private String permissions; + + @Schema(description = "菜单类型") + private String menuTypeCd; + + @Data + public static class Meta { + + @Schema(description = "菜单和面包屑对应的图标") + private String icon; + + @Schema(description = "路由标题 (用作 document.title || 菜单的名称)") + private String title; + + @Schema(description = "路由外链时填写的访问地址") + private String isLink; + + @Schema(description = "是否在菜单中隐藏 (通常列表详情页需要隐藏)") + private String isHidden; + + @Schema(description = "菜单是否全屏 (示例:数据大屏页面)") + private String isFull; + + @Schema(description = "菜单是否固定在标签页中") + private String isAffix; + + @Schema(description = "当前路由是否缓存") + private String isKeepAlive; + + @Schema(description = "菜单是否开启数据权限") + private String useDataScope; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/MessageCountVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/MessageCountVO.java new file mode 100644 index 0000000..c91de0c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/MessageCountVO.java @@ -0,0 +1,29 @@ +package com.sz.admin.system.pojo.vo.sysmessage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * MessageCountVO - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/3/13 + */ +@Data +@AllArgsConstructor +public class MessageCountVO { + + @Schema(description = "数量") + private Long all; + + @Schema(description = "待办") + private Long todo; + + @Schema(description = "消息") + private Long msg; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/SysMessageUserVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/SysMessageUserVO.java new file mode 100644 index 0000000..30a5c00 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/SysMessageUserVO.java @@ -0,0 +1,33 @@ +package com.sz.admin.system.pojo.vo.sysmessage; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + *

+ * SysMessageUser返回vo + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Data +@Schema(description = "SysMessageUser返回vo") +public class SysMessageUserVO { + + @Schema(description = "ID") + private Long id; + + @Schema(description = "消息ID") + private Long messageId; + + @Schema(description = "接收人ID") + private Long receiverId; + + @Schema(description = "是否已读") + private String isRead; + + @Schema(description = "阅读时间") + private LocalDateTime readTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/SysMessageVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/SysMessageVO.java new file mode 100644 index 0000000..9ec4637 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysmessage/SysMessageVO.java @@ -0,0 +1,43 @@ +package com.sz.admin.system.pojo.vo.sysmessage; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + *

+ * SysMessage返回vo + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Data +@Schema(description = "SysMessage返回vo") +public class SysMessageVO { + + @Schema(description = "消息ID") + private Long id; + + @Schema(description = "消息类型") + private String messageTypeCd; + + @Schema(description = "发送人ID") + private Long senderId; + + @Schema(description = "消息标题") + private String title; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "菜单路由地址") + private String menuRouter; + + @Schema(description = "是否已读") + private String isRead; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysrole/RoleOptionsVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysrole/RoleOptionsVO.java new file mode 100644 index 0000000..2198ba7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysrole/RoleOptionsVO.java @@ -0,0 +1,28 @@ +package com.sz.admin.system.pojo.vo.sysrole; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * RoleOptions - 简要描述该类的功能. + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/29 + */ +@Data +public class RoleOptionsVO { + + @Schema(description = "角色ID") + private Long id; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "角色编码") + private String permissions; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysrolemenu/SysRoleMenuVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysrolemenu/SysRoleMenuVO.java new file mode 100644 index 0000000..b99b8fa --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysrolemenu/SysRoleMenuVO.java @@ -0,0 +1,52 @@ +package com.sz.admin.system.pojo.vo.sysrolemenu; + +import com.sz.admin.system.pojo.vo.sysdept.DeptTreeVO; +import com.sz.admin.system.pojo.vo.sysmenu.MenuTreeVO; +import com.sz.admin.system.pojo.vo.sysuser.UserOptionVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author sz + * @since 2023/8/29 9:22 + */ +@Data +@Schema(description = "角色菜单详情") +public class SysRoleMenuVO { + + @Schema(description = "选中的菜单id") + private List selectMenuIds = new ArrayList<>(); + + @Schema(description = "菜单列表") + private List menuLists; + + @Schema(description = "部门列表") + private List deptLists; + + @Schema(description = "用户列表") + private List userLists; + + @Schema(description = "数据权限配置") + private List scope; + + @Data + public static class Scope { + + @Schema(description = "菜单id") + private String menuId; + + @Schema(description = "数据权限范围") + private String dataScope; + + @Schema(description = "部门id数组") + private List deptIds; + + @Schema(description = "用户id数组") + private List userIds; + + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/systempfile/SysTempFileInfoVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/systempfile/SysTempFileInfoVO.java new file mode 100644 index 0000000..b955b66 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/systempfile/SysTempFileInfoVO.java @@ -0,0 +1,54 @@ +package com.sz.admin.system.pojo.vo.systempfile; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Data +public class SysTempFileInfoVO { + + @Schema(description = "ID") + private Long id; + + @Schema(description = "文件ID") + private Integer sysFileId; + + @Schema(description = "模版名") + private String tempName; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "文件名") + private String filename; + + @Schema(description = "目录标识") + private String dirTag; + + @Schema(description = "文件大小") + private Long size; + + @Schema(description = "文件地址") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "对象名(唯一)") + private String objectName; + + @Schema(description = "文件类型") + private String contextType; + + @JsonProperty(value = "eTag") + @Schema(description = "eTag标识") + private String eTag; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/systempfile/SysTempFileVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/systempfile/SysTempFileVO.java new file mode 100644 index 0000000..0dfd55d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/systempfile/SysTempFileVO.java @@ -0,0 +1,57 @@ +package com.sz.admin.system.pojo.vo.systempfile; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * SysTempFile返回vo + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +@Data +@Schema(description = "SysTempFile返回vo") +public class SysTempFileVO { + + @Schema(description = "ID") + private Long id; + + @Schema(description = "文件ID") + private Integer sysFileId; + + @Schema(description = "模版名") + private String tempName; + + @Schema(description = "地址") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "逻辑删除") + private String delFlag; + + @Schema(description = "创建人") + private Long createId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新人") + private Long updateId; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "标识") + private String alias; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserDataMetaVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserDataMetaVO.java new file mode 100644 index 0000000..e4a1f93 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserDataMetaVO.java @@ -0,0 +1,20 @@ +package com.sz.admin.system.pojo.vo.sysuser; + +import lombok.Data; + +@Data +public class SysUserDataMetaVO { + + private Long userId; + + private String menuId; + + private Long roleId; + + private String dataScopeCd; + + private Long relationId; + + private String relationTypeCd; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserRoleVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserRoleVO.java new file mode 100644 index 0000000..1edc35d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserRoleVO.java @@ -0,0 +1,34 @@ +package com.sz.admin.system.pojo.vo.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2023/8/29 10:47 + */ +@Data +public class SysUserRoleVO { + + @Schema(description = "选中id数组") + private List selectIds; + + @Schema(description = "角色信息数组") + private List roleInfoVOS; + + @Data + public static class RoleInfoVO { + + @Schema(description = "角色id") + private Long id; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "是否锁定") + private boolean disabled = false; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserVO.java new file mode 100644 index 0000000..4d12db0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SysUserVO.java @@ -0,0 +1,68 @@ +package com.sz.admin.system.pojo.vo.sysuser; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @author sz + * @since 2023/8/24 10:29 + */ +@Data +public class SysUserVO { + + @Schema(description = "id") + private Long id; + + @Schema(description = "username") + private String username; + + @JsonIgnore // 忽略该字段的序列化和反序列化 + @Schema(description = "密码") + private String pwd; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "LOGO") + private String logo; + + @Schema(description = "年龄") + private Integer age; + + @Schema(description = "性别") + private Integer sex; + + @Schema(description = "身份证") + private String idCard; + + @Schema(description = "email") + private String email; + + @Schema(description = "账号状态码") + private String accountStatusCd; + + @Schema(description = "userTagCd") + private String userTagCd; + + @Schema(description = "最近一次登录时间") + private LocalDateTime lastLoginTime; + + private LocalDateTime createTime; + + private LocalDateTime updateTime; + + private String delFlag; + + @Schema(description = "部门ID,多个逗号分隔") + private String deptIds; + + @Schema(description = "角色ID,多个逗号分隔") + private String roleIds; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SystemUserLoginVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SystemUserLoginVO.java new file mode 100644 index 0000000..49b7a45 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/SystemUserLoginVO.java @@ -0,0 +1,33 @@ +package com.sz.admin.system.pojo.vo.sysuser; + +import com.sz.core.common.entity.BaseUserInfo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +/** + * @author sz + * @since 2022/5/24 19:47 临时login返回对象结构,后续oauth集成后失效 + */ +@Builder +@Data +public class SystemUserLoginVO { + + @Schema(description = "角色") + private List roles; + + @Schema(description = "基础用户信息") + private BaseUserInfo userInfo; + + @Schema(description = "权限标识数组") + private List permissions; + + @Schema(description = "accessToken") + private String accessToken; + + @Schema(description = "refreshToken") + private String refreshToken; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserDeptInfoVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserDeptInfoVO.java new file mode 100644 index 0000000..53c8591 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserDeptInfoVO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.vo.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * UserDeptVO + * + * @author sz + * @since 2024/4/8 9:04 + * @version 1.0 + */ +@Data +public class UserDeptInfoVO { + + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "部门ID,多个逗号分隔") + private String deptIds; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserOptionVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserOptionVO.java new file mode 100644 index 0000000..3dd7c35 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserOptionVO.java @@ -0,0 +1,26 @@ +package com.sz.admin.system.pojo.vo.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * UserOptionVO + * + * @author sz + * @since 2024/7/1 13:32 + * @version 1.0 + */ +@Data +@Schema(description = "select下拉用户项VO") +public class UserOptionVO { + + @Schema(description = "用户ID") + private Long id; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "用户昵称") + private String nickname; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserRoleInfoVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserRoleInfoVO.java new file mode 100644 index 0000000..8e866ef --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/pojo/vo/sysuser/UserRoleInfoVO.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.pojo.vo.sysuser; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * UserRoleInfoVO + * + * @author sz + * @since 2024/4/9 11:00 + * @version 1.0 + */ +@Data +public class UserRoleInfoVO { + + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "角色ID") + private String roleIds; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/CaptchaService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/CaptchaService.java new file mode 100644 index 0000000..cb70d8c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/CaptchaService.java @@ -0,0 +1,27 @@ +package com.sz.admin.system.service; + +import com.sz.core.common.entity.SliderPuzzle; +import com.sz.core.common.entity.CheckPuzzle; +import jakarta.servlet.http.HttpServletRequest; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +/** + * CaptchaService + * + * @author sz + * @since 2025/1/8 17:01 + * @version 1.0 + */ +public interface CaptchaService { + + SliderPuzzle getImageCode(HttpServletRequest request); + + void checkImageCode(CheckPuzzle checkPuzzle) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/CommonService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/CommonService.java new file mode 100644 index 0000000..e0f4f65 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/CommonService.java @@ -0,0 +1,21 @@ +package com.sz.admin.system.service; + +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.vo.common.ChallengeVO; +import com.sz.admin.system.pojo.vo.common.SelectorVO; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +public interface CommonService { + + void tempDownload(String templateName, String alias, HttpServletResponse response) throws IOException; + + SelectorVO querySelector(SelectorQueryDTO queryDTO); + + ChallengeVO challenge(); + + String ossPrivateUrl(String bucket, String url); + + void urlDownload(String url, HttpServletResponse response) throws IOException; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/ProductService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/ProductService.java new file mode 100644 index 0000000..ccca423 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/ProductService.java @@ -0,0 +1,42 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.Product; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.entity.PageResult; + +import java.util.List; + +import com.sz.admin.system.pojo.dto.ProductCreateDTO; +import com.sz.admin.system.pojo.dto.ProductUpdateDTO; +import com.sz.admin.system.pojo.dto.ProductListDTO; +import com.sz.admin.system.pojo.vo.ProductVO; +import com.sz.core.common.entity.ImportExcelDTO; +import jakarta.servlet.http.HttpServletResponse; + +/** + *

+ * 商品信息表 Service + *

+ * + * @author Lz + * @since 2026-01-22 + */ +public interface ProductService extends IService { + + void create(ProductCreateDTO dto); + + void update(ProductUpdateDTO dto); + + PageResult page(ProductListDTO dto); + + List list(ProductListDTO dto); + + void remove(SelectIdsDTO dto); + + ProductVO detail(Object id); + + void importExcel(ImportExcelDTO dto); + + void exportExcel(ProductListDTO dto, HttpServletResponse response); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysClientService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysClientService.java new file mode 100644 index 0000000..75b66fe --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysClientService.java @@ -0,0 +1,37 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysclient.SysClientCreateDTO; +import com.sz.admin.system.pojo.dto.sysclient.SysClientListDTO; +import com.sz.admin.system.pojo.dto.sysclient.SysClientUpdateDTO; +import com.sz.admin.system.pojo.po.SysClient; +import com.sz.admin.system.pojo.vo.sysclient.SysClientVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.security.pojo.ClientVO; + +import java.util.List; + +/** + *

+ * 系统授权表 Service + *

+ * + * @author sz + * @since 2024-01-22 + */ +public interface SysClientService extends IService { + + void create(SysClientCreateDTO dto); + + void update(SysClientUpdateDTO dto); + + PageResult page(SysClientListDTO dto); + + List list(SysClientListDTO dto); + + void remove(SelectIdsDTO dto); + + ClientVO detail(Object id); + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysConfigService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysConfigService.java new file mode 100644 index 0000000..af8be71 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysConfigService.java @@ -0,0 +1,34 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigCreateDTO; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigListDTO; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigUpdateDTO; +import com.sz.admin.system.pojo.po.SysConfig; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.Map; + +/** + *

+ * 参数配置表 服务类 + *

+ * + * @author sz + * @since 2023-11-23 + */ +public interface SysConfigService extends IService { + + void create(SysConfigCreateDTO dto); + + void update(SysConfigUpdateDTO dto); + + PageResult list(SysConfigListDTO queryDTO); + + void remove(SelectIdsDTO dto); + + SysConfig detail(Object id); + + Map getConfigVO(); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleMenuService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleMenuService.java new file mode 100644 index 0000000..2715436 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleMenuService.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysDataRoleMenu; + +import java.util.List; + +/** + *

+ * 系统数据角色-菜单表 Service + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +@Deprecated(since = "v1.4.0-beta") +public interface SysDataRoleMenuService extends IService { + + void batchSave(Long roleId, List menuIds); + + List getSelectMenuIdByRoleId(Long roleId); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleRelationService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleRelationService.java new file mode 100644 index 0000000..8b09831 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleRelationService.java @@ -0,0 +1,30 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysDataRoleRelation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + *

+ * 系统数据角色-关联表 Service + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +public interface SysDataRoleRelationService extends IService { + + @Transactional + void batchSave(Long roleId, String menuId, String relationTypeCd, List relationIds); + + List getSelectRelationId(Long roleId, String relationTypeCd); + + void deleteByRoleId(Long roleId); + + List queryRelationByRoleIdAndMenuIds(Long roleId, List menuIds); + + List listByRoleIdsAndMenuIds(Collection roleIds, List menuIds); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleService.java new file mode 100644 index 0000000..fbde078 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDataRoleService.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysDataRole; +import com.sz.admin.system.pojo.vo.sysdatarole.SysDataRoleMenuVO; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.entity.PageResult; +import java.util.List; + +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleCreateDTO; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleUpdateDTO; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleListDTO; +import com.sz.admin.system.pojo.vo.sysdatarole.SysDataRoleVO; + +/** + *

+ * 数据权限管理 Service + *

+ * + * @author sz-admin + * @since 2024-07-09 + */ +@Deprecated(since = "v1.4.0-beta") +public interface SysDataRoleService extends IService { + + void create(SysDataRoleCreateDTO dto); + + void update(SysDataRoleUpdateDTO dto); + + PageResult page(SysDataRoleListDTO dto); + + List list(SysDataRoleListDTO dto); + + void remove(SelectIdsDTO dto); + + SysDataRoleVO detail(Object id); + + SysDataRoleMenuVO queryDataRoleMenu(); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptClosureService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptClosureService.java new file mode 100644 index 0000000..72aac2c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptClosureService.java @@ -0,0 +1,29 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysDeptClosure; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + *

+ * 部门祖籍关系表 Service + *

+ * + * @author sz + * @since 2024-03-28 + */ +public interface SysDeptClosureService extends IService { + + List ancestorsPath(Long deptId); + + void create(Long deptId, Long parentDeptId); + + @Transactional + void remove(Long nodeId); + + List descendants(List ancestorIds); + + void move(Long nodeId, Long newNodeId); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptLeaderService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptLeaderService.java new file mode 100644 index 0000000..5ddcbdb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptLeaderService.java @@ -0,0 +1,21 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysDeptLeader; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + *

+ * 部门领导人表 Service + *

+ * + * @author sz + * @since 2024-03-26 + */ +public interface SysDeptLeaderService extends IService { + + @Transactional + void syncLeader(Long deptId, List leaderIds); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptService.java new file mode 100644 index 0000000..7477f67 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDeptService.java @@ -0,0 +1,56 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptCreateDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptListDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptRoleDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptUpdateDTO; +import com.sz.admin.system.pojo.po.SysDept; +import com.sz.admin.system.pojo.vo.common.DepartmentVO; +import com.sz.admin.system.pojo.vo.sysdept.DeptOptionsVO; +import com.sz.admin.system.pojo.vo.sysdept.DeptTreeVO; +import com.sz.admin.system.pojo.vo.sysdept.SysDeptLeaderVO; +import com.sz.admin.system.pojo.vo.sysdept.SysDeptRoleVO; +import com.sz.admin.system.pojo.vo.sysdept.SysDeptVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.List; + +/** + *

+ * 部门表 Service + *

+ * + * @author sz + * @since 2024-03-20 + */ +public interface SysDeptService extends IService { + + void create(SysDeptCreateDTO dto); + + void update(SysDeptUpdateDTO dto); + + PageResult page(SysDeptListDTO dto); + + List list(SysDeptListDTO dto); + + void remove(SelectIdsDTO dto); + + SysDeptVO detail(Object id); + + List getDepartmentTreeWithAdditionalNodes(); + + List getDeptTree(Integer excludeNodeId, Boolean appendRoot, Boolean needSetTotal); + + SysDeptLeaderVO findSysUserDeptLeader(); + + List listSelector(SelectorQueryDTO dto); + + List getDeptOptions(); + + SysDeptRoleVO findSysDeptRole(Long deptId); + + void changeSysDeptRole(SysDeptRoleDTO dto); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDictService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDictService.java new file mode 100644 index 0000000..42395ae --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDictService.java @@ -0,0 +1,42 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysdict.SysDictCreateDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictListDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictUpdateDTO; +import com.sz.admin.system.pojo.po.SysDict; +import com.sz.core.common.entity.DictVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.List; +import java.util.Map; + +/** + *

+ * 字典表 服务类 + *

+ * + * @author sz + * @since 2023-08-18 + */ +public interface SysDictService extends IService { + + void create(SysDictCreateDTO dto); + + void update(SysDictUpdateDTO dto); + + void remove(SelectIdsDTO dto); + + PageResult list(SysDictListDTO dto); + + Map> dictList(String typeCode); + + Map> dictAll(); + + List getDictByType(String typeCode); + + String exportDictSql(SelectIdsDTO dto); + + Map> getDictByCode(List typeCode); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDictTypeService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDictTypeService.java new file mode 100644 index 0000000..1000fea --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysDictTypeService.java @@ -0,0 +1,35 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeAddDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeListDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeUpDTO; +import com.sz.admin.system.pojo.po.SysDictType; +import com.sz.core.common.dict.DictTypeVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.List; + +/** + *

+ * 字典类型 服务类 + *

+ * + * @author sz + * @since 2023-08-18 + */ +public interface SysDictTypeService extends IService { + + void create(SysDictTypeAddDTO dto); + + void update(SysDictTypeUpDTO dto); + + void remove(SelectIdsDTO dto); + + SysDictType detail(Long id); + + PageResult list(SysDictTypeListDTO dto); + + List selectDictTypeOptions(); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysFileService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysFileService.java new file mode 100644 index 0000000..55a378b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysFileService.java @@ -0,0 +1,42 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysfile.SysFileListDTO; +import com.sz.admin.system.pojo.po.SysFile; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.UploadResult; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + *

+ * 服务类 + *

+ * + * @author sz + * @since 2023-08-31 + */ +public interface SysFileService extends IService { + + /** + * 文件列表 + * + * @param dto + * dto + * @return {@link List}<{@link SysFile}> + */ + PageResult fileList(SysFileListDTO dto); + + /** + * 上传文件 + * + * @param file + * 文件 + * @return {@link ApiResult} + */ + UploadResult uploadFile(MultipartFile file, String dirTag, String scene) throws Exception; + + Long fileLog(UploadResult uploadResult); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysLoginLogService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysLoginLogService.java new file mode 100644 index 0000000..dada811 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysLoginLogService.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysLoginLog; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.entity.PageResult; +import java.util.List; +import com.sz.admin.system.pojo.dto.SysLoginLogCreateDTO; +import com.sz.admin.system.pojo.dto.SysLoginLogUpdateDTO; +import com.sz.admin.system.pojo.dto.SysLoginLogListDTO; +import com.sz.admin.system.pojo.vo.SysLoginLogVO; +import jakarta.servlet.http.HttpServletResponse; + +/** + *

+ * 登陆日志表 Service + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +public interface SysLoginLogService extends IService { + + void create(SysLoginLogCreateDTO dto); + + void update(SysLoginLogUpdateDTO dto); + + PageResult page(SysLoginLogListDTO dto); + + List list(SysLoginLogListDTO dto); + + void remove(SelectIdsDTO dto); + + SysLoginLogVO detail(Object id); + + void exportExcel(SysLoginLogListDTO dto, HttpServletResponse response); + + void recordLoginLog(String userName, String status, String msg); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMenuService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMenuService.java new file mode 100644 index 0000000..80a4fe9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMenuService.java @@ -0,0 +1,95 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysmenu.MenuPermissionDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysMenuCreateDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysMenuListDTO; +import com.sz.admin.system.pojo.po.SysMenu; +import com.sz.admin.system.pojo.vo.sysmenu.MenuPermissionVO; +import com.sz.admin.system.pojo.vo.sysmenu.MenuTreeVO; +import com.sz.admin.system.pojo.vo.sysmenu.SysMenuVO; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + *

+ * 系统菜单表 服务类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +public interface SysMenuService extends IService { + + /** + * 创建 + * + * @param dto + * dto + */ + void create(SysMenuCreateDTO dto); + + /** + * 更新 + * + * @param dto + * dto + */ + void update(SysMenuCreateDTO dto); + + /** + * 删除菜单 + * + * @param dto + * dto + */ + void remove(SelectIdsDTO dto); + + /** + * 列表 + * + * @param dto + * dto + * @return {@link List}<{@link SysMenuVO}> + */ + List menuList(SysMenuListDTO dto); + + List findMenuListByUserId(Long userId); + + List getSimpleMenuTree(String nodeId); + + List getMenuTreeVOS(String nodeId, boolean isShowButton); + + List queryRoleMenuTree(boolean isShowButton); + + String exportMenuSql(SelectIdsDTO dto); + + /** + * 详情 + * + * @return {@link SysMenu} + */ + SysMenu detail(String id); + + MenuPermissionVO hasExistsPermissions(MenuPermissionDTO dto); + + /** + * 查询权限按钮 + * + * @return 权限按钮集合 + */ + List findPermission(); + + List findPermissionsByUserId(Long userId); + + List findAllPermissions(); + + Map getBtnMenuByPermissions(Collection permissions); + + List queryDataRoleMenu(); + + void changeMenuDataScope(String menuId); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMessageService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMessageService.java new file mode 100644 index 0000000..740d7a7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMessageService.java @@ -0,0 +1,33 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysmessage.Message; +import com.sz.admin.system.pojo.dto.sysmessage.SysMessageListDTO; +import com.sz.admin.system.pojo.po.SysMessage; +import com.sz.admin.system.pojo.vo.sysmessage.MessageCountVO; +import com.sz.admin.system.pojo.vo.sysmessage.SysMessageVO; +import com.sz.core.common.entity.PageResult; +import java.util.List; + +/** + *

+ * 消息管理 Service + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +public interface SysMessageService extends IService { + + void create(Message dto); + + void saveMsg(Message dto); + + PageResult page(SysMessageListDTO dto); + + List list(SysMessageListDTO dto); + + SysMessageVO detail(Object id); + + MessageCountVO countMyUnreadMessages(); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMessageUserService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMessageUserService.java new file mode 100644 index 0000000..ff0096a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysMessageUserService.java @@ -0,0 +1,20 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysMessageUser; +import java.util.List; + +/** + *

+ * 消息接收用户表 Service + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +public interface SysMessageUserService extends IService { + + void batchInsert(Long messageId, List receiverIds); + + String getIsRead(Long messageId, Long receiverId); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysPermissionService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysPermissionService.java new file mode 100644 index 0000000..16066c0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysPermissionService.java @@ -0,0 +1,30 @@ +package com.sz.admin.system.service; + +import com.sz.admin.system.pojo.po.SysUser; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * SysPermissionService + * + * @author sz + * @since 2024/2/4 15:12 + * @version 1.0 + */ +public interface SysPermissionService { + + Set getMenuPermissions(SysUser sysUser); + + Set getRoles(Long userId); + + Set getRoles(SysUser sysUser); + + List getDepts(SysUser sysUser); + + List getDeptAndChildren(SysUser sysUser); + + Map buildMenuRuleMap(SysUser sysUser, Set findMenuIds); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysRoleMenuService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysRoleMenuService.java new file mode 100644 index 0000000..3d97d50 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysRoleMenuService.java @@ -0,0 +1,27 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysrolemenu.SysRoleMenuDTO; +import com.sz.admin.system.pojo.po.SysRoleMenu; +import com.sz.core.common.entity.RoleMenuScopeVO; +import com.sz.admin.system.pojo.vo.sysrolemenu.SysRoleMenuVO; + +import java.util.Collection; +import java.util.Map; + +/** + *

+ * 系统角色-菜单表 服务类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +public interface SysRoleMenuService extends IService { + + void change(SysRoleMenuDTO dto); + + SysRoleMenuVO queryRoleMenu(Long roleId); + + Map getUserScope(Collection roleIds); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysRoleService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysRoleService.java new file mode 100644 index 0000000..ad4e760 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysRoleService.java @@ -0,0 +1,39 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleCreateDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleListDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleUpdateDTO; +import com.sz.admin.system.pojo.po.SysRole; +import com.sz.admin.system.pojo.vo.common.RoleVO; +import com.sz.admin.system.pojo.vo.sysrole.RoleOptionsVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.List; + +/** + *

+ * 系统角色表 服务类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +public interface SysRoleService extends IService { + + void create(SysRoleCreateDTO dto); + + void update(SysRoleUpdateDTO dto); + + void remove(SelectIdsDTO dto); + + void removeByMenuId(SelectIdsDTO dto); + + PageResult list(SysRoleListDTO dto); + + PageResult pageSelector(SelectorQueryDTO dto); + + List getRoleOptions(); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysTempFileHistoryService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysTempFileHistoryService.java new file mode 100644 index 0000000..9f957cb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysTempFileHistoryService.java @@ -0,0 +1,22 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileHistoryCreateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileHistoryListDTO; +import com.sz.admin.system.pojo.po.SysTempFileHistory; +import com.sz.core.common.entity.PageResult; + +/** + *

+ * 模版文件历史 Service + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +public interface SysTempFileHistoryService extends IService { + + void create(SysTempFileHistoryCreateDTO dto); + + PageResult historyList(SysTempFileHistoryListDTO dto); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysTempFileService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysTempFileService.java new file mode 100644 index 0000000..b7307f1 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysTempFileService.java @@ -0,0 +1,41 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysTempFile; +import com.sz.admin.system.pojo.vo.systempfile.SysTempFileInfoVO; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.entity.PageResult; +import java.util.List; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileCreateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileUpdateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileListDTO; +import com.sz.admin.system.pojo.vo.systempfile.SysTempFileVO; +import com.sz.core.common.entity.UploadResult; +import org.springframework.web.multipart.MultipartFile; + +/** + *

+ * 模版文件表 Service + *

+ * + * @author sz-admin + * @since 2024-12-05 + */ +public interface SysTempFileService extends IService { + + void create(SysTempFileCreateDTO dto); + + void update(SysTempFileUpdateDTO dto); + + PageResult page(SysTempFileListDTO dto); + + List list(SysTempFileListDTO dto); + + void remove(SelectIdsDTO dto); + + SysTempFileVO detail(Object id); + + UploadResult uploadFile(MultipartFile file); + + SysTempFileInfoVO detailByNameOrAlias(String tempName, String alias); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserDataRoleService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserDataRoleService.java new file mode 100644 index 0000000..61366b7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserDataRoleService.java @@ -0,0 +1,21 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysmenu.SysUserRoleDTO; +import com.sz.admin.system.pojo.po.SysUserDataRole; +import com.sz.admin.system.pojo.vo.sysuser.SysUserRoleVO; + +/** + *

+ * 系统用户-数据角色关联表 Service + *

+ * + * @author sz-admin + * @since 2024-07-11 + */ +public interface SysUserDataRoleService extends IService { + + void changeRole(SysUserRoleDTO dto); + + SysUserRoleVO queryRoleMenu(Long userId); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserDeptService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserDeptService.java new file mode 100644 index 0000000..94fd54b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserDeptService.java @@ -0,0 +1,24 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.sysuser.UserDeptDTO; +import com.sz.admin.system.pojo.po.SysUserDept; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + *

+ * 用户-部门关系表 Service + *

+ * + * @author sz + * @since 2024-04-02 + */ +public interface SysUserDeptService extends IService { + + @Transactional + void bind(UserDeptDTO dto); + + void unbind(List userIds); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserRoleService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserRoleService.java new file mode 100644 index 0000000..baffb58 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserRoleService.java @@ -0,0 +1,19 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.po.SysUserRole; + +import java.util.List; + +/** + *

+ * 系统用户-角色关联表 服务类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +public interface SysUserRoleService extends IService { + + List getUserRolesByUserId(Long userId); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserService.java new file mode 100644 index 0000000..b055757 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/SysUserService.java @@ -0,0 +1,109 @@ +package com.sz.admin.system.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysUserRoleDTO; +import com.sz.admin.system.pojo.dto.sysuser.*; +import com.sz.admin.system.pojo.po.SysUser; +import com.sz.admin.system.pojo.vo.common.UserVO; +import com.sz.admin.system.pojo.vo.sysuser.SysUserRoleVO; +import com.sz.admin.system.pojo.vo.sysuser.SysUserVO; +import com.sz.admin.system.pojo.vo.sysuser.UserOptionVO; +import com.sz.core.common.entity.LoginUser; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.util.List; + +/** + *

+ * 系统用户表 服务类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +public interface SysUserService extends IService { + + SysUserVO getSysUserByUsername(String username); + + SysUserVO getSysUserByUserId(Long userId); + + /** + * 创建用户 + * + * @param dto + * 用户信息 + */ + void create(SysUserCreateDTO dto); + + /** + * 更新用户 + * + * @param dto + * 用户信息 + */ + void update(SysUserUpdateDTO dto); + + /** + * 删除用户 + * + * @param dto + * 用户id数组 + */ + void remove(SelectIdsDTO dto); + + /** + * 详情 + * + * @param id + * id + * @return {@link SysUser} + */ + SysUserVO detail(Long id); + + PageResult page(SysUserListDTO dto); + + SysUserRoleVO findSysUserRole(Long userId); + + void changeSysUserRole(SysUserRoleDTO dto); + + /** + * 获取用户信息 + * + * @return {@link SysUserVO} + */ + SysUserVO getUserInfo(); + + /** + * 更改密码 + * + * @param dto + * dto + */ + void changePassword(SysUserPasswordDTO dto); + + /** + * 重置密码 + * + * @param id + * id + */ + void resetPassword(Long id); + + void syncUserInfo(Object userId); + + LoginUser buildLoginUser(String username, String password); + + LoginUser buildLoginUser(Long userId); + + void unlock(SelectIdsDTO dto); + + void bindUserDept(UserDeptDTO dto); + + List getUserOptions(); + + PageResult pageSelector(SelectorQueryDTO dto); + + void changeUserTag(SysUserTagDTO dto); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/CaptchaServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/CaptchaServiceImpl.java new file mode 100644 index 0000000..ba0e273 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/CaptchaServiceImpl.java @@ -0,0 +1,94 @@ +package com.sz.admin.system.service.impl; + +import com.sz.admin.system.service.CaptchaService; +import com.sz.core.common.entity.CheckPuzzle; +import com.sz.core.common.entity.PointVO; +import com.sz.core.common.entity.SliderPuzzle; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.AESUtil; +import com.sz.core.util.SlidePuzzleUtil; +import com.sz.core.util.SysConfigUtils; +import com.sz.core.util.Utils; +import com.sz.redis.RedisCache; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.stereotype.Service; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +/** + * CaptchaServiceImpl + * + * @author sz + * @version 1.0 + * @since 2025/1/8 17:01 + */ +@Service +@RequiredArgsConstructor +public class CaptchaServiceImpl implements CaptchaService { + + private final RedisCache redisCache; + + private final SecureRandom random = new SecureRandom(); + + @SneakyThrows + @Override + public SliderPuzzle getImageCode(HttpServletRequest request) { + String requestId = Utils.generateSha256Id(Utils.generateAgentRequestId(request)); // 根据request标识生成Sha256Id + int limit = Utils.getIntVal(SysConfigUtils.getConfValue("sys.captcha.requestLimit")); + String requestCycle = SysConfigUtils.getConfValue("sys.captcha.requestCycle"); + if (Utils.getIntVal(limit) != 0) { + redisCache.initializeCaptchaRequestLimit(requestId, Utils.getLongVal(requestCycle)); + Long cacheLimit = redisCache.countCaptchaRequestLimit(requestId); + CommonResponseEnum.CAPTCHA_LIMIT.assertTrue(cacheLimit > Utils.getLongVal(limit)); + } + + ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + Resource[] resources = resolver.getResources("classpath:/templates/background/*.png"); // 读取背景图片库 + CommonResponseEnum.BACKGROUND_NOT_EXISTS.assertTrue(resources.length == 0); + Resource resource = resources[random.nextInt(resources.length)]; // 从背景库中随机获取一张 + SliderPuzzle sliderPuzzle = SlidePuzzleUtil.createImage(resource.getInputStream(), request); // 生成验证码 + CommonResponseEnum.FILE_NOT_EXISTS.assertNull(sliderPuzzle); + + if (limit != 0) { + redisCache.limitCaptcha(requestId); + } + + String expireTime = SysConfigUtils.getConfValue("sys.captcha.expire"); + assert sliderPuzzle != null; + PointVO pointVO = new PointVO(sliderPuzzle.getPosX(), sliderPuzzle.getPosY(), sliderPuzzle.getSecretKey()); + + redisCache.clearCaptcha(requestId); // 清除 + redisCache.putCaptcha(requestId, pointVO, Utils.getLongVal(expireTime)); // 保存到Redis + sliderPuzzle.setPosX(null); // 清空验证的x坐标 + return sliderPuzzle; + } + + @Override + public void checkImageCode(CheckPuzzle checkPuzzle) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, + NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + String requestId = checkPuzzle.getRequestId(); + CommonResponseEnum.CAPTCHA_LACK.assertNull(checkPuzzle.getMoveEncrypted()); + CommonResponseEnum.CAPTCHA_EXPIRED.assertFalse(redisCache.existCaptcha(requestId)); + PointVO pointVO = redisCache.getCaptcha(checkPuzzle.getRequestId()); + redisCache.clearCaptcha(requestId); // 用后即消 + String str = AESUtil.aesDecrypt(checkPuzzle.getMoveEncrypted(), pointVO.getSecretKey(), checkPuzzle.getIv()); // 解密,获取x位移距离 + int posX = 0; + if (Utils.isNotNull(str)) { + double posXDouble = Double.parseDouble(str); // 将解密结果转换为double类型 + posX = (int) Math.round(posXDouble); // 四舍五入取整 + } + CommonResponseEnum.CAPTCHA_FAILED.assertTrue(Math.abs(posX - pointVO.getX()) > 3); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/CommonServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/CommonServiceImpl.java new file mode 100644 index 0000000..77f6e8f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/CommonServiceImpl.java @@ -0,0 +1,230 @@ +package com.sz.admin.system.service.impl; + +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.vo.common.ChallengeVO; +import com.sz.admin.system.pojo.vo.common.SelectorVO; +import com.sz.admin.system.pojo.vo.systempfile.SysTempFileInfoVO; +import com.sz.admin.system.service.*; +import com.sz.core.common.entity.UploadResult; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.*; +import com.sz.oss.OssClient; +import com.sz.redis.RedisCache; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; + +import static com.sz.core.common.enums.CommonResponseEnum.FILE_NOT_EXISTS; + +@Service +@RequiredArgsConstructor +@Slf4j +public class CommonServiceImpl implements CommonService { + + private final ResourceLoader resourceLoader; + + private final SysTempFileService sysTempFileService; + + private final OssClient ossClient; + + private final SysUserService sysUserService; + + private final SysDeptService sysDeptService; + + private final SysRoleService sysRoleService; + + private final RedisCache redisCache; + + @Override + public void tempDownload(String templateName, String alias, HttpServletResponse response) throws IOException { + String templatePath = "classpath:/templates/" + templateName; + Resource resource = resourceLoader.getResource(templatePath); + + // 兼容临时目录文件。 + if (resource.exists()) { + FileUtils.downloadTemplateFile(resourceLoader, response, templateName); + return; + } + + // 从oss获取文件 + SysTempFileInfoVO sysTempFileInfoVO = sysTempFileService.detailByNameOrAlias(templateName, alias); + // 异常情况处理。通过http status响应 + if (sysTempFileInfoVO == null) { + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + response.setStatus(FILE_NOT_EXISTS.getCode()); + OutputStream out = response.getOutputStream(); + out.write(FILE_NOT_EXISTS.getMessage().getBytes(StandardCharsets.UTF_8)); + out.flush(); + return; + } + FILE_NOT_EXISTS.assertNull(sysTempFileInfoVO); + + UploadResult result = sysTempFileInfoVO.getUrl().getFirst(); + String fileUrl = result.getUrl(); + String filename = result.getFilename(); + long size = result.getSize(); + if (size > 0) + response.setContentLengthLong(size); + String confValue = SysConfigUtils.getConfValue("oss.accessMode"); + // 私有文件需要生成带签名的临时访问URL + if ("private".equals(confValue)) { + String finalBucket = getBucketFromUrl(fileUrl, ""); + String objectName = getObjectNameFromUrl(fileUrl); + fileUrl = ossClient.getPrivateUrl(finalBucket, objectName); + } + try (InputStream in = new URL(fileUrl).openStream(); OutputStream os = FileUtils.getOutputStream(response, filename)) { + in.transferTo(os); + os.flush(); + } + } + + @Override + public SelectorVO querySelector(SelectorQueryDTO queryDTO) { + SelectorVO result = new SelectorVO(); + String type = queryDTO.getType(); + Object data; + switch (type) { + case "user" -> data = sysUserService.pageSelector(queryDTO); + case "role" -> data = sysRoleService.pageSelector(queryDTO); + case "department" -> data = sysDeptService.listSelector(queryDTO); + default -> throw new RuntimeException("不支持的维度类型: " + type); + } + result.setType(type); + result.setData(data); + return result; + } + + @Override + public ChallengeVO challenge() { + HttpServletRequest request = HttpReqResUtil.getRequest(); + String requestId = Utils.generateSha256Id(Utils.generateAgentRequestId(request)); + int limit = Utils.getIntVal(SysConfigUtils.getConfValue("sys.login.requestLimit")); + Long requestCycle = Utils.getLongVal(SysConfigUtils.getConfValue("sys.login.requestCycle")); + + if (limit != 0) { + // 初始化请求限制 + redisCache.initializeLoginRequestLimit(requestId, requestCycle); + Long cacheLimit = redisCache.countLoginRequestLimit(requestId); + CommonResponseEnum.LOGIN_LIMIT.assertTrue(cacheLimit > limit); + } + + // 根据request标识生成Sha256Id + String secretKey = AESUtil.getRandomString(16); + + if (limit != 0) { + redisCache.limitLoginRequest(requestId); + } + // 清除 + redisCache.clearLoginSecret(requestId); + redisCache.putLoginSecret(requestId, secretKey, 60); + return new ChallengeVO().setRequestId(requestId).setSecretKey(secretKey); + } + + @Override + public String ossPrivateUrl(String bucket, String url) { + CommonResponseEnum.NOT_EXISTS.message("URL 不能为空").assertTrue(url == null || url.isEmpty()); + String finalBucket = getBucketFromUrl(url, bucket); + String objectName = getObjectNameFromUrl(url); + log.info("bucket = {}, objectName = {}", finalBucket, objectName); + return ossClient.getPrivateUrl(finalBucket, objectName); + } + + @Override + public void urlDownload(String url, HttpServletResponse response) throws IOException { + CommonResponseEnum.NOT_EXISTS.message("URL 不能为空").assertTrue(url == null || url.isEmpty()); + String finalBucket = getBucketFromUrl(url, ""); + String objectName = getObjectNameFromUrl(url); + String filename = getFilenameFromObjectName(objectName); + String confValue = SysConfigUtils.getConfValue("oss.accessMode"); + String fileUrl = url; + // 私有文件需要生成带签名的临时访问URL + if ("private".equals(confValue)) { + fileUrl = ossClient.getPrivateUrl(finalBucket, objectName); + } + try (InputStream in = new URL(fileUrl).openStream(); OutputStream os = FileUtils.getOutputStream(response, filename)) { + in.transferTo(os); + os.flush(); + } + } + + /** + * 根据 URL 获取 bucket: 1. 若是 http(s) 开头且能解析出 bucket,则返回 URL 中的 bucket 2. 否则返回 + * defaultBucket + */ + public String getBucketFromUrl(String url, String defaultBucket) { + String finalBucket = defaultBucket; + + if (url != null && (url.startsWith("http://") || url.startsWith("https://"))) { + int schemeEndIndex = url.indexOf("://"); + String noScheme = url.substring(schemeEndIndex + 3); // 去掉 "http://"/"https://" + + int firstSlashIndex = noScheme.indexOf('/'); + // firstSlashIndex < 0 或者刚好在最后一个字符,说明没有 path,无法解析 + CommonResponseEnum.INVALID.message("URL 格式不正确,无法解析出 bucket").assertTrue(firstSlashIndex < 0 || firstSlashIndex == noScheme.length() - 1); + + // path 形如:test/user/20241216/xxx.jpg + String path = noScheme.substring(firstSlashIndex + 1); + + int secondSlashIndex = path.indexOf('/'); + // 没有第二个 /,说明没有 objectName 部分,也就无法切分出 bucket + CommonResponseEnum.INVALID.message("URL 格式不正确,无法解析出 bucket").assertTrue(secondSlashIndex < 0); + String bucketFromUrl = path.substring(0, secondSlashIndex); + if (finalBucket == null || finalBucket.isEmpty()) { + finalBucket = bucketFromUrl; + } + } + return finalBucket; + } + + /** + * 根据 URL 获取 objectName: 1. 若是 http(s) 开头,则解析出 path 中 bucket 后面的部分作为 objectName + * 2. 否则直接把 url 当成 objectName + */ + public String getObjectNameFromUrl(String url) { + if (url != null && (url.startsWith("http://") || url.startsWith("https://"))) { + int schemeEndIndex = url.indexOf("://"); + String noScheme = url.substring(schemeEndIndex + 3); // 去掉 "http://"/"https://" + + int firstSlashIndex = noScheme.indexOf('/'); + CommonResponseEnum.INVALID.message("URL 格式不正确,无法解析出 objectName").assertTrue(firstSlashIndex < 0 || firstSlashIndex == noScheme.length() - 1); + + String path = noScheme.substring(firstSlashIndex + 1); // 去掉第一个 "/" + + // path 形如:test/user/20241216/xxx.jpg + int secondSlashIndex = path.indexOf('/'); + CommonResponseEnum.INVALID.message("URL 格式不正确,无法解析出 objectName").assertTrue(secondSlashIndex < 0); + + // 去掉 bucket 后面的 "/" + return path.substring(secondSlashIndex + 1); + } else { + // 非 http(s) 开头,直接认为是 objectName + return url; + } + } + + public String getFilenameFromObjectName(String objectName) { + if (objectName == null || objectName.isEmpty()) { + return objectName; + } + int lastSlashIndex = objectName.lastIndexOf('/'); + if (lastSlashIndex < 0 || lastSlashIndex == objectName.length() - 1) { + // 没有 "/" 或 "/" 在最后(类似 "xxx/"),直接返回原字符串 + return objectName; + } + return objectName.substring(lastSlashIndex + 1); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/ProductServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/ProductServiceImpl.java new file mode 100644 index 0000000..59639b9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/ProductServiceImpl.java @@ -0,0 +1,137 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.spring.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.sz.admin.system.service.ProductService; +import com.sz.admin.system.pojo.po.Product; +import com.sz.admin.system.mapper.ProductMapper; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.query.QueryChain; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.PageUtils; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.Utils; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.io.Serializable; +import java.util.List; + +import com.sz.admin.system.pojo.dto.ProductCreateDTO; +import com.sz.admin.system.pojo.dto.ProductUpdateDTO; +import com.sz.admin.system.pojo.dto.ProductListDTO; +import com.sz.admin.system.pojo.dto.ProductImportDTO; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.excel.core.ExcelResult; + +import java.io.OutputStream; + +import jakarta.servlet.http.HttpServletResponse; +import com.sz.core.util.FileUtils; +import com.sz.excel.utils.ExcelUtils; +import lombok.SneakyThrows; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.admin.system.pojo.vo.ProductVO; + +/** + *

+ * 商品信息表 服务实现类 + *

+ * + * @author Lz + * @since 2026-01-22 + */ +@Service +@RequiredArgsConstructor +public class ProductServiceImpl extends ServiceImpl implements ProductService { + @Override + public void create(ProductCreateDTO dto) { + Product sysProduct = BeanCopyUtils.copy(dto, Product.class); + save(sysProduct); + } + + @Override + public void update(ProductUpdateDTO dto) { + Product sysProduct = BeanCopyUtils.copy(dto, Product.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create() + .eq(Product::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + + saveOrUpdate(sysProduct); + } + + @Override + public PageResult page(ProductListDTO dto) { + try { + SimpleDataScopeHelper.start(Product.class); + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), ProductVO.class); + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(ProductListDTO dto) { + try { + SimpleDataScopeHelper.start(Product.class); + return listAs(buildQueryWrapper(dto), ProductVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public ProductVO detail(Object id) { + Product sysProduct = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(sysProduct); + return BeanCopyUtils.copy(sysProduct, ProductVO.class); + } + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), ProductImportDTO.class, true); + List list = excelResult.getList(); + // 入库 + List importList = BeanCopyUtils.copyList(list, Product.class); + saveBatch(importList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + } + + @SneakyThrows + @Override + public void exportExcel(ProductListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "商品信息表模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "商品信息表", ProductVO.class, os); + } + + private static QueryWrapper buildQueryWrapper(ProductListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(Product.class); + if (Utils.isNotNull(dto.getProductName())) { + wrapper.like(Product::getProductName, dto.getProductName()); + } + if (Utils.isNotNull(dto.getPrice())) { + wrapper.eq(Product::getPrice, dto.getPrice()); + } + if (Utils.isNotNull(dto.getStatus())) { + wrapper.eq(Product::getStatus, dto.getStatus()); + } + return wrapper; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysClientServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysClientServiceImpl.java new file mode 100644 index 0000000..3fb46b6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysClientServiceImpl.java @@ -0,0 +1,131 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysClientMapper; +import com.sz.admin.system.pojo.dto.sysclient.SysClientCreateDTO; +import com.sz.admin.system.pojo.dto.sysclient.SysClientListDTO; +import com.sz.admin.system.pojo.dto.sysclient.SysClientUpdateDTO; +import com.sz.admin.system.pojo.po.SysClient; +import com.sz.admin.system.pojo.vo.sysclient.SysClientVO; +import com.sz.admin.system.service.SysClientService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.StreamUtils; +import com.sz.core.util.Utils; +import com.sz.security.pojo.ClientVO; +import com.sz.security.service.ClientService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; + +/** + *

+ * 系统授权表 服务实现类 + *

+ * + * @author sz + * @since 2024-01-22 + */ +@Service +@RequiredArgsConstructor +public class SysClientServiceImpl extends ServiceImpl implements SysClientService, ClientService { + + @Override + public void create(SysClientCreateDTO dto) { + SysClient sysClient = BeanCopyUtils.copy(dto, SysClient.class); + String clientId = Utils.generateUUIDs(); + sysClient.setClientId(clientId); + sysClient.setClientSecret(Utils.generateUUIDs()); + // 唯一性校验 + QueryWrapper wrapper = QueryWrapper.create().eq(SysClient::getClientKey, dto.getClientKey()); + CommonResponseEnum.EXISTS.message("clientKey已存在").assertTrue(count(wrapper) > 0); + List grantTypeCdList = dto.getGrantTypeCdList(); + formatGrantType(grantTypeCdList, sysClient); + save(sysClient); + } + + @Override + public void update(SysClientUpdateDTO dto) { + SysClient sysClient = BeanCopyUtils.copy(dto, SysClient.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(SysClient::getClientId, dto.getClientId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + List grantTypeCdList = dto.getGrantTypeCdList(); + formatGrantType(grantTypeCdList, sysClient); + + saveOrUpdate(sysClient); + } + + @Override + public PageResult page(SysClientListDTO dto) { + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), SysClientVO.class); + return PageUtils.getPageResult(page); + } + + @Override + public List list(SysClientListDTO dto) { + return listAs(buildQueryWrapper(dto), SysClientVO.class); + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public ClientVO detail(Object id) { + SysClient sysClient = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(sysClient); + ClientVO clientVO = BeanCopyUtils.copy(sysClient, ClientVO.class); + clientVO.setGrantTypeCdList(Arrays.asList(sysClient.getGrantTypeCd().split(","))); + return clientVO; + } + + @Override + public ClientVO getClientByClientId(Object id) { + return detail(id); + } + + private static QueryWrapper buildQueryWrapper(SysClientListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(SysClient.class); + if (Utils.isNotNull(dto.getClientKey())) { + wrapper.eq(SysClient::getClientKey, dto.getClientKey()); + } + + if (Utils.isNotNull(dto.getClientSecret())) { + wrapper.eq(SysClient::getClientSecret, dto.getClientSecret()); + } + + if (Utils.isNotNull(dto.getGrantTypeCd())) { + wrapper.eq(SysClient::getGrantTypeCd, dto.getGrantTypeCd()); + } + + if (Utils.isNotNull(dto.getDeviceTypeCd())) { + wrapper.eq(SysClient::getDeviceTypeCd, dto.getDeviceTypeCd()); + } + + if (Utils.isNotNull(dto.getActiveTimeout())) { + wrapper.eq(SysClient::getActiveTimeout, dto.getActiveTimeout()); + } + + return wrapper; + } + + private static void formatGrantType(List grantTypeCdList, SysClient sysClient) { + if (!grantTypeCdList.isEmpty()) { + String grantTypes = StreamUtils.listToStr(grantTypeCdList); + sysClient.setGrantTypeCd(grantTypes); + } + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysConfigServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..ca94afc --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,130 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysConfigMapper; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigCreateDTO; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigListDTO; +import com.sz.admin.system.pojo.dto.sysconfig.SysConfigUpdateDTO; +import com.sz.admin.system.pojo.po.SysConfig; +import com.sz.admin.system.pojo.po.table.SysConfigTableDef; +import com.sz.admin.system.pojo.vo.sysconfig.ConfigVO; +import com.sz.admin.system.service.SysConfigService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.service.ConfService; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import com.sz.redis.RedisCache; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + *

+ * 参数配置表 服务实现类 + *

+ * + * @author sz + * @since 2023-11-23 + */ +@Service +@RequiredArgsConstructor +public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService, ConfService { + + private final RedisCache redisCache; + + @Override + public void create(SysConfigCreateDTO dto) { + SysConfig sysConfig = BeanCopyUtils.copy(dto, SysConfig.class); + QueryWrapper wrapper = QueryWrapper.create().where(SysConfigTableDef.SYS_CONFIG.CONFIG_KEY.eq(sysConfig.getConfigKey())); + CommonResponseEnum.EXISTS.message("key已存在").assertTrue(count(wrapper) > 0); + save(sysConfig); + } + + @Override + public void update(SysConfigUpdateDTO dto) { + SysConfig sysConfig = BeanCopyUtils.copy(dto, SysConfig.class); + QueryWrapper wrapper = QueryWrapper.create().where(SysConfigTableDef.SYS_CONFIG.ID.ne(dto.getId())) + .where(SysConfigTableDef.SYS_CONFIG.CONFIG_KEY.eq(dto.getConfigKey())); + CommonResponseEnum.EXISTS.message(2015, "key已存在").assertTrue(count(wrapper) > 0); + saveOrUpdate(sysConfig); + redisCache.clearConf(sysConfig.getConfigKey()); // 清除conf key + } + + @Override + public PageResult list(SysConfigListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create(); + if (Utils.isNotNull(dto.getConfigName())) { + wrapper.where(SysConfigTableDef.SYS_CONFIG.CONFIG_NAME.like(dto.getConfigName())); + } + if (Utils.isNotNull(dto.getConfigKey())) { + wrapper.where(SysConfigTableDef.SYS_CONFIG.CONFIG_KEY.like(dto.getConfigKey())); + } + wrapper.orderBy(SysConfigTableDef.SYS_CONFIG.CREATE_TIME.asc()); + return PageUtils.getPageResult(page(PageUtils.getPage(dto), wrapper)); + } + + @Override + public void remove(SelectIdsDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().where(SysConfigTableDef.SYS_CONFIG.ID.in(dto.getIds())); + List list = list(wrapper); + for (SysConfig sysConfig : list) { + redisCache.clearConf(sysConfig.getConfigKey()); // 清除conf key + redisCache.deleteFrontendConfig(sysConfig.getConfigKey()); + } + + removeByIds(dto.getIds()); + } + + @Override + public SysConfig detail(Object id) { + return getById((Serializable) id); + } + + @Override + public boolean hasConfKey(String key) { + return redisCache.hasConfKey(key); + } + + @Override + public String getConfValue(String key) { + if (hasConfKey(key)) { + return redisCache.getConfValue(key); + } else { + QueryWrapper wrapper = QueryWrapper.create().where(SysConfigTableDef.SYS_CONFIG.CONFIG_KEY.eq(key)); + SysConfig sysConfig = getOne(wrapper); + if (sysConfig != null) { + String value = sysConfig.getConfigValue(); + redisCache.putConf(key, value); + return value; + } + } + return ""; + } + + @Override + public Map getConfigVO() { + Map result = new HashMap<>(); + boolean hasFrontendKey = redisCache.hasFrontendKey(); + if (hasFrontendKey) { + return redisCache.getFrontendConfig(); + } + QueryWrapper wrapper = QueryWrapper.create().where(SysConfigTableDef.SYS_CONFIG.FRONTEND_VISIBLE.eq("T")); + List lists = listAs(wrapper, ConfigVO.class); + if (lists.isEmpty()) + return result; + for (ConfigVO conf : lists) { + result.put(conf.getConfigKey(), conf.getConfigValue()); + } + redisCache.putAllFrontendConfig(result); + return result; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleMenuServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleMenuServiceImpl.java new file mode 100644 index 0000000..748e516 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleMenuServiceImpl.java @@ -0,0 +1,54 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDataRoleMenuMapper; +import com.sz.admin.system.pojo.po.SysDataRoleMenu; +import com.sz.admin.system.service.SysDataRoleMenuService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +import static com.sz.admin.system.pojo.po.table.SysDataRoleMenuTableDef.SYS_DATA_ROLE_MENU; + +/** + *

+ * 系统数据角色-菜单表 服务实现类 + *

+ * + * @author sz + * @since 2024-07-11 + */ +@Deprecated(since = "v1.4.0-beta") +@Service +@RequiredArgsConstructor +public class SysDataRoleMenuServiceImpl extends ServiceImpl implements SysDataRoleMenuService { + + @Override + public void batchSave(Long roleId, List menuIds) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DATA_ROLE_MENU.ROLE_ID.eq(roleId)); + if (count(wrapper) > 0) { + remove(wrapper); + } + + List roleMenus = new ArrayList<>(); + SysDataRoleMenu roleMenu; + for (String menuId : menuIds) { + roleMenu = new SysDataRoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenus.add(roleMenu); + } + if (!roleMenus.isEmpty()) + saveBatch(roleMenus); + } + + @Override + public List getSelectMenuIdByRoleId(Long roleId) { + QueryWrapper wrapper = QueryWrapper.create().select(SYS_DATA_ROLE_MENU.MENU_ID).where(SYS_DATA_ROLE_MENU.ROLE_ID.eq(roleId)); + return listAs(wrapper, String.class); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleRelationServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleRelationServiceImpl.java new file mode 100644 index 0000000..bd64f11 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleRelationServiceImpl.java @@ -0,0 +1,77 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDataRoleRelationMapper; +import com.sz.admin.system.pojo.po.SysDataRoleRelation; +import com.sz.admin.system.service.SysDataRoleRelationService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static com.sz.admin.system.pojo.po.table.SysDataRoleRelationTableDef.SYS_DATA_ROLE_RELATION; + +/** + *

+ * 系统数据角色-关联表 服务实现类 + *

+ * + * @author sz + * @since 2024-07-11 + */ +@Service +@RequiredArgsConstructor +public class SysDataRoleRelationServiceImpl extends ServiceImpl implements SysDataRoleRelationService { + + @Transactional + @Override + public void batchSave(Long roleId, String menuId, String relationTypeCd, List relationIds) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DATA_ROLE_RELATION.ROLE_ID.eq(roleId)) + .where(SYS_DATA_ROLE_RELATION.RELATION_TYPE_CD.eq(relationTypeCd)); + long count = count(wrapper); + if (count > 0) { + remove(wrapper); + } + List roleRelations = new ArrayList<>(); + SysDataRoleRelation roleRelation; + for (Long relationId : relationIds) { + roleRelation = new SysDataRoleRelation(); + roleRelation.setRoleId(roleId); + roleRelation.setRelationId(relationId); + roleRelation.setRelationTypeCd(relationTypeCd); + roleRelation.setMenuId(menuId); + roleRelations.add(roleRelation); + } + if (!roleRelations.isEmpty()) + saveBatch(roleRelations); + } + + @Override + public List getSelectRelationId(Long roleId, String relationTypeCd) { + QueryWrapper wrapper = QueryWrapper.create().select(SYS_DATA_ROLE_RELATION.RELATION_ID).where(SYS_DATA_ROLE_RELATION.ROLE_ID.eq(roleId)) + .where(SYS_DATA_ROLE_RELATION.RELATION_TYPE_CD.eq(relationTypeCd)); + return listAs(wrapper, Long.class); + } + + @Override + public void deleteByRoleId(Long roleId) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DATA_ROLE_RELATION.ROLE_ID.eq(roleId)); + remove(wrapper); + } + + @Override + public List queryRelationByRoleIdAndMenuIds(Long roleId, List menuIds) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DATA_ROLE_RELATION.ROLE_ID.eq(roleId)).where(SYS_DATA_ROLE_RELATION.MENU_ID.in(menuIds)); + return list(wrapper); + } + @Override + public List listByRoleIdsAndMenuIds(Collection roleIds, List menuIds) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DATA_ROLE_RELATION.ROLE_ID.in(roleIds)).where(SYS_DATA_ROLE_RELATION.MENU_ID.in(menuIds)); + return list(wrapper); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleServiceImpl.java new file mode 100644 index 0000000..40b373c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDataRoleServiceImpl.java @@ -0,0 +1,147 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDataRoleMapper; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleCreateDTO; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleListDTO; +import com.sz.admin.system.pojo.dto.sysdatarole.SysDataRoleUpdateDTO; +import com.sz.admin.system.pojo.po.SysDataRole; +import com.sz.admin.system.pojo.po.SysUserDataRole; +import com.sz.admin.system.pojo.vo.sysdatarole.SysDataRoleMenuVO; +import com.sz.admin.system.pojo.vo.sysdatarole.SysDataRoleVO; +import com.sz.admin.system.pojo.vo.sysdept.DeptTreeVO; +import com.sz.admin.system.pojo.vo.sysmenu.MenuTreeVO; +import com.sz.admin.system.pojo.vo.sysuser.UserOptionVO; +import com.sz.admin.system.service.*; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.event.EventPublisher; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import com.sz.platform.event.PermissionChangeEvent; +import com.sz.platform.event.PermissionMeta; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import static com.sz.admin.system.pojo.po.table.SysUserDataRoleTableDef.SYS_USER_DATA_ROLE; + +/** + *

+ * 数据权限管理 服务实现类 + *

+ * + * @author sz + * @since 2024-07-09 + */ +@Service +@RequiredArgsConstructor +@Deprecated(since = "v1.4.0-beta") +public class SysDataRoleServiceImpl extends ServiceImpl implements SysDataRoleService { + + private final SysMenuService sysMenuService; + + private final SysDeptServiceImpl sysDeptService; + + private final SysUserService sysUserService; + + private final SysDataRoleMenuService sysDataRoleMenuService; + + private final SysDataRoleRelationService sysDataRoleRelationService; + + private final EventPublisher eventPublisher; + + @Transactional + @Override + public void create(SysDataRoleCreateDTO dto) { + SysDataRole sysDataRole = BeanCopyUtils.copy(dto, SysDataRole.class); + save(sysDataRole); + sysDataRoleMenuService.batchSave(sysDataRole.getId(), dto.getSelectMenuIds()); + if (Utils.isNotNull(dto.getSelectDeptIds())) + sysDataRoleRelationService.batchSave(sysDataRole.getId(), "", "1007001", dto.getSelectDeptIds()); + if (Utils.isNotNull(dto.getUserOptions())) + sysDataRoleRelationService.batchSave(sysDataRole.getId(), "", "1007002", dto.getUserOptions()); + + } + + @Transactional + @Override + public void update(SysDataRoleUpdateDTO dto) { + SysDataRole sysDataRole = BeanCopyUtils.copy(dto, SysDataRole.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(SysDataRole::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + sysDataRoleMenuService.batchSave(sysDataRole.getId(), dto.getSelectMenuIds()); + sysDataRoleRelationService.batchSave(sysDataRole.getId(), "", "1007001", dto.getSelectDeptIds()); + sysDataRoleRelationService.batchSave(sysDataRole.getId(), "", "1007002", dto.getUserOptions()); + saveOrUpdate(sysDataRole); + + List changeUserIds = QueryChain.of(SysUserDataRole.class) // 查询用户影响范围 + .select(SYS_USER_DATA_ROLE.USER_ID).where(SYS_USER_DATA_ROLE.ROLE_ID.eq(dto.getId())).listAs(Long.class); + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(changeUserIds))); + } + + @Override + public PageResult page(SysDataRoleListDTO dto) { + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), SysDataRoleVO.class); + return PageUtils.getPageResult(page); + } + + @Override + public List list(SysDataRoleListDTO dto) { + return listAs(buildQueryWrapper(dto), SysDataRoleVO.class); + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public SysDataRoleVO detail(Object id) { + Long longVal = Utils.getLongVal(id); + SysDataRole sysDataRole = getById(longVal); + CommonResponseEnum.INVALID_ID.assertNull(sysDataRole); + List menuIds = sysDataRoleMenuService.getSelectMenuIdByRoleId(Utils.getLongVal(id)); + List deptIds = sysDataRoleRelationService.getSelectRelationId(Utils.getLongVal(id), "1007001"); + List userOptions = sysDataRoleRelationService.getSelectRelationId(Utils.getLongVal(id), "1007002"); + SysDataRoleVO vo = BeanCopyUtils.copy(sysDataRole, SysDataRoleVO.class); + vo.setSelectMenuIds(menuIds); + vo.setSelectDeptIds(deptIds); + vo.setUserOptions(userOptions); + return vo; + } + + private static QueryWrapper buildQueryWrapper(SysDataRoleListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(SysDataRole.class); + if (Utils.isNotNull(dto.getRoleName())) { + wrapper.like(SysDataRole::getRoleName, dto.getRoleName()); + } + if (Utils.isNotNull(dto.getIsLock())) { + wrapper.eq(SysDataRole::getIsLock, dto.getIsLock()); + } + return wrapper; + } + + @Override + public SysDataRoleMenuVO queryDataRoleMenu() { + SysDataRoleMenuVO menuVO = new SysDataRoleMenuVO(); + List menuTreeVOS = sysMenuService.queryDataRoleMenu(); + List deptTreeVOS = sysDeptService.getDeptTree(null, false, false); + List userOptions = sysUserService.getUserOptions(); + menuVO.setMenuLists(menuTreeVOS); + menuVO.setDeptLists(deptTreeVOS); + menuVO.setUserOptions(userOptions); + return menuVO; + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptClosureServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptClosureServiceImpl.java new file mode 100644 index 0000000..86662db --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptClosureServiceImpl.java @@ -0,0 +1,123 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryMethods; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDeptClosureMapper; +import com.sz.admin.system.pojo.po.SysDeptClosure; +import com.sz.admin.system.service.SysDeptClosureService; +import com.sz.core.common.enums.CommonResponseEnum; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static com.sz.admin.system.pojo.po.table.SysDeptClosureTableDef.SYS_DEPT_CLOSURE; + +/** + *

+ * 部门祖籍关系表 服务实现类 + *

+ * + * @author sz + * @since 2024-03-28 + */ +@Service +@RequiredArgsConstructor +public class SysDeptClosureServiceImpl extends ServiceImpl implements SysDeptClosureService { + + @Override + public List ancestorsPath(Long nodeId) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DEPT_CLOSURE.DESCENDANT_ID.eq(nodeId)).where(SYS_DEPT_CLOSURE.ANCESTOR_ID.ne(nodeId)) + .where(SYS_DEPT_CLOSURE.DEPTH.gt(0)); + return list(wrapper); + } + + @Override + public void create(Long nodeId, Long pid) { + List closures = new ArrayList<>(); + List pathList = ancestorsPath(pid); + for (SysDeptClosure path : pathList) { + SysDeptClosure closure = buildClosure(path.getAncestorId(), nodeId, path.getDepth() + 1); + closures.add(closure); + } + // self + SysDeptClosure self = buildClosure(nodeId, nodeId, 0); + // parent + SysDeptClosure parent = buildClosure(pid, nodeId, 1); + closures.add(self); + closures.add(parent); + saveBatch(closures); + } + + @Override + @Transactional + public void remove(Long nodeId) { + SysDeptClosure one = getById(nodeId); + CommonResponseEnum.INVALID_ID.assertNull(one); + List desList = descendants(nodeId); + for (SysDeptClosure closure : desList) { + QueryWrapper removeWrapper = QueryWrapper.create().eq(SysDeptClosure::getAncestorId, closure.getAncestorId()).eq(SysDeptClosure::getDescendantId, + closure.getDescendantId()); + remove(removeWrapper); + } + removeById(nodeId); + } + + /** + * 查询所有子孙节点 + * + * @param nodeId + * 节点ID + * @return 子孙节点 + */ + public List descendants(Long nodeId) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DEPT_CLOSURE.ANCESTOR_ID.eq(nodeId)).where(SYS_DEPT_CLOSURE.DESCENDANT_ID.ne(nodeId)); + return list(wrapper); + } + + /** + * 查询指定祖籍节点的所有子孙节点 + * + * @param ancestorIds + * 祖籍节点ID + * @return 子孙节点ID + */ + @Override + public List descendants(List ancestorIds) { + if (ancestorIds.isEmpty()) { + return new ArrayList<>(); + } + QueryWrapper wrapper = QueryWrapper.create().select(QueryMethods.distinct(SYS_DEPT_CLOSURE.DESCENDANT_ID)) + .where(SYS_DEPT_CLOSURE.ANCESTOR_ID.in(ancestorIds)); + return listAs(wrapper, Long.class); + } + + /** + * 移动子树 + */ + @Override + public void move(Long nodeId, Long newNodeId) { + if (Objects.equals(nodeId, newNodeId)) + return; + List closures = this.mapper.selectDetachTree(nodeId); + for (SysDeptClosure closure : closures) { + QueryWrapper removeWrapper = QueryWrapper.create().eq(SysDeptClosure::getAncestorId, closure.getAncestorId()).eq(SysDeptClosure::getDescendantId, + closure.getDescendantId()); + remove(removeWrapper); + } + this.mapper.graft(nodeId, newNodeId); + } + + private SysDeptClosure buildClosure(Long ancestorId, Long descendantId, Integer depth) { + SysDeptClosure closure = new SysDeptClosure(); + closure.setAncestorId(ancestorId); + closure.setDescendantId(descendantId); + closure.setDepth(depth); + return closure; + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptLeaderServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptLeaderServiceImpl.java new file mode 100644 index 0000000..4eff37a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptLeaderServiceImpl.java @@ -0,0 +1,40 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDeptLeaderMapper; +import com.sz.admin.system.pojo.po.SysDeptLeader; +import com.sz.admin.system.service.SysDeptLeaderService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + *

+ * 部门领导人表 服务实现类 + *

+ * + * @author sz + * @since 2024-03-26 + */ +@Service +@RequiredArgsConstructor +public class SysDeptLeaderServiceImpl extends ServiceImpl implements SysDeptLeaderService { + + @Override + public void syncLeader(Long deptId, List leaderIds) { + QueryWrapper wrapper = QueryWrapper.create().eq(SysDeptLeader::getDeptId, deptId); + remove(wrapper); // 清除旧的信息 + List deptLeaders = new ArrayList<>(); + for (Long leaderId : leaderIds) { + SysDeptLeader deptLeader = new SysDeptLeader(); + deptLeader.setDeptId(deptId); + deptLeader.setLeaderId(leaderId); + deptLeaders.add(deptLeader); + } + saveBatch(deptLeaders); // 批量生成新的信息 + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 0000000..61d7e27 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,397 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.logicdelete.LogicDeleteManager; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryMethods; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.*; +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptCreateDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptListDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptRoleDTO; +import com.sz.admin.system.pojo.dto.sysdept.SysDeptUpdateDTO; +import com.sz.admin.system.pojo.po.*; +import com.sz.admin.system.pojo.vo.common.DepartmentVO; +import com.sz.admin.system.pojo.vo.sysdept.*; +import com.sz.admin.system.service.SysDeptClosureService; +import com.sz.admin.system.service.SysDeptLeaderService; +import com.sz.admin.system.service.SysDeptService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.event.EventPublisher; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.TreeUtils; +import com.sz.core.util.Utils; +import com.sz.platform.event.PermissionChangeEvent; +import com.sz.platform.event.PermissionMeta; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import static com.mybatisflex.core.query.QueryMethods.*; +import static com.sz.admin.system.pojo.po.table.SysDeptLeaderTableDef.SYS_DEPT_LEADER; +import static com.sz.admin.system.pojo.po.table.SysDeptRoleTableDef.SYS_DEPT_ROLE; +import static com.sz.admin.system.pojo.po.table.SysDeptTableDef.SYS_DEPT; +import static com.sz.admin.system.pojo.po.table.SysRoleTableDef.SYS_ROLE; +import static com.sz.admin.system.pojo.po.table.SysUserDeptTableDef.SYS_USER_DEPT; +import static com.sz.admin.system.pojo.po.table.SysUserTableDef.SYS_USER; + +/** + *

+ * 部门表 服务实现类 + *

+ * + * @author sz + * @since 2024-03-20 + */ +@Service +@RequiredArgsConstructor +public class SysDeptServiceImpl extends ServiceImpl implements SysDeptService { + + private final SysUserMapper userMapper; + + private final SysRoleMapper sysRoleMapper; + + private final SysDeptRoleMapper sysDeptRoleMapper; + + private final SysUserDeptMapper sysUserDeptMapper; + + private final SysUserRoleMapper sysUserRoleMapper; + + private final SysDeptLeaderMapper leaderMapper; + + private final SysDeptLeaderService deptLeaderService; + + private final SysDeptClosureService deptClosureService; + + private final EventPublisher eventPublisher; + + @Transactional + @Override + public void create(SysDeptCreateDTO dto) { + SysDept sysDept = BeanCopyUtils.copy(dto, SysDept.class); + if (dto.getPid() == 0) { + sysDept.setDeep(1); + } else { + QueryWrapper wrapper = QueryWrapper.create().eq(SysDept::getId, dto.getPid()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + SysDept parentDept = getOne(wrapper); + parentDept.setHasChildren("T"); + saveOrUpdate(parentDept); + sysDept.setDeep(parentDept.getDeep() + 1); + } + save(sysDept); + Long deptId = sysDept.getId(); + Long pid = dto.getPid(); + // 设置负责人 + deptLeaderService.syncLeader(deptId, dto.getLeaders()); + deptClosureService.create(deptId, pid); + + } + + @Transactional + @Override + public void update(SysDeptUpdateDTO dto) { + SysDept sysDept = BeanCopyUtils.copy(dto, SysDept.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(SysDept::getId, dto.getId()); + SysDept one = getOne(wrapper); + Long oldPid = one.getPid(); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + if (dto.getPid() == 0) { + sysDept.setDeep(1); + } else { + wrapper = QueryWrapper.create().eq(SysDept::getId, dto.getPid()); + SysDept parent = getOne(wrapper); + one.setHasChildren("T"); + saveOrUpdate(one); + sysDept.setDeep(parent.getDeep() + 1); + } + // 设置负责人 + deptLeaderService.syncLeader(dto.getId(), dto.getLeaders()); + saveOrUpdate(sysDept); + // 移动树 + if (!Objects.equals(oldPid, dto.getPid())) { + deptClosureService.move(dto.getId(), dto.getPid()); + } + } + + @Override + public PageResult page(SysDeptListDTO dto) { + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), SysDeptVO.class); + return PageUtils.getPageResult(page); + } + + @Override + public List list(SysDeptListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create() + .select(SYS_DEPT.ALL_COLUMNS, QueryMethods.groupConcat(if_(SYS_USER.DEL_FLAG.eq("F"), SYS_DEPT_LEADER.LEADER_ID, null_())).as("leader_ids")) + .from(SYS_DEPT).leftJoin(SYS_DEPT_LEADER).on(SYS_DEPT.ID.eq(SYS_DEPT_LEADER.DEPT_ID)).leftJoin(SYS_USER) + .on(SYS_DEPT_LEADER.LEADER_ID.eq(SYS_USER.ID)).groupBy(SYS_DEPT.ID); + + List deptVOS = listAs(wrapper, SysDeptVO.class); + setDeptRoleInfo(deptVOS); + SysDeptVO root = TreeUtils.getRoot(SysDeptVO.class); + List trees = TreeUtils.buildTree(deptVOS, root); + return trees.getFirst().getChildren(); + } + + /** + * 添加部门关联角色信息 + */ + private void setDeptRoleInfo(List deptList) { + if (deptList.isEmpty()) { + return; + } + // 获取所有部门的 ID 列表,查询角色信息 + List deptIds = deptList.stream().map(SysDeptVO::getId).collect(Collectors.toList()); + List deptRoleInfoVOS = QueryChain.of(this.mapper).select(SYS_DEPT.ID.as("deptId"), SYS_ROLE.ID.as("roleId")).from(SYS_DEPT) + .leftJoin(SYS_DEPT_ROLE).on(SYS_DEPT.ID.eq(SYS_DEPT_ROLE.DEPT_ID)).leftJoin(SYS_ROLE).on(SYS_DEPT_ROLE.ROLE_ID.eq(SYS_ROLE.ID)) + .and(SYS_DEPT.ID.in(deptIds)).and(SYS_ROLE.ID.isNotNull()).listAs(DeptRoleInfoVO.class); + Map> roleInfoMap = deptRoleInfoVOS.stream().collect(Collectors.groupingBy(DeptRoleInfoVO::getDeptId)); + + // 遍历部门列表,设置部门的角色信息 + for (SysDeptVO dept : deptList) { + if (roleInfoMap.containsKey(dept.getId())) { + List deptRoleInfos = roleInfoMap.get(dept.getId()); + dept.setRoleIds(deptRoleInfos.stream().map(DeptRoleInfoVO::getRoleId).collect(Collectors.joining(","))); + } + } + } + + @Override + public void remove(SelectIdsDTO dto) { + List ids = (List) dto.getIds(); + CommonResponseEnum.INVALID_ID.assertTrue(ids.isEmpty()); + // 根据要删除的id,获取所有子集id + List descendants = deptClosureService.descendants(ids); + removeByIds(descendants); + } + + @Override + public SysDeptVO detail(Object id) { + SysDept sysDept = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(sysDept); + SysDeptVO deptVO = BeanCopyUtils.copy(sysDept, SysDeptVO.class); + // 查询指定部门的负责人 + List leaderIds = QueryChain.of(leaderMapper).select(SYS_DEPT_LEADER.LEADER_ID).eq(SysDeptLeader::getDeptId, id).listAs(Long.class); + deptVO.setLeaders(leaderIds); + return deptVO; + } + + @Override + public List getDepartmentTreeWithAdditionalNodes() { + // 获取部门树 + List trees = getDeptTree(null, false, true); + // 获取所有用户数量 + long allUserCount = count(QueryWrapper.create().from(SysUser.class)); + // 获取未设置部门的用户数量 + long unsetDeptCount = userMapper.countSysUserListNotDept(); + // 创建全部节点 + DeptTreeVO all = createAllNode(allUserCount); + // 创建未设置部门节点 + DeptTreeVO unset = createUnsetNode(unsetDeptCount); + // 将‘全部’、‘未设置部门’节点添加到集合头部 + trees.add(0, all); + trees.add(1, unset); + return trees; + } + + private DeptTreeVO createUnsetNode(Long unsetDeptCount) { + DeptTreeVO unset = new DeptTreeVO(); + unset.setId(-2L); + unset.setName("未设置部门"); + AtomicReference total = new AtomicReference<>(0L); + LogicDeleteManager.execWithoutLogicDelete(() -> total.set(unsetDeptCount)); + unset.setUserTotal(total.get()); + return unset; + } + + private DeptTreeVO createAllNode(Long userCount) { + DeptTreeVO all = new DeptTreeVO(); + all.setId(-1L); + all.setName("全部"); + all.setUserTotal(userCount); + return all; + } + + @Override + public List getDeptTree(Integer excludeNodeId, Boolean appendRoot, Boolean needSetTotal) { + QueryWrapper wrapper = QueryWrapper.create() + // .orderBy(SysDept::getDeep).asc() + .orderBy(SysDept::getSort).asc(); + // 获取所有部门信息 + List list = list(wrapper); + List deptTreeVOS = BeanCopyUtils.copyList(list, DeptTreeVO.class); + if (needSetTotal != null && needSetTotal) { + setUseTotal(deptTreeVOS); + } + DeptTreeVO root = TreeUtils.getRoot(DeptTreeVO.class); + assert root != null; + root.setName("根部门"); + List trees = TreeUtils.buildTree(deptTreeVOS, root, excludeNodeId); + if (appendRoot != null && !appendRoot) { + if (trees.getFirst().getChildren() == null) { + trees = new ArrayList<>(); + } else { + trees = trees.getFirst().getChildren(); + } + } + return trees; + } + + private void setUseTotal(List deptTreeVOS) { + // 查询直属部门的数量 + QueryWrapper wrapper = QueryWrapper.create() + .select(SYS_DEPT.ID, SYS_DEPT.NAME, QueryMethods.count(case_().when(SYS_USER.DEL_FLAG.eq("F")).then(SYS_USER_DEPT.USER_ID).end()).as("total")) + .from(SYS_DEPT).leftJoin(SYS_USER_DEPT).on(SYS_DEPT.ID.eq(SYS_USER_DEPT.DEPT_ID)).leftJoin(SYS_USER).on(SYS_USER_DEPT.USER_ID.eq(SYS_USER.ID)) + .groupBy(SYS_DEPT.ID, SYS_DEPT.NAME).orderBy(SYS_DEPT.DEEP.asc()).orderBy(SYS_DEPT.SORT.asc()); + List totalDeptVOS = listAs(wrapper, TotalDeptVO.class); + + /* + * 查询非直属部门的数量。 + * + * SQL 查询语句: SELECT d.id, d.name, COUNT(ud.user_id) AS total FROM sys_dept d + * LEFT JOIN sys_dept_closure c ON d.id = c.ancestor_id LEFT JOIN sys_user_dept + * ud ON c.descendant_id = ud.dept_id GROUP BY d.id, d.name; + * + * 该查询通过 `LEFT JOIN` 连接 `sys_dept`、`sys_dept_closure` 和 `sys_user_dept` 三个表, + * 统计每个部门下非直属的用户数量,并按部门 ID 和名称分组。 + */ + Map totalDeptMap = new HashMap<>(); + if (totalDeptVOS != null) { + totalDeptMap = totalDeptVOS.stream().collect(Collectors.toMap(TotalDeptVO::getId, TotalDeptVO::getTotal)); + } + for (DeptTreeVO treeVO : deptTreeVOS) { + if (totalDeptMap.containsKey(treeVO.getId())) { + treeVO.setUserTotal(totalDeptMap.get(treeVO.getId())); + } + } + } + + /** + * 查询部门leader信息-穿梭框 + * + * @return SysDeptLeaderVO + */ + @Override + public SysDeptLeaderVO findSysUserDeptLeader() { + // 查询所有的用户 + List userInfos = QueryChain.of(userMapper).eq(SysUser::getDelFlag, "F").listAs(SysDeptLeaderVO.LeaderInfoVO.class); + SysDeptLeaderVO leaderVO = new SysDeptLeaderVO(); + leaderVO.setLeaderInfoVOS(userInfos); + return leaderVO; + } + + /** + * 部门角色信息查询 + * + * @param deptId + * 部门id + */ + @Override + public SysDeptRoleVO findSysDeptRole(Long deptId) { + List sysRoleList = QueryChain.of(this.sysRoleMapper).list(); + List roleInfoVOS = BeanCopyUtils.copyList(sysRoleList, SysDeptRoleVO.RoleInfoVO.class); + List deptRoles = QueryChain.of(sysDeptRoleMapper).eq(SysDeptRole::getDeptId, deptId).list(); + List roleIds = new ArrayList<>(); + if (Utils.isNotNull(deptRoles)) { + roleIds = deptRoles.stream().map(SysDeptRole::getRoleId).collect(Collectors.toList()); + } + SysDeptRoleVO sysDeptRoleVO = new SysDeptRoleVO(); + sysDeptRoleVO.setRoleInfoVOS(roleInfoVOS); + sysDeptRoleVO.setSelectIds(roleIds); + return sysDeptRoleVO; + } + + @Override + public void changeSysDeptRole(SysDeptRoleDTO dto) { + Long deptId = dto.getDeptId(); + List roleIds = dto.getRoleIds(); + // 删除当前部门下的所有角色 + UpdateChain.of(sysDeptRoleMapper).eq(SysDeptRole::getDeptId, deptId).remove(); + + if (Utils.isNotNull(roleIds)) { + List deptRoles = dto.getRoleIds().stream().map(roleId -> { + SysDeptRole sysDataRole = new SysDeptRole(); + sysDataRole.setRoleId(roleId); + sysDataRole.setDeptId(deptId); + return sysDataRole; + }).toList(); + sysDeptRoleMapper.insertBatch(deptRoles); + + // 查询当前部门下所有用户 + List userDepts = QueryChain.of(sysUserDeptMapper).eq(SysUserDept::getDeptId, deptId).list(); + List userIdList = userDepts.stream().map(SysUserDept::getUserId).distinct().toList(); + if (userIdList.isEmpty()) { + return; + } + + // 查询并插入用户需要绑定的新角色 + List userRoleList = userRoleLinkData(userIdList, roleIds); + if (Utils.isNotNull(userRoleList)) { + sysUserRoleMapper.insertBatch(userRoleList); + List changeUserIds = userRoleList.stream().map(SysUserRole::getUserId).distinct().toList(); + // 触发更新用户元数据事件 + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(changeUserIds))); + } + } + } + + /** + * 构造用户角色关联数据 + */ + private List userRoleLinkData(List userIdList, List roleIds) { + // 查询当前用户已有的角色 + List existingUserRoles = QueryChain.of(sysUserRoleMapper).in(SysUserRole::getUserId, userIdList).list(); + + // 将用户角色关联信息作为key + Set existingBindings = existingUserRoles.stream().map(ur -> ur.getUserId() + "_" + ur.getRoleId()).collect(Collectors.toSet()); + List newUserRoles = new ArrayList<>(); + // 循环判断色插用户需要绑定的角色 + for (Long userId : userIdList) { + for (Long roleId : roleIds) { + // 检查绑定是否已存在 + String bindingKey = userId + "_" + roleId; + if (!existingBindings.contains(bindingKey)) { + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(userId); + userRole.setRoleId(roleId); + newUserRoles.add(userRole); + } + } + } + return newUserRoles; + } + + private static QueryWrapper buildQueryWrapper(SysDeptListDTO dto) { + return QueryWrapper.create().from(SysDept.class); + } + + @Override + public List listSelector(SelectorQueryDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().select(SYS_DEPT.ID, SYS_DEPT.PID, SYS_DEPT.NAME, SYS_DEPT.SORT, SYS_DEPT.DEEP) + .orderBy(SYS_DEPT.SORT.asc()); + // 获取所有部门信息 + List list = listAs(wrapper, DepartmentVO.class); + return TreeUtils.buildTree(list, 0); + } + + @Override + public List getDeptOptions() { + QueryWrapper wrapper = QueryWrapper.create().select(SYS_DEPT.ID, SYS_DEPT.NAME).from(SYS_DEPT).orderBy(SYS_DEPT.SORT.asc()); + return listAs(wrapper, DeptOptionsVO.class); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDictServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDictServiceImpl.java new file mode 100644 index 0000000..9c009ed --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDictServiceImpl.java @@ -0,0 +1,228 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.logicdelete.LogicDeleteManager; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDictMapper; +import com.sz.admin.system.mapper.SysDictTypeMapper; +import com.sz.admin.system.pojo.dto.sysdict.SysDictCreateDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictListDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictUpdateDTO; +import com.sz.admin.system.pojo.po.SysDict; +import com.sz.admin.system.pojo.po.SysDictType; +import com.sz.admin.system.pojo.po.table.SysDictTableDef; +import com.sz.admin.system.service.SysDictService; +import com.sz.admin.system.service.SysDictTypeService; +import com.sz.core.common.entity.DictVO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.dict.DictService; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.StreamUtils; +import com.sz.core.util.Utils; +import com.sz.generator.service.GeneratorTableService; +import com.sz.core.common.dict.DictLoaderFactory; +import com.sz.redis.RedisCache; +import com.sz.socket.SocketService; +import freemarker.template.Template; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.io.StringWriter; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import static com.sz.admin.system.pojo.po.table.SysDictTypeTableDef.SYS_DICT_TYPE; + +/** + *

+ * 字典表 服务实现类 + *

+ * + * @author sz + * @since 2023-08-18 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class SysDictServiceImpl extends ServiceImpl implements SysDictService, DictService { + + private final SysDictTypeMapper sysDictTypeMapper; + + private final SysDictTypeService sysDictTypeService; + + private final RedisCache redisCache; + + private final GeneratorTableService generatorTableService; + + private final DictLoaderFactory dictLoaderFactory; + + private final SocketService socketService; + + private static Long generateCustomId(Long firstPart, int secondPart) { + secondPart += 1; + String paddedFirstPart = String.format("%04d", firstPart); // 格式化为四位数字,不足补零 + String paddedSecondPart = String.format("%03d", secondPart); // 格式化为三位数字,不足补零 + String part = paddedFirstPart + paddedSecondPart; + return Long.valueOf(part); + } + + @Override + public void create(SysDictCreateDTO dto) { + SysDict sysDict = BeanCopyUtils.copy(dto, SysDict.class); + QueryWrapper wrapper; + long count = QueryChain.of(sysDictTypeMapper).eq(SysDictType::getId, dto.getSysDictTypeId()).count(); + CommonResponseEnum.NOT_EXISTS.message("SYS_DICT_TYPE不存在").assertTrue(count < 1); + + wrapper = QueryWrapper.create().where(SysDictTableDef.SYS_DICT.SYS_DICT_TYPE_ID.eq(dto.getSysDictTypeId())) + .where(SysDictTableDef.SYS_DICT.CODE_NAME.eq(dto.getCodeName())); + CommonResponseEnum.EXISTS.message("字典已存在").assertTrue(count(wrapper) > 0); + + wrapper = QueryWrapper.create().where(SysDictTableDef.SYS_DICT.SYS_DICT_TYPE_ID.eq(dto.getSysDictTypeId())); + AtomicReference dictCount = new AtomicReference<>(0L); + QueryWrapper finalWrapper = wrapper; + // 跳过逻辑删除,查询真实count数 + LogicDeleteManager.execWithoutLogicDelete(() -> dictCount.set(count(finalWrapper))); + Long generateCustomId = generateCustomId(dto.getSysDictTypeId(), dictCount.get().intValue()); + sysDict.setId(generateCustomId); + save(sysDict); + upCache(dto.getSysDictTypeId()); + socketService.syncDict(); + } + + @Override + public void update(SysDictUpdateDTO dto) { + SysDict sysDict = BeanCopyUtils.copy(dto, SysDict.class); + long count = QueryChain.of(this.mapper).select().from(SysDictTableDef.SYS_DICT).where(SysDictTableDef.SYS_DICT.ID.ne(dto.getId())) + .and(SysDictTableDef.SYS_DICT.SYS_DICT_TYPE_ID.eq(dto.getSysDictTypeId())).and(SysDictTableDef.SYS_DICT.CODE_NAME.eq(dto.getCodeName())) + .count(); + CommonResponseEnum.EXISTS.message(SysDictTableDef.SYS_DICT.CODE_NAME.getName() + "已存在").assertTrue(count > 0); + sysDict.setId(dto.getId()); + saveOrUpdate(sysDict); + upCache(dto.getSysDictTypeId()); + socketService.syncDict(); + } + + private void upCache(Long dictTypeId) { + SysDictType sysDictType = sysDictTypeService.detail(dictTypeId); + String typeCode = sysDictType.getTypeCode(); + redisCache.clearDict(typeCode); // 清除redis缓存 + dictLoaderFactory.getDictByType(typeCode); // 更新缓存 + socketService.syncDict(); + } + + @Override + public void remove(SelectIdsDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().where(SysDictTableDef.SYS_DICT.ID.in(dto.getIds())); + List list = list(wrapper); + for (SysDict sysDict : list) { + SysDictType sysDictType = sysDictTypeService.detail(sysDict.getSysDictTypeId()); + redisCache.clearDict(sysDictType.getTypeCode()); // 清除redis缓存 + } + removeByIds(dto.getIds()); + socketService.syncDict(); + } + + @Override + public PageResult list(SysDictListDTO dto) { + QueryChain chain = QueryChain.of(this.mapper).select().from(SysDictTableDef.SYS_DICT) + .where(SysDictTableDef.SYS_DICT.SYS_DICT_TYPE_ID.eq(dto.getSysDictTypeId())); + if (Utils.isNotNull(dto.getCodeName())) { + chain.and(SysDictTableDef.SYS_DICT.CODE_NAME.like(dto.getCodeName())); + } + Page page = chain.orderBy(SysDictTableDef.SYS_DICT.SORT.asc()).page(PageUtils.getPage(dto)); + return PageUtils.getPageResult(page); + } + + @Override + public Map> dictList(String typeCode) { + Map> result = new HashMap<>(); + Map> allDict = dictLoaderFactory.loadAllDict(); + if (allDict.containsKey(typeCode)) { + return dictLoaderFactory.loadAllDict(); + } + // 如果查询不到,从数据库中获取,并赋值 + List dictVOS = this.mapper.listDict(typeCode); + if (!dictVOS.isEmpty()) { + redisCache.setDict(typeCode, dictVOS); + result = dictVOS.stream().collect(Collectors.groupingBy(DictVO::getSysDictTypeCode, LinkedHashMap::new, Collectors.toList())); + } + return result; + } + + @Override + public Map> dictAll() { + return dictLoaderFactory.loadAllDict(); + } + + @Override + public List getDictByType(String typeCode) { + return dictLoaderFactory.getDictByType(typeCode); + } + + @Override + public String getDictLabel(String dictType, String dictValue, String separator) { + List dictLists = dictLoaderFactory.getDictByType(dictType); + Map map = StreamUtils.toMap(dictLists, DictVO::getId, vo -> vo.getCodeName() != null ? vo.getCodeName() : ""); // {"1000003":"禁言","1000002":"禁用","1000001":"正常"} + return map.getOrDefault(dictValue, ""); + } + + @Override + public String getDictValue(String dictType, String dictLabel, String separator) { + List dictLists = dictLoaderFactory.getDictByType(dictType); + Map map = StreamUtils.toMap(dictLists, DictVO::getCodeName, DictVO::getId); // {"禁言":"1000003","禁用":"1000002","正常":"1000001"} + return map.getOrDefault(dictLabel, ""); + } + + @Override + public Map getAllDictByType(String dictType) { + List dictLists = dictLoaderFactory.getDictByType(dictType); + if (dictLists.isEmpty()) { + return new HashMap<>(); + } + return StreamUtils.toMap(dictLists, DictVO::getCodeName, DictVO::getId); + } + + @Override + public Map> getAllDict() { + return dictLoaderFactory.loadAllDict(); + } + + @SneakyThrows + @Override + public String exportDictSql(SelectIdsDTO dto) { + String generatedContent = ""; + if (Utils.isNotNull(dto.getIds())) { + List dictTypeList = QueryChain.of(SysDictType.class).where(SYS_DICT_TYPE.ID.in(dto.getIds())).list(); + + QueryWrapper queryWrapper = QueryWrapper.create().in(SysDict::getSysDictTypeId, dto.getIds()).orderBy(SysDict::getSysDictTypeId).asc() + .orderBy(SysDict::getSort).asc(); + List dictList = list(queryWrapper); + Map dataModel = new HashMap<>(); + dataModel.put("dictTypeList", dictTypeList); + dataModel.put("dictList", dictList); + Template template = generatorTableService.getDictSqlTemplate(); + try (StringWriter writer = new StringWriter()) { + template.process(dataModel, writer); + generatedContent = writer.toString(); + } catch (Exception e) { + log.error("exportDictSql err", e); + } + + } + return generatedContent; + } + + @Override + public Map> getDictByCode(List typeCode) { + return typeCode.stream().collect(Collectors.toMap(code -> code, this::getDictByType)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDictTypeServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000..6cf4ea2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,142 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.logicdelete.LogicDeleteManager; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryMethods; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDictTypeMapper; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeAddDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeListDTO; +import com.sz.admin.system.pojo.dto.sysdict.SysDictTypeUpDTO; +import com.sz.admin.system.pojo.po.SysDictType; +import com.sz.core.common.dict.DictTypeService; +import com.sz.core.common.dict.DictTypeVO; +import com.sz.admin.system.service.SysDictTypeService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.SysConfigUtils; +import com.sz.core.util.Utils; +import com.sz.core.common.dict.DictLoaderFactory; +import com.sz.redis.RedisCache; +import com.sz.socket.SocketService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +import static com.sz.admin.system.pojo.po.table.SysDictTypeTableDef.SYS_DICT_TYPE; + +/** + *

+ * 字典类型 服务实现类 + *

+ * + * @author sz + * @since 2023-08-18 + */ +@Service +@RequiredArgsConstructor +public class SysDictTypeServiceImpl extends ServiceImpl implements SysDictTypeService, DictTypeService { + + private final DictLoaderFactory dictLoaderFactory; + + private final RedisCache redisCache; + + private final SocketService socketService; + + @Override + public void create(SysDictTypeAddDTO dto) { + String confValue = SysConfigUtils.getConfValue("sys.dict.startNo"); + SysDictType sysDictType = BeanCopyUtils.copy(dto, SysDictType.class); + String type = dto.getType(); + if ("system".equals(type)) { // 系统字典 + AtomicReference maxId = new AtomicReference<>(0L); + LogicDeleteManager.execWithoutLogicDelete(() -> { + Long count = QueryChain.of(SysDictType.class).select(QueryMethods.max(SYS_DICT_TYPE.ID)).from(SYS_DICT_TYPE) + .where(SYS_DICT_TYPE.ID.lt(confValue)).oneAs(Long.class); + maxId.set(count); + }); + sysDictType.setId(maxId.get() + 1); + } else { + AtomicReference maxId = new AtomicReference<>(0L); + LogicDeleteManager.execWithoutLogicDelete(() -> { + Long count = QueryChain.of(SysDictType.class).select(QueryMethods.max(SYS_DICT_TYPE.ID)).from(SYS_DICT_TYPE) + .where(SYS_DICT_TYPE.ID.ge(confValue)).oneAs(Long.class); + maxId.set(count); + }); + if (Utils.isNotNull(maxId) && Utils.isNotNull(maxId.get())) { + sysDictType.setId(maxId.get() + 1); + } else { + sysDictType.setId(Utils.getLongVal(confValue)); + } + } + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DICT_TYPE.TYPE_CODE.eq(dto.getTypeCode())); + CommonResponseEnum.EXISTS.message("typeCode已存在").assertTrue(count(wrapper) > 0); + save(sysDictType); + } + + @Override + public void update(SysDictTypeUpDTO dto) { + SysDictType sysDictType = BeanCopyUtils.copy(dto, SysDictType.class); + sysDictType.setId(dto.getId()); + SysDictType oldDetail = detail(dto.getId()); + // 修改时的重复性效验需要排除本身 + QueryWrapper wrapper = QueryWrapper.create().where(SYS_DICT_TYPE.TYPE_CODE.eq(dto.getTypeCode())).where(SYS_DICT_TYPE.ID.ne(dto.getId())); + CommonResponseEnum.EXISTS.message("typeCode已存在").assertTrue(count(wrapper) > 0); + saveOrUpdate(sysDictType); + redisCache.clearDict(oldDetail.getTypeCode()); // 清除redis缓存 + dictLoaderFactory.getDictByType(sysDictType.getTypeCode()); // 更新缓存 + socketService.syncDict(); + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertNull(dto.getIds()); + QueryWrapper wrapper = QueryWrapper.create().select(SYS_DICT_TYPE.TYPE_CODE).where(SYS_DICT_TYPE.ID.in(dto.getIds())); + List typeCodes = listAs(wrapper, String.class); + for (String typeCode : typeCodes) { + redisCache.clearDict(typeCode); // 清除redis缓存 + } + removeByIds(dto.getIds()); + socketService.syncDict(); + } + + @Override + public SysDictType detail(Long id) { + SysDictType dictType = getById(id); + CommonResponseEnum.INVALID_ID.assertNull(dictType); + return dictType; + } + + @Override + public PageResult list(SysDictTypeListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create(); + if (Utils.isNotNull(dto.getTypeName())) { + wrapper.where(SYS_DICT_TYPE.TYPE_NAME.like(dto.getTypeName())); + } + if (Utils.isNotNull(dto.getTypeCode())) { + wrapper.where(SYS_DICT_TYPE.TYPE_CODE.like(dto.getTypeCode())); + } + wrapper.orderBy(SYS_DICT_TYPE.CREATE_TIME.asc()); + Page page = page(PageUtils.getPage(dto), wrapper); + return PageUtils.getPageResult(page); + } + + @Override + public List findDictType() { + QueryWrapper wrapper = QueryWrapper.create().orderBy(SYS_DICT_TYPE.CREATE_TIME.desc()); + return listAs(wrapper, DictTypeVO.class); + } + + @Override + public List selectDictTypeOptions() { + return dictLoaderFactory.getAllDictType(); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysFileServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysFileServiceImpl.java new file mode 100644 index 0000000..fd5de5f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysFileServiceImpl.java @@ -0,0 +1,93 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.CommonFileMapper; +import com.sz.admin.system.pojo.dto.sysfile.SysFileListDTO; +import com.sz.admin.system.pojo.po.SysFile; +import com.sz.admin.system.pojo.po.table.SysFileTableDef; +import com.sz.admin.system.service.SysFileService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import com.sz.oss.OssClient; +import com.sz.core.common.entity.UploadResult; +import com.sz.oss.OssProperties; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +/** + *

+ * 服务实现类 + *

+ * + * @author sz + * @since 2023-08-31 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class SysFileServiceImpl extends ServiceImpl implements SysFileService { + + private final OssClient ossClient; + + private final OssProperties properties; + + /** + * 文件列表 + * + * @param dto + * dto + * @return {@link PageResult}<{@link SysFile}> + */ + @Override + public PageResult fileList(SysFileListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create(); + if (Utils.isNotNull(dto.getFilename())) { + wrapper.where(SysFileTableDef.SYS_FILE.FILENAME.like(dto.getFilename())); + } + wrapper.orderBy(SysFileTableDef.SYS_FILE.CREATE_TIME.desc()); + Page page = page(PageUtils.getPage(dto), wrapper); + return PageUtils.getPageResult(page); + } + + /** + * 上传文件 + * + * @param file + * 文件 + * @param dirTag + * 文件夹标识 + * @return {@link String} + */ + @Override + public UploadResult uploadFile(MultipartFile file, String dirTag, String scene) { + UploadResult uploadResult = null; + String bucketName = properties.getBucketName(); + // 如果是富文本编辑器上传,选择富文本编辑器的bucket配置 + if ("richtext".equals(scene)) { + bucketName = properties.getRichtextBucketName(); + } + try { + uploadResult = ossClient.upload(file, dirTag, bucketName); + Long fileId = fileLog(uploadResult); + uploadResult.setFileId(fileId); + } catch (Exception e) { + log.error(" sysFile oss upload error", e); + CommonResponseEnum.FILE_UPLOAD_ERROR.assertTrue(true); + } + return uploadResult; + } + + @Override + public Long fileLog(UploadResult uploadResult) { + SysFile sysFile = BeanCopyUtils.copy(uploadResult, SysFile.class); + this.save(sysFile); + return sysFile.getId(); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysLoginLogServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysLoginLogServiceImpl.java new file mode 100644 index 0000000..0ff7144 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysLoginLogServiceImpl.java @@ -0,0 +1,153 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysLoginLogMapper; +import com.sz.admin.system.pojo.dto.SysLoginLogCreateDTO; +import com.sz.admin.system.pojo.dto.SysLoginLogListDTO; +import com.sz.admin.system.pojo.dto.SysLoginLogUpdateDTO; +import com.sz.admin.system.pojo.po.SysLoginLog; +import com.sz.admin.system.pojo.vo.SysLoginLogVO; +import com.sz.admin.system.service.SysLoginLogService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.ip.IpUtils; +import com.sz.core.util.*; +import com.sz.excel.utils.ExcelUtils; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import nl.basjes.parse.useragent.UserAgent; +import nl.basjes.parse.useragent.UserAgentAnalyzer; +import org.springframework.stereotype.Service; + +import java.io.OutputStream; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 登陆日志表 服务实现类 + *

+ * + * @author sz-admin + * @since 2025-07-25 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysLoginLogServiceImpl extends ServiceImpl implements SysLoginLogService { + + private static final UserAgentAnalyzer USER_AGENT_ANALYZER = UserAgentAnalyzer.newBuilder().dropTests().build(); + + @Override + public void create(SysLoginLogCreateDTO dto) { + SysLoginLog sysLoginLog = BeanCopyUtils.copy(dto, SysLoginLog.class); + save(sysLoginLog); + } + + @Override + public void update(SysLoginLogUpdateDTO dto) { + SysLoginLog sysLoginLog = BeanCopyUtils.copy(dto, SysLoginLog.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(SysLoginLog::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + + saveOrUpdate(sysLoginLog); + } + + @Override + public PageResult page(SysLoginLogListDTO dto) { + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), SysLoginLogVO.class); + return PageUtils.getPageResult(page); + } + + @Override + public List list(SysLoginLogListDTO dto) { + return listAs(buildQueryWrapper(dto), SysLoginLogVO.class); + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public SysLoginLogVO detail(Object id) { + SysLoginLog sysLoginLog = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(sysLoginLog); + return BeanCopyUtils.copy(sysLoginLog, SysLoginLogVO.class); + } + + @SneakyThrows + @Override + public void exportExcel(SysLoginLogListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "登陆日志表模板"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, "登陆日志表", SysLoginLogVO.class, os); + } + + /** + * 异步记录登陆日志 + */ + @Override + public void recordLoginLog(String username, String status, String msg) { + try { + // 在主线程中获取所有请求信息 + HttpServletRequest request = HttpReqResUtil.getRequest(); + String ipAddress = HttpReqResUtil.getIpAddress(request); + String userAgentString = request.getHeader("User-Agent"); + String realAddressByIP = IpUtils.getRealAddressByIP(ipAddress); + // 使用虚拟线程进行异步提交 + Thread.startVirtualThread(() -> { + try { + UserAgent.ImmutableUserAgent agent = USER_AGENT_ANALYZER.parse(userAgentString); + SysLoginLog log = new SysLoginLog(); + log.setUserName(username); + log.setLoginStatus(status); + log.setLoginTime(LocalDateTime.now()); + log.setMsg(msg); + log.setIpAddress(ipAddress); + log.setLoginLocation(realAddressByIP); + log.setBrowser(agent.getValue(UserAgent.AGENT_NAME)); + log.setOs(agent.getValue(UserAgent.OPERATING_SYSTEM_NAME)); + this.mapper.insertLoginLog(log); + } catch (Exception e) { + log.error("登陆日志记录异常-用户名:{}, 状态:{}, 错误:{}", username, status, e.getMessage()); + } + }); + } catch (Exception e) { + // 获取请求信息失败记录基本日志信息 + log.error("获取登录日志请求信息失败-用户名:{}, 状态:{}, 错误:{}", username, status, e.getMessage()); + SysLoginLog log = new SysLoginLog(); + log.setUserName(username); + log.setLoginStatus(status); + log.setLoginTime(LocalDateTime.now()); + log.setMsg(msg); + this.mapper.insertLoginLog(log); + } + } + + private static QueryWrapper buildQueryWrapper(SysLoginLogListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(SysLoginLog.class); + if (Utils.isNotNull(dto.getUserName())) { + wrapper.like(SysLoginLog::getUserName, dto.getUserName()); + } + if (Utils.isNotNull(dto.getLoginStatus())) { + wrapper.eq(SysLoginLog::getLoginStatus, dto.getLoginStatus()); + } + if (Utils.isNotNull(dto.getLoginTimeStart()) && Utils.isNotNull(dto.getLoginTimeEnd())) { + wrapper.between(SysLoginLog::getLoginTime, dto.getLoginTimeStart(), dto.getLoginTimeEnd()); + } + wrapper.orderBy(SysLoginLog::getLoginTime).desc(); + return wrapper; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMenuServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..b4167c6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,471 @@ +package com.sz.admin.system.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryMethods; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysMenuMapper; +import com.sz.admin.system.mapper.SysUserRoleMapper; +import com.sz.admin.system.pojo.dto.sysmenu.MenuPermissionDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysMenuCreateDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysMenuListDTO; +import com.sz.admin.system.pojo.po.SysMenu; +import com.sz.admin.system.pojo.po.SysUserDataRole; +import com.sz.admin.system.pojo.po.table.SysMenuTableDef; +import com.sz.admin.system.pojo.vo.sysmenu.MenuPermissionVO; +import com.sz.admin.system.pojo.vo.sysmenu.MenuTreeVO; +import com.sz.admin.system.pojo.vo.sysmenu.SysMenuVO; +import com.sz.admin.system.service.SysMenuService; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.entity.UserPermissionChangeMessage; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.event.EventPublisher; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.TreeUtils; +import com.sz.core.util.Utils; +import com.sz.generator.service.GeneratorTableService; +import com.sz.platform.enums.AdminResponseEnum; +import com.sz.platform.event.PermissionChangeEvent; +import com.sz.platform.event.PermissionMeta; +import com.sz.redis.RedisService; +import com.sz.security.core.util.LoginUtils; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.IOException; +import java.io.StringWriter; +import java.time.LocalDateTime; +import java.util.*; +import java.util.stream.Collectors; + +import static com.mybatisflex.core.query.QueryMethods.select; +import static com.sz.admin.system.pojo.po.table.SysDataRoleMenuTableDef.SYS_DATA_ROLE_MENU; +import static com.sz.admin.system.pojo.po.table.SysMenuTableDef.SYS_MENU; +import static com.sz.admin.system.pojo.po.table.SysRoleMenuTableDef.SYS_ROLE_MENU; +import static com.sz.admin.system.pojo.po.table.SysUserDataRoleTableDef.SYS_USER_DATA_ROLE; +import static com.sz.admin.system.pojo.po.table.SysUserRoleTableDef.SYS_USER_ROLE; + +/** + *

+ * 系统菜单表 服务实现类 + *

+ * + * @author sz + * @since 2022-10-01 + */ + +@Slf4j +@Service +@RequiredArgsConstructor +public class SysMenuServiceImpl extends ServiceImpl implements SysMenuService { + + private final SysUserRoleMapper sysUserRoleMapper; + + private final RedisService redisService; + + private final GeneratorTableService generatorTableService; + + private final EventPublisher eventPublisher; + + /** + * 创建菜单 + * + * @param dto + * dto + */ + @Transactional + @Override + public void create(SysMenuCreateDTO dto) { + SysMenu menu = BeanCopyUtils.copy(dto, SysMenu.class); + menu.setId(Utils.generateUUIDs()); + QueryWrapper wrapper; + if (!("1002003").equals(dto.getMenuTypeCd())) { // 对非按钮进行唯一性校验 + wrapper = QueryWrapper.create().eq(SysMenu::getName, dto.getName()).eq(SysMenu::getDelFlag, "F"); + AdminResponseEnum.MENU_NAME_EXISTS.assertTrue(count(wrapper) > 0); + + wrapper = QueryWrapper.create().eq(SysMenu::getPath, dto.getPath()).eq(SysMenu::getDelFlag, "F"); + CommonResponseEnum.EXISTS.message("menuPath已存在").assertTrue(count(wrapper) > 0); + } + + int deep; + if (isRoot(dto.getPid())) { + deep = 1; + menu.setPid("0"); + } else { + wrapper = QueryWrapper.create().where(SysMenuTableDef.SYS_MENU.ID.eq(dto.getPid())); + Integer parentDeep = getOne(wrapper).getDeep(); + deep = parentDeep + 1; + } + menu.setDeep(deep); + menu.setCreateId(Objects.requireNonNull(LoginUtils.getLoginUser()).getUserInfo().getId()); + menu.setHasChildren("F"); + save(menu); + this.mapper.syncTreeDeep(); + this.mapper.syncTreeHasChildren(); + // 发布Permission 变更通知 + UserPermissionChangeMessage message = new UserPermissionChangeMessage(null, true); + redisService.sendPermissionChangeMsg(message); + + } + + /** + * 更新菜单 + * + * @param dto + * dto + */ + @Transactional + @Override + public void update(SysMenuCreateDTO dto) { + QueryWrapper wrapper; + SysMenu menu = BeanCopyUtils.copy(dto, SysMenu.class); + // 菜单是否存在 + wrapper = QueryWrapper.create().where(SysMenuTableDef.SYS_MENU.ID.eq(dto.getId())); + CommonResponseEnum.NOT_EXISTS.message("菜单不存在").assertTrue(count(wrapper) < 1); + menu.setUpdateId(Objects.requireNonNull(LoginUtils.getLoginUser()).getUserInfo().getId()); + menu.setUpdateTime(LocalDateTime.now()); + updateById(menu); + this.mapper.syncTreeDeep(); + this.mapper.syncTreeHasChildren(); + + // 发布Permission 变更通知 + UserPermissionChangeMessage message = new UserPermissionChangeMessage(null, true); + redisService.sendPermissionChangeMsg(message); + + } + + /** + * 删除 + * + * @param dto + * dto + */ + @Transactional + @Override + public void remove(SelectIdsDTO dto) { + if (Utils.isNotNull(dto.getIds())) { + // 递归查询下边的子节点id + List list = this.mapper.selectMenuAndChildrenIds((List) dto.getIds()); + this.mapper.updateMenuAndChildrenIsDelete(list); + this.mapper.syncTreeDeep(); + this.mapper.syncTreeHasChildren(); + // 发布Permission 变更通知 + UserPermissionChangeMessage message = new UserPermissionChangeMessage(null, true); + redisService.sendPermissionChangeMsg(message); + } + } + + /** + * 列表 + * + * @param dto + * dto + * @return {@link List}<{@link SysMenuVO}> + */ + @Override + public List menuList(SysMenuListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().eq(SysMenu::getDelFlag, "F") + /* .orderBy(SYS_MENU.DEEP.asc()) */ + .orderBy(SysMenuTableDef.SYS_MENU.SORT.asc()); + + if (!dto.isShowButton()) { + wrapper.ne(SysMenu::getMenuTypeCd, "1002003"); + } + // 菜单全部数据 + List list = list(wrapper); + List treeList = new ArrayList<>(); + // 构建树形 + for (SysMenuVO rootNode : getRootNodes(list)) { + SysMenuVO menuVO = BeanCopyUtils.copy(rootNode, SysMenuVO.class); + SysMenuVO.Meta meta = BeanCopyUtils.copy(rootNode, SysMenuVO.Meta.class); + menuVO.setMeta(meta); + SysMenuVO childrenNode = getChildrenNode(menuVO, list); + treeList.add(childrenNode); + } + return treeList; + } + + @Override + public List findMenuListByUserId(Long userId) { + List treeList = new ArrayList<>(); + // 菜单全部数据(当前用户下的) + QueryWrapper wrapper = QueryWrapper.create() + .select(QueryMethods.distinct(SYS_MENU.ID, SYS_MENU.PID, SYS_MENU.PATH, SYS_MENU.NAME, SYS_MENU.TITLE, SYS_MENU.ICON, SYS_MENU.COMPONENT, + SYS_MENU.REDIRECT, SYS_MENU.SORT, SYS_MENU.DEEP, SYS_MENU.MENU_TYPE_CD, SYS_MENU.PERMISSIONS, SYS_MENU.IS_HIDDEN, SYS_MENU.HAS_CHILDREN, + SYS_MENU.IS_LINK, SYS_MENU.IS_FULL, SYS_MENU.IS_AFFIX, SYS_MENU.IS_KEEP_ALIVE, SYS_MENU.CREATE_TIME, SYS_MENU.UPDATE_TIME, + SYS_MENU.CREATE_ID, SYS_MENU.UPDATE_ID, SYS_MENU.DEL_FLAG, SYS_MENU.USE_DATA_SCOPE, SYS_MENU.DELETE_ID, SYS_MENU.DELETE_TIME)) + .from(SYS_USER_ROLE).leftJoin(SYS_ROLE_MENU).on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE_MENU.ROLE_ID)).leftJoin(SYS_MENU) + .on(SYS_ROLE_MENU.MENU_ID.eq(SYS_MENU.ID)).where(SYS_MENU.MENU_TYPE_CD.ne("1002003")).where(SYS_USER_ROLE.USER_ID.eq(userId)) + .orderBy(SYS_MENU.DEEP.asc()).orderBy(SYS_MENU.SORT.asc()); + List list = list(wrapper); + // 构建树形 + for (SysMenuVO rootNode : getRootNodes(list)) { + SysMenuVO menuVO = BeanCopyUtils.copy(rootNode, SysMenuVO.class); + SysMenuVO.Meta meta = BeanCopyUtils.copy(rootNode, SysMenuVO.Meta.class); + meta.setIsLink(("T").equals(meta.getIsLink()) ? menuVO.getRedirect() : ""); + menuVO.setMeta(meta); + SysMenuVO childrenNode = getChildrenNode(menuVO, list); + treeList.add(childrenNode); + } + return treeList; + } + + @Override + public List getSimpleMenuTree(String nodeId) { + // 创建根目录节点并将所有数据包裹在其中 + MenuTreeVO root = new MenuTreeVO(); + root.setId("0"); // 根目录ID通常为0 + root.setPid("-1"); // 设置一个无效的值作为根目录的PID + root.setTitle("根目录"); // 根目录的标题 + + QueryWrapper wrapper = QueryWrapper.create().eq(SysMenu::getDelFlag, "F").ne(SysMenu::getMenuTypeCd, "1002003") // 排除按钮 + .orderBy(SYS_MENU.DEEP.asc()).orderBy(SysMenuTableDef.SYS_MENU.SORT.asc()); + List list = list(wrapper); + List menuTreeVOS = BeanCopyUtils.copyList(list, MenuTreeVO.class); + return TreeUtils.buildTree(menuTreeVOS, root, nodeId); + } + + @Override + public List getMenuTreeVOS(String nodeId, boolean isShowButton) { + List childrenIds = new ArrayList<>(); + if (nodeId != null && !nodeId.equals("0")) { + childrenIds = this.mapper.getMenuAndChildrenIds(nodeId, isShowButton); + } + List sysMenuVOS; + if (!childrenIds.isEmpty()) { + sysMenuVOS = menuListTree(childrenIds); + } else { + SysMenuListDTO dto = new SysMenuListDTO(); + dto.setShowButton(isShowButton); + sysMenuVOS = menuList(dto); + } + return BeanCopyUtils.copyList(sysMenuVOS, MenuTreeVO.class); + } + + @Override + public List queryRoleMenuTree(boolean isShowButton) { + SysMenuListDTO dto = new SysMenuListDTO(); + dto.setShowButton(isShowButton); + List sysMenuVOS = menuList(dto); + return BeanCopyUtils.copyList(sysMenuVOS, MenuTreeVO.class); + } + + public String exportMenuSql(SelectIdsDTO dto) { + String generatedContent = ""; + if (Utils.isNotNull(dto.getIds())) { + // 递归查询下边的子节点id + List list = this.mapper.selectMenuAndChildrenIds((List) dto.getIds()); + QueryWrapper queryWrapper = QueryWrapper.create().in(SysMenu::getId, list).orderBy(SysMenu::getDeep).asc().orderBy(SysMenu::getSort).asc(); + List sysMenuList = list(queryWrapper); + if (Utils.isNotNull(sysMenuList)) { + Map dataModel = new HashMap<>(); + dataModel.put("sysMenuList", sysMenuList); + try (StringWriter writer = new StringWriter()) { + Template template = generatorTableService.getMenuSqlTemplate(); + template.process(dataModel, writer); + generatedContent = writer.toString(); + } catch (IOException | TemplateException e) { + log.error("exportMenuSql error", e); + } + } + } + return generatedContent; + } + + /** + * 菜单属性查询(排除自己和自己的子节点) + * + * @param excludingIds + * 排除的id + * @return 菜单属性 + */ + private List menuListTree(List excludingIds) { + QueryWrapper wrapper = QueryWrapper.create().notIn(SysMenu::getId, excludingIds).ne(SysMenu::getMenuTypeCd, "10023").orderBy(SysMenu::getDeep).asc() + .orderBy(SysMenu::getSort).asc().eq(SysMenu::getDelFlag, "F"); + + // 菜单全部数据 + List list = list(wrapper); + List treeList = new ArrayList<>(); + // 构建树形 + for (SysMenuVO rootNode : getRootNodes(list)) { + SysMenuVO menuVO = BeanCopyUtils.copy(rootNode, SysMenuVO.class); + SysMenuVO.Meta meta = BeanCopyUtils.copy(rootNode, SysMenuVO.Meta.class); + menuVO.setMeta(meta); + SysMenuVO childrenNode = getChildrenNode(menuVO, list); + treeList.add(childrenNode); + } + return treeList; + } + + /** + * 详情 + * + * @return {@link SysMenuVO} + */ + @Override + public SysMenu detail(String id) { + SysMenu menu = getById(id); + CommonResponseEnum.INVALID_ID.assertNull(menu); + return menu; + } + + /** + * 是否是根节点 + * + * @param pid + * 父级Id + * @return true:是根节点 + */ + private boolean isRoot(String pid) { + return pid == null || pid.equals("0"); + } + + /** + * 获取父级跟节点 + * + * @param list + * 菜单列表 + * @return 父级跟节点菜单列表 + */ + private List getRootNodes(List list) { + List rootList = new ArrayList<>(); + for (SysMenu sysMenu : list) { + // 找到所有父级节点 + if (sysMenu.getPid() == null || sysMenu.getPid().equals("0")) { + SysMenuVO sysMenuTreeVO = BeanCopyUtils.copy(sysMenu, SysMenuVO.class); + rootList.add(sysMenuTreeVO); + } + } + return rootList; + } + + private SysMenuVO getChildrenNode(SysMenuVO sysMenu, List menuList) { + List childrenList = new ArrayList<>(); + for (SysMenu menu : menuList) { + if (menu.getPid().equals(sysMenu.getId())) { + SysMenuVO childrenNode = BeanCopyUtils.copy(menu, SysMenuVO.class); + SysMenuVO.Meta meta = BeanCopyUtils.copy(menu, SysMenuVO.Meta.class); + meta.setIsLink(("T").equals(meta.getIsLink()) ? childrenNode.getRedirect() : ""); + childrenNode.setMeta(meta); + childrenList.add(getChildrenNode(childrenNode, menuList)); + } + } + sysMenu.setChildren(childrenList); + return sysMenu; + } + + /** + * 验证是否有权限标识 + * + * @param dto + * dto + * @return 权限标识对象 + */ + @Override + public MenuPermissionVO hasExistsPermissions(MenuPermissionDTO dto) { + MenuPermissionVO permissionVO = new MenuPermissionVO(); + if (dto.getPermissions() == null || dto.getPermissions().isEmpty()) { + return permissionVO; + } + QueryWrapper wrapper = QueryWrapper.create().ne(SysMenu::getId, dto.getId()).eq(SysMenu::getPermissions, dto.getPermissions()); + long count = count(wrapper); + permissionVO.setPermissionCount((int) count); + return permissionVO; + } + + /** + * 查询权限按钮 + * + * @return 权限集合 + */ + @Override + public List findPermission() { + return sysUserRoleMapper.queryPermissionByUserId(StpUtil.getLoginIdAsLong()); + } + + @Override + public List findPermissionsByUserId(Long userId) { + QueryWrapper queryWrapper = QueryWrapper.create().select(QueryMethods.distinct(SYS_MENU.PERMISSIONS)).from(SYS_MENU).leftJoin(SYS_ROLE_MENU) + .on(SYS_MENU.ID.eq(SYS_ROLE_MENU.MENU_ID)).leftJoin(SYS_USER_ROLE).on(SYS_ROLE_MENU.ROLE_ID.eq(SYS_USER_ROLE.ROLE_ID)) + .where(SYS_USER_ROLE.USER_ID.eq(userId)).where(SYS_MENU.PERMISSIONS.isNotNull()).where(SYS_MENU.PERMISSIONS.ne("")); + return listAs(queryWrapper, String.class); + } + + @Override + public List findAllPermissions() { + QueryWrapper queryWrapper = QueryWrapper.create().select(QueryMethods.distinct(SYS_MENU.PERMISSIONS)).from(SYS_MENU).eq(SysMenu::getDelFlag, "F") + .isNotNull(SysMenu::getPermissions).ne(SysMenu::getPermissions, ""); + + return listAs(queryWrapper, String.class); + } + + @Override + public Map getBtnMenuByPermissions(Collection permissions) { + Map btnMenuMap = new HashMap<>(); + if (permissions.isEmpty()) { + return btnMenuMap; + } + try { + QueryWrapper wrapper = QueryWrapper.create().from(SYS_MENU).where( + SYS_MENU.PID.in(select(SYS_MENU.ID).from(SYS_MENU).where(SYS_MENU.USE_DATA_SCOPE.eq("T")).where(SYS_MENU.MENU_TYPE_CD.eq("1002002")))); + List list = list(wrapper); + if (list.isEmpty()) { + return btnMenuMap; + } + Set pids = list.stream().map(SysMenu::getPid).collect(Collectors.toSet()); + QueryWrapper checkWrapper = QueryWrapper.create().select(SYS_MENU.ID).from(SYS_MENU).where(SYS_MENU.ID.in(pids)); + List existsMenuIds = listAs(checkWrapper, String.class); + for (SysMenu menu : list) { + if (existsMenuIds.contains(menu.getPid()) || existsMenuIds.contains(menu.getId())) { // 过滤脏数据 + String key = menu.getPermissions(); + String value; + if (("1002002").equals(menu.getMenuTypeCd())) { + value = menu.getId(); + } else { + value = menu.getPid(); + } + btnMenuMap.put(key, value); + } + } + } catch (Exception e) { + log.error(" sync menuButton info err ", e); + } + return btnMenuMap; + } + + @Override + public List queryDataRoleMenu() { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_MENU.USE_DATA_SCOPE.eq("T")).where(SYS_MENU.MENU_TYPE_CD.eq("1002002")); + List list = list(wrapper); + return BeanCopyUtils.copyList(list, MenuTreeVO.class); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void changeMenuDataScope(String menuId) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_MENU.ID.eq(menuId)); + SysMenu menu = getOne(wrapper); + CommonResponseEnum.INVALID_ID.assertNull(menu); + String useDataScope; + if (("F").equals(menu.getUseDataScope())) { + useDataScope = "T"; + menu.setUseDataScope(useDataScope); + } else { + useDataScope = "F"; + menu.setUseDataScope(useDataScope); + } + updateById(menu); + UpdateChain.of(SysMenu.class).set(SYS_MENU.USE_DATA_SCOPE, useDataScope).where(SYS_MENU.PID.eq(menu.getId())).update(); + + List changeUserIds = QueryChain.of(SysUserDataRole.class).select(SYS_USER_DATA_ROLE.USER_ID).from(SYS_USER_DATA_ROLE).leftJoin(SYS_DATA_ROLE_MENU) + .on(SYS_DATA_ROLE_MENU.ROLE_ID.eq(SYS_USER_DATA_ROLE.ROLE_ID)).where(SYS_DATA_ROLE_MENU.MENU_ID.eq(menuId)).listAs(Long.class); + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(changeUserIds))); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMessageServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMessageServiceImpl.java new file mode 100644 index 0000000..5d654cf --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMessageServiceImpl.java @@ -0,0 +1,133 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysMessageMapper; +import com.sz.admin.system.pojo.dto.sysmessage.Message; +import com.sz.admin.system.pojo.dto.sysmessage.PayloadBody; +import com.sz.admin.system.pojo.dto.sysmessage.SysMessageListDTO; +import com.sz.admin.system.pojo.po.SysMessage; +import com.sz.admin.system.pojo.po.SysMessageUser; +import com.sz.admin.system.pojo.vo.sysmessage.MessageCountVO; +import com.sz.admin.system.pojo.vo.sysmessage.SysMessageVO; +import com.sz.admin.system.service.SysMessageService; +import com.sz.admin.system.service.SysMessageUserService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +import com.sz.security.core.util.LoginUtils; +import com.sz.socket.SocketService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import static com.sz.admin.system.pojo.po.table.SysMessageTableDef.SYS_MESSAGE; +import static com.sz.admin.system.pojo.po.table.SysMessageUserTableDef.SYS_MESSAGE_USER; + +/** + *

+ * 消息管理 服务实现类 + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Service +@RequiredArgsConstructor +public class SysMessageServiceImpl extends ServiceImpl implements SysMessageService { + + private final SysMessageUserService sysMessageUserService; + + private final SocketService socketService; + + @Override + public void create(Message dto) { + SysMessage sysMessage = BeanCopyUtils.copy(dto, SysMessage.class); + save(sysMessage); + Long messageId = sysMessage.getId(); + List receiverIds = dto.getReceiverIds(); + sysMessageUserService.batchInsert(messageId, receiverIds); + + PayloadBody body = new PayloadBody(); + body.setTitle(dto.getTitle()); + body.setContent(dto.getContent()); + socketService.sendMessage(body, dto.getSenderId().toString(), dto.getReceiverIds()); + } + + @Override + public void saveMsg(Message dto) { + SysMessage sysMessage = BeanCopyUtils.copy(dto, SysMessage.class); + save(sysMessage); + Long messageId = sysMessage.getId(); + List receiverIds = dto.getReceiverIds(); + sysMessageUserService.batchInsert(messageId, receiverIds); + } + + @Override + public PageResult page(SysMessageListDTO dto) { + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), SysMessageVO.class); + return PageUtils.getPageResult(page); + } + + @Override + public List list(SysMessageListDTO dto) { + QueryWrapper queryWrapper = buildQueryWrapper(dto); + queryWrapper.where(SYS_MESSAGE_USER.IS_READ.eq("F")); + return listAs(queryWrapper, SysMessageVO.class); + } + + @Override + public SysMessageVO detail(Object id) { + SysMessage sysMessage = getById((Serializable) id); + Long userId = Objects.requireNonNull(LoginUtils.getLoginUser()).getUserInfo().getId(); + CommonResponseEnum.INVALID_ID.assertNull(sysMessage); + SysMessageVO messageVO = BeanCopyUtils.copy(sysMessage, SysMessageVO.class); + String isRead = sysMessageUserService.getIsRead(sysMessage.getId(), userId); + messageVO.setIsRead(isRead); + read(Utils.getLongVal(id)); + return messageVO; + } + + @Override + public MessageCountVO countMyUnreadMessages() { + long all = count(buildQueryWrapper(new SysMessageListDTO("")).where(SYS_MESSAGE_USER.IS_READ.eq("F"))); + long todo = count(buildQueryWrapper(new SysMessageListDTO("todo")).where(SYS_MESSAGE_USER.IS_READ.eq("F"))); + long msg = count(buildQueryWrapper(new SysMessageListDTO("msg")).where(SYS_MESSAGE_USER.IS_READ.eq("F"))); + return new MessageCountVO(all, todo, msg); + } + + private static QueryWrapper buildQueryWrapper(SysMessageListDTO dto) { + Long userId = Objects.requireNonNull(LoginUtils.getLoginUser()).getUserInfo().getId(); + QueryWrapper wrapper = QueryWrapper.create() + .select(SYS_MESSAGE.ID, SYS_MESSAGE.MESSAGE_TYPE_CD, SYS_MESSAGE.SENDER_ID, SYS_MESSAGE.TITLE, SYS_MESSAGE.CONTENT, SYS_MESSAGE.CREATE_TIME, + SYS_MESSAGE_USER.IS_READ) + .from(SYS_MESSAGE).join(SYS_MESSAGE_USER).on(SYS_MESSAGE_USER.MESSAGE_ID.eq(SYS_MESSAGE.ID)).where(SYS_MESSAGE_USER.RECEIVER_ID.eq(userId)) + .where(SYS_MESSAGE.MESSAGE_TYPE_CD.eq(dto.getMessageTypeCd()).when(Utils.isNotNull(dto.getMessageTypeCd()))); + if (Utils.isNotNull(dto.getReadType())) { + if ("read".equals(dto.getReadType())) { + wrapper.where(SYS_MESSAGE_USER.IS_READ.eq("T")); + } else if ("unread".equals(dto.getReadType())) { + wrapper.where(SYS_MESSAGE_USER.IS_READ.eq("F")); + } + } + wrapper.orderBy(SYS_MESSAGE.CREATE_TIME.desc()); + return wrapper; + } + + public void read(Long messageId) { + Long userId = Objects.requireNonNull(LoginUtils.getLoginUser()).getUserInfo().getId(); + UpdateChain.of(SysMessageUser.class).set(SYS_MESSAGE_USER.IS_READ, "T").set(SYS_MESSAGE_USER.READ_TIME, LocalDateTime.now()) + .where(SYS_MESSAGE_USER.MESSAGE_ID.eq(messageId)).where(SYS_MESSAGE_USER.RECEIVER_ID.eq(userId)).update(); + socketService.readMessage(userId.toString(), List.of(userId)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMessageUserServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMessageUserServiceImpl.java new file mode 100644 index 0000000..f329263 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysMessageUserServiceImpl.java @@ -0,0 +1,49 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysMessageUserMapper; +import com.sz.admin.system.pojo.po.SysMessageUser; +import com.sz.admin.system.service.SysMessageUserService; +import java.util.List; + +import com.sz.core.util.Utils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + *

+ * 消息接收用户表 服务实现类 + *

+ * + * @author sz-admin + * @since 2025-04-21 + */ +@Service +@RequiredArgsConstructor +public class SysMessageUserServiceImpl extends ServiceImpl implements SysMessageUserService { + + @Override + public void batchInsert(Long messageId, List receiverIds) { + if (receiverIds.isEmpty()) { + return; + } + List sysMessageUsers = receiverIds.stream().map(receiverId -> { + SysMessageUser sysMessageUser = new SysMessageUser(); + sysMessageUser.setMessageId(messageId); + sysMessageUser.setReceiverId(Utils.getLongVal(receiverId)); + return sysMessageUser; + }).toList(); + saveBatch(sysMessageUsers); + } + + @Override + public String getIsRead(Long messageId, Long receiverId) { + SysMessageUser sysMessageUser = getOne(QueryWrapper.create().eq(SysMessageUser::getMessageId, messageId).eq(SysMessageUser::getReceiverId, receiverId)); + if (sysMessageUser == null) { + return "F"; + } + return sysMessageUser.getIsRead(); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysPermissionServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysPermissionServiceImpl.java new file mode 100644 index 0000000..f4f5931 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysPermissionServiceImpl.java @@ -0,0 +1,201 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryChain; +import com.sz.admin.system.pojo.po.SysDept; +import com.sz.admin.system.pojo.po.SysUser; +import com.sz.admin.system.pojo.po.SysUserDataRole; +import com.sz.admin.system.pojo.po.SysUserDept; +import com.sz.admin.system.pojo.vo.sysuser.SysUserDataMetaVO; +import com.sz.admin.system.service.SysDeptClosureService; +import com.sz.admin.system.service.SysMenuService; +import com.sz.admin.system.service.SysPermissionService; +import com.sz.admin.system.service.SysUserRoleService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.JsonUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +import static com.sz.admin.system.pojo.po.table.SysDataRoleMenuTableDef.SYS_DATA_ROLE_MENU; +import static com.sz.admin.system.pojo.po.table.SysDataRoleRelationTableDef.SYS_DATA_ROLE_RELATION; +import static com.sz.admin.system.pojo.po.table.SysDataRoleTableDef.SYS_DATA_ROLE; +import static com.sz.admin.system.pojo.po.table.SysDeptTableDef.SYS_DEPT; +import static com.sz.admin.system.pojo.po.table.SysMenuTableDef.SYS_MENU; +import static com.sz.admin.system.pojo.po.table.SysUserDataRoleTableDef.SYS_USER_DATA_ROLE; +import static com.sz.admin.system.pojo.po.table.SysUserDeptTableDef.SYS_USER_DEPT; + +/** + * SysPermissionServiceImpl + * + * @author sz + * @since 2024/2/4 15:12 + * @version 1.0 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysPermissionServiceImpl implements SysPermissionService { + + private final SysMenuService sysMenuService; + + private final SysUserRoleService sysUserRoleService; + + private final SysDeptClosureService sysDeptClosureService; + + @Override + public Set getMenuPermissions(SysUser sysUser) { + Set permissions = new HashSet<>(); + CommonResponseEnum.INVALID_USER.assertNull(sysUser); + if (isSuperAdmin(sysUser)) { // 获取超管权限 + permissions.addAll(sysMenuService.findAllPermissions()); + } else { // 获取指定用户的权限 + permissions.addAll(sysMenuService.findPermissionsByUserId(sysUser.getId())); + } + return permissions; + } + + @Override + public Set getRoles(Long userId) { + Set roles = new HashSet<>(); + SysUser sysUser = QueryChain.of(SysUser.class).eq(SysUser::getId, userId).one(); + CommonResponseEnum.INVALID_USER.assertNull(sysUser); + if (isSuperAdmin(sysUser)) { // 获取超管角色 + roles.add(GlobalConstant.SUPER_ROLE); // 超管角色设置为"admin" + } else { + roles.addAll(sysUserRoleService.getUserRolesByUserId(userId)); + } + return roles; + } + + @Override + public Set getRoles(SysUser sysUser) { + Set roles = new HashSet<>(); + if (isSuperAdmin(sysUser)) { // 获取超管角色 + roles.add(GlobalConstant.SUPER_ROLE); // 超管角色设置为"admin" + } else { + roles.addAll(sysUserRoleService.getUserRolesByUserId(sysUser.getId())); + } + return roles; + } + + @Override + public List getDepts(SysUser sysUser) { + CommonResponseEnum.INVALID_USER.assertNull(sysUser); + if (isSuperAdmin(sysUser)) { + // 查询全部的部门ID + return QueryChain.of(SysDept.class).select(SYS_DEPT.ID).listAs(Long.class); + } else { + return QueryChain.of(SysUserDept.class).select(SYS_USER_DEPT.DEPT_ID).where(SYS_USER_DEPT.USER_ID.eq(sysUser.getId())).listAs(Long.class); + } + } + + @Override + public List getDeptAndChildren(SysUser sysUser) { + if (isSuperAdmin(sysUser)) { + // 查询全部的部门ID + return QueryChain.of(SysDept.class).select(SYS_DEPT.ID).listAs(Long.class); + } else { + return sysDeptClosureService.descendants(getDepts(sysUser)); + } + } + + public Map buildMenuRuleMap(SysUser sysUser, Set findMenuIds) { + Map ruleMap = new HashMap<>(); + CommonResponseEnum.INVALID_USER.assertNull(sysUser); + // 如果用户是超级管理员,返回空规则映射 + if (isSuperAdmin(sysUser)) { + return ruleMap; + } + + // 如果没有菜单ID,返回默认规则 + if (findMenuIds.isEmpty()) { + return ruleMap; + } + + // 获取用户数据角色的元信息 + List metaVOList = QueryChain.of(SysUserDataRole.class) + .select(SYS_USER_DATA_ROLE.USER_ID, SYS_USER_DATA_ROLE.ROLE_ID, SYS_DATA_ROLE.DATA_SCOPE_CD, SYS_DATA_ROLE_MENU.MENU_ID) + .from(SYS_USER_DATA_ROLE).leftJoin(SYS_DATA_ROLE).on(SYS_USER_DATA_ROLE.ROLE_ID.eq(SYS_DATA_ROLE.ID)).leftJoin(SYS_DATA_ROLE_MENU) + .on(SYS_USER_DATA_ROLE.ROLE_ID.eq(SYS_DATA_ROLE_MENU.ROLE_ID)).leftJoin(SYS_MENU).on(SYS_MENU.ID.eq(SYS_DATA_ROLE_MENU.MENU_ID)) + .where(SYS_MENU.USE_DATA_SCOPE.eq("T")).where(SYS_USER_DATA_ROLE.USER_ID.eq(sysUser.getId())).where(SYS_DATA_ROLE.DATA_SCOPE_CD.ne("1006005")) + .where(SYS_DATA_ROLE_MENU.MENU_ID.in(findMenuIds)).where(SYS_DATA_ROLE.DATA_SCOPE_CD.isNotNull()).listAs(SysUserDataMetaVO.class); + + // 聚合菜单下的权限规则 (一次聚合) + Map> menuMap = metaVOList.stream().collect(Collectors.groupingBy(SysUserDataMetaVO::getMenuId)); + // 根据最小权限规则生成最终规则映射 (二次聚合) + for (Map.Entry> entry : menuMap.entrySet()) { + String menuId = entry.getKey(); + List values = entry.getValue(); + SysUserDataMetaVO metaVO = values.stream().min(Comparator.comparing(SysUserDataMetaVO::getDataScopeCd)).orElse(null); + ruleMap.put(menuId, metaVO != null ? metaVO.getDataScopeCd() : ""); + } + buildCustomScope(sysUser, findMenuIds, ruleMap); + return ruleMap; + } + + private static void buildCustomScope(SysUser sysUser, Set findMenuIds, Map ruleMap) { + // 获取自定义权限 + List customMetaList = QueryChain.of(SysUserDataRole.class) + .select(SYS_USER_DATA_ROLE.USER_ID, SYS_USER_DATA_ROLE.ROLE_ID, SYS_DATA_ROLE.DATA_SCOPE_CD, SYS_DATA_ROLE_MENU.MENU_ID, + SYS_DATA_ROLE_RELATION.RELATION_ID, SYS_DATA_ROLE_RELATION.RELATION_TYPE_CD) + .from(SYS_USER_DATA_ROLE).leftJoin(SYS_DATA_ROLE).on(SYS_USER_DATA_ROLE.ROLE_ID.eq(SYS_DATA_ROLE.ID)).leftJoin(SYS_DATA_ROLE_MENU) + .on(SYS_USER_DATA_ROLE.ROLE_ID.eq(SYS_DATA_ROLE_MENU.ROLE_ID)).leftJoin(SYS_DATA_ROLE_RELATION) + .on(SYS_USER_DATA_ROLE.ROLE_ID.eq(SYS_DATA_ROLE_RELATION.ROLE_ID)).leftJoin(SYS_MENU).on(SYS_MENU.ID.eq(SYS_DATA_ROLE_MENU.MENU_ID)) + .where(SYS_MENU.USE_DATA_SCOPE.eq("T")).where(SYS_USER_DATA_ROLE.USER_ID.eq(sysUser.getId())).where(SYS_DATA_ROLE.DATA_SCOPE_CD.eq("1006005")) + .where(SYS_DATA_ROLE_MENU.MENU_ID.in(findMenuIds)).listAs(SysUserDataMetaVO.class); + + Map> deptRuleMap = new HashMap<>(); // 自定义部门rule + Map> userRuleMap = new HashMap<>(); // 自定义用户rule + for (SysUserDataMetaVO metaVO : customMetaList) { + String menuId = metaVO.getMenuId(); + Long relationId = metaVO.getRelationId(); + if (("1007001").equals(metaVO.getRelationTypeCd())) { + Set deptIds; + if (deptRuleMap.containsKey(menuId)) { + deptIds = deptRuleMap.get(menuId); + deptIds.add(relationId); + } else { + deptIds = new HashSet<>(); + deptIds.add(relationId); + deptRuleMap.put(menuId, deptIds); + } + } + + if (("1007002").equals(metaVO.getRelationTypeCd())) { + Set userIds; + if (userRuleMap.containsKey(menuId)) { + userIds = userRuleMap.get(menuId); + userIds.add(relationId); + } else { + userIds = new HashSet<>(); + userIds.add(relationId); + userRuleMap.put(menuId, userIds); + } + } + } + // 将自定义权限添加到规则映射中 + if (!userRuleMap.isEmpty()) { + ruleMap.put("userRule", JsonUtils.toJsonString(userRuleMap)); + } + if (!deptRuleMap.isEmpty()) { + ruleMap.put("deptRule", JsonUtils.toJsonString(deptRuleMap)); + } + } + + /** + * 验证用户是否是【管理员身份】 验证方式:sys_user.user_tag_cd 字段; [1001001 测试用户; 1001002 超级管理员; + * 1001003 普通用户] 。 详见字典:用户标签(user_tag) + * + * @param sysUser + * 用户信息 + * @return 是否是超级管理员 + */ + private boolean isSuperAdmin(SysUser sysUser) { + return sysUser != null && ("1001002").equals(sysUser.getUserTagCd()); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysRoleMenuServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysRoleMenuServiceImpl.java new file mode 100644 index 0000000..5592f7b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysRoleMenuServiceImpl.java @@ -0,0 +1,257 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryMethods; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysRoleMenuMapper; +import com.sz.admin.system.mapper.SysUserMapper; +import com.sz.admin.system.pojo.dto.sysrolemenu.SysRoleMenuDTO; +import com.sz.admin.system.pojo.po.SysDataRoleRelation; +import com.sz.admin.system.pojo.po.SysRoleMenu; +import com.sz.admin.system.pojo.vo.sysdept.DeptTreeVO; +import com.sz.admin.system.pojo.vo.sysmenu.MenuTreeVO; +import com.sz.core.common.entity.RoleMenuScopeVO; +import com.sz.admin.system.pojo.vo.sysrolemenu.SysRoleMenuVO; +import com.sz.admin.system.pojo.vo.sysuser.UserOptionVO; +import com.sz.admin.system.service.*; +import com.sz.core.common.event.EventPublisher; +import com.sz.core.util.Utils; +import com.sz.platform.event.PermissionChangeEvent; +import com.sz.platform.event.PermissionMeta; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +import static com.sz.admin.system.pojo.po.table.SysRoleMenuTableDef.SYS_ROLE_MENU; +import static com.sz.admin.system.pojo.po.table.SysUserRoleTableDef.SYS_USER_ROLE; +import static com.sz.admin.system.pojo.po.table.SysUserTableDef.SYS_USER; + +/** + *

+ * 系统角色-菜单表 服务实现类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysRoleMenuServiceImpl extends ServiceImpl implements SysRoleMenuService { + + private final SysMenuService sysMenuService; + + private final EventPublisher eventPublisher; + + private final SysDeptService sysDeptService; + + private final SysDataRoleRelationService sysDataRoleRelationService; + + private final SysUserMapper sysUserMapper; + + @Override + @Transactional + public void change(SysRoleMenuDTO dto) { + Long roleId = dto.getRoleId(); + // 根据角色id 查询影响用户范围,获取到用户id + QueryWrapper userWrapper = QueryWrapper.create().select(QueryMethods.distinct(SYS_USER_ROLE.USER_ID)).from(SYS_USER_ROLE) + .where(SYS_USER_ROLE.ROLE_ID.eq(roleId)); + // 获取到影响范围的userId + List userIds = listAs(userWrapper, String.class); + + // 1. 功能权限的修改 + // 删除当前角色下的所有菜单记录 + QueryWrapper wrapper = QueryWrapper.create().eq(SysRoleMenu::getRoleId, roleId); + remove(wrapper); // 移除角色-菜单关联记录 + sysDataRoleRelationService.deleteByRoleId(roleId); // 移除角色-数据权限关联记录 + if (Utils.isNotNull(dto.getMenu().getMenuIds())) { + this.mapper.insertBatchSysRoleMenu(dto.getMenu().getMenuIds(), roleId, "menu", null); // 批量插入角色-菜单记录 + } + + // 2. 数据权限的修改 + List scopeList = dto.getScope(); + List scopeRoleMenus = new ArrayList<>(); + SysRoleMenu roleMenu; + for (SysRoleMenuDTO.Scope scope : scopeList) { + String dataScope = scope.getDataScope(); + String menuId = scope.getMenuId(); + roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenu.setPermissionType("scope"); + roleMenu.setDataScopeCd(dataScope); + scopeRoleMenus.add(roleMenu); + + if ("1006005".equals(dataScope)) { // 自定义数据权限 + sysDataRoleRelationService.batchSave(roleId, menuId, "1007001", scope.getUserIds()); + sysDataRoleRelationService.batchSave(roleId, menuId, "1007002", scope.getDeptIds()); + } + } + saveBatch(scopeRoleMenus); + + // 3. 发布权限变更事件 + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(userIds))); + } + + /** + * 查询角色分配的菜单,及全部菜单 + * + * @param roleId + * 角色id + * @return 菜单 + */ + @Override + public SysRoleMenuVO queryRoleMenu(Long roleId) { + // 1. 查询基础信息:菜单树、部门树、用户列表 + List menuTreeVOS = sysMenuService.queryRoleMenuTree(true); + List menuIds = getMenuId(roleId, "menu"); + SysRoleMenuVO menuVO = new SysRoleMenuVO(); + menuVO.setMenuLists(menuTreeVOS); + menuVO.setSelectMenuIds(menuIds); + List deptTreeVOS = sysDeptService.getDeptTree(null, false, false); + QueryWrapper wrapper = QueryWrapper.create().select(SYS_USER.ID, SYS_USER.USERNAME, SYS_USER.NICKNAME); + List userOptions = sysUserMapper.selectListByQueryAs(wrapper, UserOptionVO.class); + menuVO.setDeptLists(deptTreeVOS); + menuVO.setUserLists(userOptions); + + List scopeRoleMenus = getMenuList(roleId, "scope"); + List scopes = new ArrayList<>(); + List customMenuIds = new ArrayList<>(); + Map customMenuMap = new HashMap<>(); + for (SysRoleMenu menu : scopeRoleMenus) { + if ("1006005".equals(menu.getDataScopeCd())) { // 自定义数据权限 + customMenuIds.add(menu.getMenuId()); + customMenuMap.put(menu.getMenuId(), menu); + } else { // 非自定义数据权限 + SysRoleMenuVO.Scope scope = new SysRoleMenuVO.Scope(); + scope.setMenuId(menu.getMenuId()); + scope.setDataScope(menu.getDataScopeCd()); + scopes.add(scope); + } + } + + // 查询并聚合自定义数据权限 + if (!customMenuIds.isEmpty()) { + List relations = sysDataRoleRelationService.queryRelationByRoleIdAndMenuIds(roleId, customMenuIds); + Map> relationMap = relations.stream().collect(Collectors.groupingBy(SysDataRoleRelation::getMenuId)); // 按菜单ID聚合 + for (String menuId : customMenuIds) { + List group = relationMap.getOrDefault(menuId, Collections.emptyList()); + SysRoleMenuVO.Scope scope = new SysRoleMenuVO.Scope(); + scope.setMenuId(menuId); + scope.setDataScope("1006005"); + List deptIds = new ArrayList<>(); + List userIds = new ArrayList<>(); + for (SysDataRoleRelation relation : group) { + if ("1007001".equals(relation.getRelationTypeCd())) { // 用户维度 + userIds.add(relation.getRelationId()); + } else if ("1007002".equals(relation.getRelationTypeCd())) { // 部门维度 + deptIds.add(relation.getRelationId()); + } + } + scope.setDeptIds(deptIds); + scope.setUserIds(userIds); + scopes.add(scope); + } + } + menuVO.setScope(scopes); + return menuVO; + } + + private List getMenuList(Long roleId, String permissionType) { + QueryWrapper wrapper = QueryWrapper.create().eq(SysRoleMenu::getRoleId, roleId).eq(SysRoleMenu::getPermissionType, permissionType); + return list(wrapper); + } + + private List getMenuId(Long roleId, String permissionType) { + List list = getMenuList(roleId, permissionType); + List menuIds = new ArrayList<>(); + if (Utils.isNotNull(list)) { + menuIds = list.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList()); + } + return menuIds; + } + + @Override + public Map getUserScope(Collection roleIds) { + Map scopeVOMap = new HashMap<>(); + if (roleIds.isEmpty()) { + return scopeVOMap; + } + List customMenuIds = new ArrayList<>(); + Map> roleScopeMap = new HashMap<>(); + QueryWrapper wrapper = QueryWrapper.create().where(SYS_ROLE_MENU.ROLE_ID.in(roleIds)).where(SYS_ROLE_MENU.PERMISSION_TYPE.eq("scope")); + List list = list(wrapper); + for (SysRoleMenu roleMenu : list) { + String menuId = roleMenu.getMenuId(); + if (roleMenu.getDataScopeCd().equals("1006005")) { + customMenuIds.add(menuId); + } + List roleMenus; + if (roleScopeMap.containsKey(menuId)) { + roleMenus = roleScopeMap.get(menuId); + roleMenus.add(roleMenu); + } else { + roleMenus = new ArrayList<>(); + roleMenus.add(roleMenu); + roleScopeMap.put(menuId, roleMenus); + } + } + Map customScopeMap = new HashMap<>(); + // 根据 角色 和 菜单 获取 自定义权限 + if (!customMenuIds.isEmpty()) { + List relations = sysDataRoleRelationService.listByRoleIdsAndMenuIds(roleIds, customMenuIds); + Map> relationMap = relations.stream().collect(Collectors.groupingBy(SysDataRoleRelation::getMenuId)); + for (String menuId : customMenuIds) { + List group = relationMap.getOrDefault(menuId, Collections.emptyList()); + Set deptIds = new HashSet<>(); + Set userIds = new HashSet<>(); + for (SysDataRoleRelation relation : group) { + if ("1007001".equals(relation.getRelationTypeCd())) { // 用户维度 + userIds.add(relation.getRelationId()); + } else if ("1007002".equals(relation.getRelationTypeCd())) { // 部门维度 + deptIds.add(relation.getRelationId()); + } + } + RoleMenuScopeVO.CustomScope customScope = new RoleMenuScopeVO.CustomScope(); + customScope.setDeptIds(deptIds); + customScope.setUserIds(userIds); + customScopeMap.put(menuId, customScope); + } + } + + // 处理权限范围的合并逻辑 + for (Map.Entry> entry : roleScopeMap.entrySet()) { + String menuId = entry.getKey(); + List menus = entry.getValue(); + RoleMenuScopeVO scopeVO = new RoleMenuScopeVO(); + scopeVO.setMenuId(menuId); + + // 1. 找出最高优先权 dataScopeCd=1006005 的所有菜单(可有多个角色) + boolean hasCustom = false; + for (SysRoleMenu menu : menus) { + if ("1006005".equals(menu.getDataScopeCd())) { + hasCustom = true; + break; + } + } + + if (hasCustom) { + scopeVO.setDataScopeCd("1006005"); + scopeVO.setCustomScope(customScopeMap.get(menuId)); + } else { + // 没有自定义范围时,取dataScopeCd的最小值(字符串比较即可,通常1006001<..2<..3...) + String minScope = menus.stream().map(SysRoleMenu::getDataScopeCd).min(String::compareTo).orElse("1006004"); // 默认取最小范围 仅本人 + scopeVO.setDataScopeCd(minScope); + // 无自定义权限 + scopeVO.setCustomScope(null); + } + scopeVOMap.put(menuId, scopeVO); + } + return scopeVOMap; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysRoleServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..2c0520f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,112 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryCondition; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysRoleMapper; +import com.sz.admin.system.mapper.SysRoleMenuMapper; +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleCreateDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleListDTO; +import com.sz.admin.system.pojo.dto.sysrole.SysRoleUpdateDTO; +import com.sz.admin.system.pojo.po.SysRole; +import com.sz.admin.system.pojo.po.SysRoleMenu; +import com.sz.admin.system.pojo.vo.common.RoleVO; +import com.sz.admin.system.pojo.vo.sysrole.RoleOptionsVO; +import com.sz.admin.system.service.SysRoleService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import com.sz.core.util.Utils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static com.sz.admin.system.pojo.po.table.SysRoleTableDef.SYS_ROLE; + +/** + *

+ * 系统角色表 服务实现类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +@Service +@RequiredArgsConstructor +public class SysRoleServiceImpl extends ServiceImpl implements SysRoleService { + + private final SysRoleMenuMapper sysRoleMenuMapper; + + @Override + public void create(SysRoleCreateDTO dto) { + SysRole sysRole = BeanCopyUtils.copy(dto, SysRole.class); + long count; + count = QueryChain.of(SysRole.class).eq(SysRole::getRoleName, dto.getRoleName()).count(); + CommonResponseEnum.EXISTS.message("roleName已存在").assertTrue(count > 0); + if (Utils.isNotNull(dto.getPermissions())) { + count = QueryChain.of(SysRole.class).eq(SysRole::getPermissions, dto.getPermissions()).count(); + CommonResponseEnum.EXISTS.message("permissions已存在").assertTrue(count > 0); + } + save(sysRole); + } + + @Override + public void update(SysRoleUpdateDTO dto) { + SysRole sysRole = BeanCopyUtils.copy(dto, SysRole.class); + long count; + count = QueryChain.of(SysRole.class).eq(SysRole::getRoleName, dto.getRoleName()).ne(SysRole::getId, dto.getId()).count(); + CommonResponseEnum.EXISTS.message("roleName已存在").assertTrue(count > 0); + if (Utils.isNotNull(dto.getPermissions())) { + count = QueryChain.of(SysRole.class).eq(SysRole::getPermissions, dto.getPermissions()).ne(SysRole::getId, dto.getId()).count(); + CommonResponseEnum.EXISTS.message("permissions已存在").assertTrue(count > 0); + } + updateById(sysRole); + } + + @Override + public void remove(SelectIdsDTO dto) { + removeByIds(dto.getIds()); + } + + @Override + public void removeByMenuId(SelectIdsDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().in(SysRoleMenu::getMenuId, dto.getIds()); + sysRoleMenuMapper.deleteByQuery(wrapper); + } + + @Override + public PageResult list(SysRoleListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create(); + if (Utils.isNotNull(dto.getRoleName())) { + wrapper.like(SysRole::getRoleName, dto.getRoleName()); + } + return PageUtils.getPageResult(page(PageUtils.getPage(dto), wrapper)); + } + + @Override + public PageResult pageSelector(SelectorQueryDTO dto) { + String keyword = dto.getKeyword(); + QueryWrapper wrapper = QueryWrapper.create().select(SYS_ROLE.ID, SYS_ROLE.ROLE_NAME.as("name"), SYS_ROLE.PERMISSIONS) + .orderBy(SYS_ROLE.CREATE_TIME.asc()); + if (keyword != null && !keyword.isEmpty()) { + QueryCondition condition = SYS_ROLE.ROLE_NAME.like(keyword).or(SYS_ROLE.PERMISSIONS.like(keyword)); + wrapper.and(condition); + } + Page page = pageAs(PageUtils.getPage(dto), wrapper, RoleVO.class); + return PageUtils.getPageResult(page); + } + + @Override + public List getRoleOptions() { + QueryWrapper wrapper = QueryWrapper.create().select(SYS_ROLE.ID, SYS_ROLE.ROLE_NAME, SYS_ROLE.PERMISSIONS).from(SYS_ROLE) + .orderBy(SYS_ROLE.CREATE_TIME.asc()); + return listAs(wrapper, RoleOptionsVO.class); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysTempFileHistoryServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysTempFileHistoryServiceImpl.java new file mode 100644 index 0000000..a97d6c4 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysTempFileHistoryServiceImpl.java @@ -0,0 +1,44 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysTempFileHistoryMapper; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileHistoryCreateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileHistoryListDTO; +import com.sz.admin.system.pojo.po.SysTempFileHistory; +import com.sz.admin.system.service.SysTempFileHistoryService; +import com.sz.core.common.entity.PageResult; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.PageUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import static com.sz.admin.system.pojo.po.table.SysTempFileHistoryTableDef.SYS_TEMP_FILE_HISTORY; + +/** + *

+ * 模版文件历史 服务实现类 + *

+ * + * @author sz + * @since 2024-12-05 + */ +@Service +@RequiredArgsConstructor +public class SysTempFileHistoryServiceImpl extends ServiceImpl implements SysTempFileHistoryService { + + @Override + public void create(SysTempFileHistoryCreateDTO dto) { + SysTempFileHistory history = BeanCopyUtils.copy(dto, SysTempFileHistory.class); + save(history); + } + + @Override + public PageResult historyList(SysTempFileHistoryListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_TEMP_FILE_HISTORY.SYS_TEMP_FILE_ID.eq(dto.getSysTempFileId())); + Page page = page(PageUtils.getPage(dto), wrapper); + return PageUtils.getPageResult(page); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysTempFileServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysTempFileServiceImpl.java new file mode 100644 index 0000000..30736d7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysTempFileServiceImpl.java @@ -0,0 +1,147 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileHistoryCreateDTO; +import com.sz.admin.system.pojo.vo.systempfile.SysTempFileInfoVO; +import com.sz.admin.system.service.SysFileService; +import com.sz.admin.system.service.SysTempFileHistoryService; +import com.sz.oss.OssClient; +import com.sz.core.common.entity.UploadResult; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import com.sz.admin.system.service.SysTempFileService; +import com.sz.admin.system.pojo.po.SysTempFile; +import com.sz.admin.system.mapper.SysTempFileMapper; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.PageUtils; +import com.sz.core.util.BeanCopyUtils; +import com.sz.core.util.Utils; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; + +import java.io.Serializable; +import java.util.List; + +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileCreateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileUpdateDTO; +import com.sz.admin.system.pojo.dto.systempfile.SysTempFileListDTO; +import com.sz.admin.system.pojo.vo.systempfile.SysTempFileVO; +import org.springframework.web.multipart.MultipartFile; + +import static com.sz.admin.system.pojo.po.table.SysFileTableDef.SYS_FILE; +import static com.sz.admin.system.pojo.po.table.SysTempFileTableDef.SYS_TEMP_FILE; + +/** + *

+ * 模版文件表 服务实现类 + *

+ * + * @author sz + * @since 2024-12-05 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class SysTempFileServiceImpl extends ServiceImpl implements SysTempFileService { + + private final OssClient ossClient; + + private final SysFileService sysFileService; + + private final SysTempFileHistoryService sysTempFileHistoryService; + + @Override + public void create(SysTempFileCreateDTO dto) { + SysTempFile sysTempFile = BeanCopyUtils.copy(dto, SysTempFile.class); + // 唯一性校验 + long count = QueryChain.of(SysTempFile.class).eq(SysTempFile::getAlias, dto.getAlias()).count(); + CommonResponseEnum.EXISTS.message("标识:" + dto.getAlias() + " 已存在").assertTrue(count > 0); + List url = dto.getUrl(); + Long fileId = url.getFirst().getFileId(); + sysTempFile.setSysFileId(fileId); + save(sysTempFile); + SysTempFileHistoryCreateDTO history = BeanCopyUtils.copy(sysTempFile, SysTempFileHistoryCreateDTO.class); + history.setSysTempFileId(sysTempFile.getId()); + sysTempFileHistoryService.create(history); + } + + @Override + public void update(SysTempFileUpdateDTO dto) { + SysTempFile sysTempFile = BeanCopyUtils.copy(dto, SysTempFile.class); + List url = dto.getUrl(); + Long fileId = url.getFirst().getFileId(); + sysTempFile.setSysFileId(fileId); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(SysTempFile::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + // 唯一性校验 + long count; + count = QueryChain.of(SysTempFile.class).eq(SysTempFile::getAlias, dto.getAlias()).ne(SysTempFile::getId, dto.getId()).count(); + CommonResponseEnum.EXISTS.message("标识:" + dto.getAlias() + " 已存在").assertTrue(count > 0); + + saveOrUpdate(sysTempFile); + + SysTempFileHistoryCreateDTO history = BeanCopyUtils.copy(sysTempFile, SysTempFileHistoryCreateDTO.class); + history.setSysTempFileId(sysTempFile.getId()); + sysTempFileHistoryService.create(history); + } + + @Override + public PageResult page(SysTempFileListDTO dto) { + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), SysTempFileVO.class); + return PageUtils.getPageResult(page); + } + + @Override + public List list(SysTempFileListDTO dto) { + return listAs(buildQueryWrapper(dto), SysTempFileVO.class); + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public SysTempFileVO detail(Object id) { + SysTempFile sysTempFile = getById((Serializable) id); + CommonResponseEnum.INVALID_ID.assertNull(sysTempFile); + return BeanCopyUtils.copy(sysTempFile, SysTempFileVO.class); + } + + @Override + public UploadResult uploadFile(MultipartFile file) { + UploadResult uploadResult = null; + try { + uploadResult = ossClient.upload(file, "tmp", ""); + Long fileId = sysFileService.fileLog(uploadResult); + uploadResult.setFileId(fileId); + } catch (Exception e) { + log.error(" sysTempFile oss upload error", e); + CommonResponseEnum.FILE_UPLOAD_ERROR.assertTrue(true); + } + return uploadResult; + } + + private static QueryWrapper buildQueryWrapper(SysTempFileListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(SysTempFile.class); + if (Utils.isNotNull(dto.getTempName())) { + wrapper.like(SysTempFile::getTempName, dto.getTempName()); + } + return wrapper; + } + + @Override + public SysTempFileInfoVO detailByNameOrAlias(String tempName, String alias) { + QueryWrapper wrapper = QueryWrapper.create().from(SYS_TEMP_FILE).leftJoin(SYS_FILE).on(SYS_TEMP_FILE.SYS_FILE_ID.eq(SYS_FILE.ID)) + .where(SYS_TEMP_FILE.TEMP_NAME.eq(tempName).or(SYS_TEMP_FILE.ALIAS.eq(alias))); + return getOneAs(wrapper, SysTempFileInfoVO.class); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserDataRoleServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserDataRoleServiceImpl.java new file mode 100644 index 0000000..acfb7da --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserDataRoleServiceImpl.java @@ -0,0 +1,77 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDataRoleMapper; +import com.sz.admin.system.pojo.dto.sysmenu.SysUserRoleDTO; +import com.sz.admin.system.pojo.po.SysDataRole; +import com.sz.admin.system.pojo.vo.sysuser.SysUserRoleVO; +import com.sz.core.common.event.EventPublisher; +import com.sz.core.util.BeanCopyUtils; +import com.sz.platform.event.PermissionChangeEvent; +import com.sz.platform.event.PermissionMeta; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.sz.admin.system.service.SysUserDataRoleService; +import com.sz.admin.system.pojo.po.SysUserDataRole; +import com.sz.admin.system.mapper.SysUserDataRoleMapper; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.sz.admin.system.pojo.po.table.SysUserDataRoleTableDef.SYS_USER_DATA_ROLE; + +/** + *

+ * 系统用户-数据角色关联表 服务实现类 + *

+ * + * @author sz + * @since 2024-07-11 + */ +@Service +@RequiredArgsConstructor +public class SysUserDataRoleServiceImpl extends ServiceImpl implements SysUserDataRoleService { + + private final SysDataRoleMapper sysDataRoleMapper; + + private final EventPublisher eventPublisher; + + @Transactional + @Override + public void changeRole(SysUserRoleDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().where(SYS_USER_DATA_ROLE.USER_ID.eq(dto.getUserId())); + if (count(wrapper) > 0) { + remove(wrapper); + } + List dataRoles = new ArrayList<>(); + SysUserDataRole dataRole; + for (Long roleId : dto.getRoleIds()) { + dataRole = new SysUserDataRole(); + dataRole.setUserId(dto.getUserId()); + dataRole.setRoleId(roleId); + dataRoles.add(dataRole); + } + if (dataRoles.isEmpty()) + return; + saveBatch(dataRoles); + Long userId = dto.getUserId(); + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(Collections.singletonList(userId)))); // 发送用户元数据change事件 + + } + + @Override + public SysUserRoleVO queryRoleMenu(Long userId) { + List list = QueryChain.of(sysDataRoleMapper).list(); + List roleInfoVOS = BeanCopyUtils.copyList(list, SysUserRoleVO.RoleInfoVO.class); + List roleIds = QueryChain.of(this.mapper).select(SYS_USER_DATA_ROLE.ROLE_ID).where(SYS_USER_DATA_ROLE.USER_ID.eq(userId)).listAs(Long.class); + SysUserRoleVO vo = new SysUserRoleVO(); + vo.setRoleInfoVOS(roleInfoVOS); + vo.setSelectIds(roleIds); + return vo; + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserDeptServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserDeptServiceImpl.java new file mode 100644 index 0000000..b84d02c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserDeptServiceImpl.java @@ -0,0 +1,61 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysUserDeptMapper; +import com.sz.admin.system.pojo.dto.sysuser.UserDeptDTO; +import com.sz.admin.system.pojo.po.SysUserDept; +import com.sz.admin.system.service.SysUserDeptService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +import static com.sz.admin.system.pojo.po.table.SysUserDeptTableDef.SYS_USER_DEPT; + +/** + *

+ * 用户-部门关系表 服务实现类 + *

+ * + * @author sz + * @since 2024-04-02 + */ + +@Service +@RequiredArgsConstructor +public class SysUserDeptServiceImpl extends ServiceImpl implements SysUserDeptService { + + @Override + @Transactional + public void bind(UserDeptDTO dto) { + List userIds = dto.getUserIds(); + List deptIds = dto.getDeptIds(); + if (!userIds.isEmpty()) { + List removeIds = QueryChain.of(SysUserDept.class).select(SYS_USER_DEPT.ID).where(SYS_USER_DEPT.USER_ID.in(userIds)).listAs(Long.class); + removeByIds(removeIds); + } + + List batchList = new ArrayList<>(); + SysUserDept userDept; + for (Long deptId : deptIds) { + for (Long userId : userIds) { + userDept = new SysUserDept(); + userDept.setUserId(userId); + userDept.setDeptId(deptId); + batchList.add(userDept); + } + } + saveBatch(batchList); // 重新创建user 和dept的关系 + } + + @Override + public void unbind(List userIds) { + QueryWrapper removeWrapper = QueryWrapper.create().where(SYS_USER_DEPT.USER_ID.in(userIds)); + remove(removeWrapper); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserRoleServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserRoleServiceImpl.java new file mode 100644 index 0000000..bbd0f82 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserRoleServiceImpl.java @@ -0,0 +1,42 @@ +package com.sz.admin.system.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysUserRoleMapper; +import com.sz.admin.system.pojo.po.SysUserRole; +import com.sz.admin.system.service.SysUserRoleService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +import static com.sz.admin.system.pojo.po.table.SysUserRoleTableDef.SYS_USER_ROLE; + +/** + *

+ * 系统用户-角色关联表 服务实现类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysUserRoleServiceImpl extends ServiceImpl implements SysUserRoleService { + + /** + * 获取用户的角色 + * + * @param userId + * 用户id + * @return 用户角色集合 + */ + @Override + public List getUserRolesByUserId(Long userId) { + QueryWrapper queryWrapper = QueryWrapper.create().select(SYS_USER_ROLE.ROLE_ID).from(SYS_USER_ROLE).where(SYS_USER_ROLE.USER_ID.eq(userId)); + return listAs(queryWrapper, String.class); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..4ba07d7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,574 @@ +package com.sz.admin.system.service.impl; + +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpUtil; +import com.github.pagehelper.PageHelper; +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryChain; +import com.mybatisflex.core.query.QueryCondition; +import com.mybatisflex.core.query.QueryMethods; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.system.mapper.SysDeptRoleMapper; +import com.sz.admin.system.mapper.SysRoleMapper; +import com.sz.admin.system.mapper.SysUserMapper; +import com.sz.admin.system.mapper.SysUserRoleMapper; +import com.sz.admin.system.pojo.dto.common.SelectorQueryDTO; +import com.sz.admin.system.pojo.dto.sysmenu.SysUserRoleDTO; +import com.sz.admin.system.pojo.dto.sysuser.*; +import com.sz.admin.system.pojo.po.*; +import com.sz.admin.system.pojo.vo.common.UserVO; +import com.sz.core.common.entity.RoleMenuScopeVO; +import com.sz.admin.system.pojo.vo.sysuser.*; +import com.sz.admin.system.service.*; +import com.sz.core.common.entity.BaseUserInfo; +import com.sz.core.common.entity.LoginUser; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.common.event.EventPublisher; +import com.sz.core.util.*; +import com.sz.mysql.DataScopeProperties; +import com.sz.platform.event.PermissionChangeEvent; +import com.sz.platform.event.PermissionMeta; +import com.sz.redis.CommonKeyConstants; +import com.sz.redis.RedisCache; +import com.sz.redis.RedisUtils; +import com.sz.security.core.util.LoginUtils; +import com.sz.security.service.AuthService; +import com.sz.socket.SocketService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +import static com.sz.admin.system.pojo.po.table.SysDeptClosureTableDef.SYS_DEPT_CLOSURE; +import static com.sz.admin.system.pojo.po.table.SysDeptTableDef.SYS_DEPT; +import static com.sz.admin.system.pojo.po.table.SysRoleTableDef.SYS_ROLE; +import static com.sz.admin.system.pojo.po.table.SysUserDeptTableDef.SYS_USER_DEPT; +import static com.sz.admin.system.pojo.po.table.SysUserRoleTableDef.SYS_USER_ROLE; +import static com.sz.admin.system.pojo.po.table.SysUserTableDef.SYS_USER; + +/** + *

+ * 系统用户表 服务实现类 + *

+ * + * @author sz + * @since 2022-10-01 + */ +@Service +@Slf4j +@RequiredArgsConstructor +public class SysUserServiceImpl extends ServiceImpl implements SysUserService { + + private final SysRoleMapper sysRoleMapper; + + private final SysUserRoleMapper sysUserRoleMapper; + + private final SysDeptRoleMapper sysDeptRoleMapper; + + private final RedisCache redisCache; + + private final SysPermissionService sysPermissionService; + + private final EventPublisher eventPublisher; + + private final SysUserDeptService userDeptService; + + private final DataScopeProperties dataScopeProperties; + + private final SysMenuService menuService; + + @Value("${spring.profiles.active}") + private String activeProfile; + + private final AuthService authService; + + private final SysRoleMenuService sysRoleMenuService; + + private final SocketService socketService; + + /** + * 获取认证账户信息接角色信息 + * + * @param username + * 用户名 + * @return 用户信息 + */ + @Override + public SysUserVO getSysUserByUsername(String username) { + QueryWrapper wrapper = QueryWrapper.create().eq(SysUser::getUsername, username); + + SysUser one = getOne(wrapper); + CommonResponseEnum.BAD_USERNAME_OR_PASSWORD.assertNull(one); + SysUserVO sysUserVO = new SysUserVO(); + BeanCopyUtils.copy(one, sysUserVO); + return sysUserVO; + } + + /** + * 获取认证账户信息接角色信息 + * + * @param userId + * 用户id + * @return 用户信息 + */ + @Override + public SysUserVO getSysUserByUserId(Long userId) { + QueryWrapper wrapper = QueryWrapper.create().eq(SysUser::getId, userId); + SysUser one = getOne(wrapper); + CommonResponseEnum.BAD_USERNAME_OR_PASSWORD.assertNull(one); + return BeanCopyUtils.copy(one, SysUserVO.class); + } + + /** + * 后台创建用户 + * + * @param dto + * 用户信息 + */ + @Transactional + @Override + public void create(SysUserCreateDTO dto) { + SysUser user = BeanCopyUtils.copy(dto, SysUser.class); + QueryWrapper wrapper = QueryWrapper.create().eq(SysUser::getUsername, dto.getUsername()); + CommonResponseEnum.USERNAME_EXISTS.assertTrue(count(wrapper) > 0); + String encodePwd = getEncoderPwd(getInitPassword()); + user.setPwd(encodePwd); + user.setAccountStatusCd("1000001"); + user.setUserTagCd("1001003"); + save(user); + + if (dto.getDeptId() <= 0) + return; + UserDeptDTO deptDTO = new UserDeptDTO(); + deptDTO.setDeptIds(Collections.singletonList(dto.getDeptId())); + deptDTO.setUserIds(Collections.singletonList(user.getId())); + bindUserDept(deptDTO); + } + + /** + * 更新用户 + * + * @param dto + * 用户信息 + */ + @Override + public void update(SysUserUpdateDTO dto) { + SysUser user = BeanCopyUtils.copy(dto, SysUser.class); + // 检查用户是否存在 + QueryWrapper wrapper = QueryWrapper.create().eq(SysUser::getId, dto.getId()); + SysUser one = getOne(wrapper); + CommonResponseEnum.INVALID_USER.assertNull(one); + updateById(user); + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(Collections.singletonList(user.getId())))); + } + + /** + * 删除用户 (逻辑删除,保留数据关系。如部门、权限、角色等) + * + * @param dto + * 用户id数组 + */ + @Override + @Transactional + public void remove(SelectIdsDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().in(SysUser::getId, dto.getIds()); + // 检查用户是否存在 + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) < 1); + removeByIds(dto.getIds()); + } + + /** + * 详情 + * + * @param id + * 用户id + * @return {@link SysUser} + */ + @Override + public SysUserVO detail(Long id) { + SysUser user = getById(id); + CommonResponseEnum.INVALID_ID.assertNull(user); + return BeanCopyUtils.copy(user, SysUserVO.class); + } + + @Override + public PageResult page(SysUserListDTO dto) { + PageResult result; + PageUtils.toPage(dto); + try { + List sysUserVOS; + if (dto.getDeptId() != null && dto.getDeptId() == -1) { // 查询全部 + sysUserVOS = this.mapper.queryAllSysUserList(dto); + } else if (dto.getDeptId() != null && dto.getDeptId() == -2) { // 查询未分配部门的列表 + sysUserVOS = this.mapper.querySysUserListNotDept(dto); + } else { // 查询指定部门的列表 + sysUserVOS = this.mapper.querySysUserListByDept(dto); + } + setUserDeptInfo(sysUserVOS); + setUserRoleInfo(sysUserVOS); + result = PageUtils.getPageResult(sysUserVOS); + } finally { + PageHelper.clearPage(); + } + return result; + } + + private void setUserDeptInfo(List userList) { + if (userList.isEmpty()) { + return; + } + // 获取所有用户的 ID 列表 + List userIds = userList.stream().map(SysUserVO::getId).collect(Collectors.toList()); + + // 查询用户的部门信息并转换为 Map + Map userDeptMap = new HashMap<>(); + QueryWrapper wrapper = QueryWrapper.create().select(SYS_USER_DEPT.USER_ID, QueryMethods.groupConcat(SYS_USER_DEPT.DEPT_ID).as("deptIds")) + .from(SYS_USER_DEPT).join(SYS_DEPT).on(SYS_USER_DEPT.DEPT_ID.eq(SYS_DEPT.ID)).where(SYS_USER_DEPT.USER_ID.in(userIds)) + .groupBy(SYS_USER_DEPT.USER_ID); + List userDeptList = listAs(wrapper, UserDeptInfoVO.class); + + if (userDeptList != null) { + for (UserDeptInfoVO userDeptInfoVO : userDeptList) { + userDeptMap.put(userDeptInfoVO.getUserId(), userDeptInfoVO); + } + } + // 遍历用户列表,设置用户的部门信息 + for (SysUserVO user : userList) { + // 检查部门信息是否存在 + if (userDeptMap.containsKey(user.getId())) { + UserDeptInfoVO infoVO = userDeptMap.get(user.getId()); + user.setDeptIds(infoVO.getDeptIds()); + } + } + } + + private void setUserRoleInfo(List userList) { + if (userList.isEmpty()) { + return; + } + // 获取所有用户的 ID 列表 + List userIds = userList.stream().map(SysUserVO::getId).collect(Collectors.toList()); + + // 查询用户的部门信息并转换为 Map + Map userRoleMap = new HashMap<>(); + QueryWrapper wrapper = QueryWrapper.create().select(SYS_USER_ROLE.USER_ID, QueryMethods.groupConcat(SYS_USER_ROLE.ROLE_ID).as("role_ids")) + .from(SYS_USER_ROLE).innerJoin(SYS_ROLE).on(SYS_USER_ROLE.ROLE_ID.eq(SYS_ROLE.ID)).where(SYS_USER_ROLE.USER_ID.in(userIds)) + .groupBy(SYS_USER_ROLE.USER_ID); + List userDeptList = listAs(wrapper, UserRoleInfoVO.class); + if (userDeptList != null) { + for (UserRoleInfoVO infoVO : userDeptList) { + userRoleMap.put(infoVO.getUserId(), infoVO); + } + } + // 遍历用户列表,设置用户的部门信息 + for (SysUserVO user : userList) { + // 检查部门信息是否存在 + if (userRoleMap.containsKey(user.getId())) { + UserRoleInfoVO infoVO = userRoleMap.get(user.getId()); + user.setRoleIds(infoVO.getRoleIds()); + } + } + } + + private String getEncoderPwd(String pwd) { + return BCrypt.hashpw(pwd, BCrypt.gensalt(10)); + } + + private boolean matchEncoderPwd(String pwd, String pwdEncoder) { + return BCrypt.checkpw(pwd, pwdEncoder); + } + + @Override + public SysUserRoleVO findSysUserRole(Long userId) { + List sysRoleList = QueryChain.of(this.sysRoleMapper).list(); + List roleInfoVOS = BeanCopyUtils.copyList(sysRoleList, SysUserRoleVO.RoleInfoVO.class); + String superAdminRoleId = SysConfigUtils.getConfValue("sys.admin.superAdminRoleId"); + for (SysUserRoleVO.RoleInfoVO roleInfoVO : roleInfoVOS) { + if (superAdminRoleId.equals(Utils.getStringVal(roleInfoVO.getId()))) { + roleInfoVO.setDisabled(true); + } + } + + List userRoles = QueryChain.of(sysUserRoleMapper).eq(SysUserRole::getUserId, userId).list(); + List roleIds = new ArrayList<>(); + if (Utils.isNotNull(userRoles)) { + roleIds = userRoles.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()); + } + SysUserRoleVO sysUserRoleVO = new SysUserRoleVO(); + sysUserRoleVO.setRoleInfoVOS(roleInfoVOS); + sysUserRoleVO.setSelectIds(roleIds); + return sysUserRoleVO; + } + + @Override + public void changeSysUserRole(SysUserRoleDTO dto) { + // 删除当前用户下的所有角色 + UpdateChain.of(sysUserRoleMapper).eq(SysUserRole::getUserId, dto.getUserId()).remove(); + + if (Utils.isNotNull(dto.getRoleIds())) { + sysUserRoleMapper.insertBatchSysUserRole(dto.getRoleIds(), dto.getUserId()); + } + + List userIds = new ArrayList<>(); + userIds.add(dto.getUserId()); + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(userIds))); + } + + /** + * 获取用户信息 + * + * @return {@link SysUserVO} + */ + @Override + public SysUserVO getUserInfo() { + SysUser sysUser = getById(Objects.requireNonNull(LoginUtils.getLoginUser()).getUserInfo().getId()); + return BeanCopyUtils.copy(sysUser, SysUserVO.class); + } + + /** + * 更改(当前用户)密码 + * + * @param dto + * dto + */ + @Override + public void changePassword(SysUserPasswordDTO dto) { + SysUser sysUser = getById(StpUtil.getLoginIdAsLong()); // 获取当前用户id + CommonResponseEnum.BAD_USERNAME_OR_PASSWORD.assertFalse(matchEncoderPwd(dto.getOldPwd(), sysUser.getPwd())); + sysUser.setPwd(getEncoderPwd(dto.getNewPwd())); + updateById(sysUser); + redisCache.clearUserInfo(sysUser.getUsername()); + authService.kickOut(StpUtil.getLoginIdAsLong()); + } + + /** + * 重置密码 + * + * @param id + * id + */ + @Override + public void resetPassword(Long id) { + SysUser user = getById(id); + CommonResponseEnum.INVALID_ID.assertNull(user); + user.setPwd(getEncoderPwd(getInitPassword())); + updateById(user); + authService.kickOut(id); + } + + private String getInitPassword() { + return SysConfigUtils.getConfValue("sys.user.initPwd"); + } + + @Override + public void syncUserInfo(Object userId) { + List tokens = StpUtil.getTokenValueListByLoginId(userId); + if (tokens.isEmpty()) { + return; + } + // 1. 查询当前用户的最新用户权限信息 + LoginUser loginUser = buildLoginUser(Long.parseLong(userId.toString())); + int successCount = 0; + // todo 如果用户使用了websocket,可以结合socket来判断需要更新的“在线用户”有哪些 + for (String token : tokens) { + try { + // 根据token获取用户session + SaSession saSession = StpUtil.getTokenSessionByToken(token); + // 2. 更新redis信息 + saSession.set(LoginUtils.USER_KEY, loginUser); + successCount++; + } catch (SaTokenException e) { + log.warn("token:{} 已失效, 无需同步用户信息", token); + } + log.info("用户元数据变更,同步更新用户信息 userId:{}, 成功:{} / {}", userId, successCount, tokens.size()); + } + socketService.syncPermission(userId); + } + + @Override + public LoginUser buildLoginUser(String username, String password) { + boolean hasKey = RedisUtils.hasKey(CommonKeyConstants.SYS_PWD_ERR_CNT, username); + Object value = RedisUtils.getValue(CommonKeyConstants.SYS_PWD_ERR_CNT, username); + long count = hasKey ? Long.parseLong(String.valueOf(value)) : 0; + if (!"preview".equals(activeProfile)) { // 预览环境不做账号锁定 + String maxErrCnt = SysConfigUtils.getConfValue("sys.pwd.errCnt"); + CommonResponseEnum.CNT_PASSWORD_ERR.assertTrue(hasKey && (count >= Utils.getIntVal(maxErrCnt))); + } + SysUserVO userVo = getSysUserByUsername(username); + // 用户状态校验(禁用状态校验) + validateUserStatus(userVo); + // 密码校验 + validatePassword(password, userVo.getPwd(), username); + return getLoginUser(userVo); + } + + @Override + public LoginUser buildLoginUser(Long userId) { + SysUserVO userVo = getSysUserByUserId(userId); + return getLoginUser(userVo); + } + + @Override + public void unlock(SelectIdsDTO dto) { + if (dto.getIds() == null || dto.getIds().isEmpty()) + return; + String[] ids = dto.getIds().stream().map(Utils::getStringVal).filter(Objects::nonNull).toArray(String[]::new); + List sysUserVOS = this.mapper.queryAllSysUserNameList(ids); + for (SysUserVO sysUserVO : sysUserVOS) { + RedisUtils.removeKey(CommonKeyConstants.SYS_PWD_ERR_CNT, Utils.getStringVal(sysUserVO.getUsername())); + } + } + + private LoginUser getLoginUser(SysUserVO userVo) { + BaseUserInfo userInfo = BeanCopyUtils.copy(userVo, BaseUserInfo.class); + SysUser sysUser = BeanCopyUtils.copy(userVo, SysUser.class); + CommonResponseEnum.INVALID_USER.assertNull(sysUser); + LoginUser loginUser = new LoginUser(); + loginUser.setUserInfo(userInfo); + loginUser.setPermissions(sysPermissionService.getMenuPermissions(sysUser)); // 获取用户permissions + loginUser.setRoles(sysPermissionService.getRoles(sysUser)); // 获取用户角色 + loginUser.setDepts(sysPermissionService.getDepts(sysUser)); // 获取用户部门 + loginUser.setDeptAndChildren(sysPermissionService.getDeptAndChildren(sysUser)); // 获取用户部门及子孙节点 + if (!dataScopeProperties.isEnabled()) + return loginUser; // 未开启数据权限控制,结束逻辑return !!! + + // 根据角色 获取用户数据权限范围 + Set roles = loginUser.getRoles(); + Map userScope = sysRoleMenuService.getUserScope(roles); + loginUser.setDataScope(userScope); + + Map btmPermissionMap = menuService.getBtnMenuByPermissions(loginUser.getPermissions()); + loginUser.setPermissionAndMenuIds(btmPermissionMap); + + return loginUser; + } + + private void validateUserStatus(SysUserVO user) { + CommonResponseEnum.BAD_USERNAME_STATUS_INVALID.assertFalse(("1000001").equals(user.getAccountStatusCd())); + } + + private void validatePassword(String password, String hashedPassword, String username) { + String timeout = SysConfigUtils.getConfValue("sys_pwd.lockTime"); + boolean checkpwd = BCrypt.checkpw(password, hashedPassword); + if (!checkpwd) + redisCache.countPwdErr(username, Utils.getLongVal(timeout)); + CommonResponseEnum.BAD_USERNAME_OR_PASSWORD.assertFalse(checkpwd); + } + + @Override + public void bindUserDept(UserDeptDTO dto) { + userDeptService.bind(dto); + if (Utils.isNotNull(dto.getUserIds()) && Utils.isNotNull(dto.getDeptIds())) { + bindUserRoleByDept(dto.getUserIds(), dto.getDeptIds()); + } + if (Utils.isNotNull(dto.getUserIds())) { + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(dto.getUserIds()))); + } + } + + /** + * 根据部门绑定角色 + */ + private void bindUserRoleByDept(List userIds, List deptIds) { + if (!Utils.isNotNull(userIds) || !Utils.isNotNull(deptIds)) { + return; + } + + // 获取用户当前拥有的所有角色 + List existingUserRoles = QueryChain.of(sysUserRoleMapper).in(SysUserRole::getUserId, userIds).list(); + Map> userToRoleIdsMap = existingUserRoles.stream() + .collect(Collectors.groupingBy(SysUserRole::getUserId, Collectors.mapping(SysUserRole::getRoleId, Collectors.toSet()))); + // 获取部门关联的所有角色 + List deptRoles = QueryChain.of(sysDeptRoleMapper).in(SysDeptRole::getDeptId, deptIds).list(); + Set deptRoleIds = deptRoles.stream().map(SysDeptRole::getRoleId).collect(Collectors.toSet()); + if (deptRoleIds.isEmpty()) { + return; + } + // 为每个用户构造需要绑定的角色 + List toInsert = new ArrayList<>(); + for (Long userId : userIds) { + Set userRoleIds = userToRoleIdsMap.getOrDefault(userId, Collections.emptySet()); + deptRoleIds.stream().filter(roleId -> !userRoleIds.contains(roleId)).forEach(roleId -> { + SysUserRole sysUserRole = new SysUserRole(); + sysUserRole.setRoleId(roleId); + sysUserRole.setUserId(userId); + toInsert.add(sysUserRole); + }); + } + if (!toInsert.isEmpty()) { + sysUserRoleMapper.insertBatch(toInsert); + // 更新用户元数据 + List changedUserIds = toInsert.stream().map(SysUserRole::getUserId).distinct().toList(); + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(changedUserIds))); + } + } + + @Override + public List getUserOptions() { + QueryWrapper wrapper = QueryWrapper.create().select(SYS_USER.ID, SYS_USER.USERNAME, SYS_USER.NICKNAME); + return listAs(wrapper, UserOptionVO.class); + } + + @Override + public PageResult pageSelector(SelectorQueryDTO dto) { + String keyword = dto.getKeyword(); + Object parentId = dto.getParentId(); + + QueryWrapper wrapper = QueryWrapper.create().select(SYS_USER.ID, SYS_USER.USERNAME, SYS_USER.NICKNAME.as("name"), SYS_USER.PHONE).from(SYS_USER); + + if (parentId != null && !("-1").equals(parentId.toString())) { + wrapper.join(SYS_USER_DEPT).on(SYS_USER.ID.eq(SYS_USER_DEPT.USER_ID)).join(SYS_DEPT_CLOSURE) + .on(SYS_USER_DEPT.DEPT_ID.eq(SYS_DEPT_CLOSURE.DESCENDANT_ID)).join(SYS_DEPT).on(SYS_USER_DEPT.DEPT_ID.eq(SYS_DEPT.ID)) + .where(SYS_DEPT_CLOSURE.DESCENDANT_ID.isNotNull()).and(SYS_DEPT_CLOSURE.ANCESTOR_ID.eq(parentId)).groupBy(SYS_USER.ID) + .orderBy(SYS_USER.CREATE_TIME.asc()); + } + + // 关键词条件 + if (keyword != null && !keyword.isEmpty()) { + QueryCondition condition = SYS_USER.USERNAME.like(keyword).or(SYS_USER.NICKNAME.like(keyword)).or(SYS_USER.PHONE.like(keyword)); + wrapper.and(condition); + } + + Page page = pageAs(PageUtils.getPage(dto), wrapper, UserVO.class); + return PageUtils.getPageResult(page); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void changeUserTag(SysUserTagDTO dto) { + String userTagCd = dto.getUserTagCd(); + List userIds = dto.getUserIds(); + String superAdminRoleId = SysConfigUtils.getConfValue("sys.admin.superAdminRoleId"); + if (userIds.isEmpty()) { + return; + } + UpdateChain.of(SysUser.class).set(SYS_USER.USER_TAG_CD, userTagCd).where(SYS_USER.ID.in(userIds)).update(); // 更新用户标签 + UpdateChain.of(SysUserRole.class).where(SYS_USER_ROLE.USER_ID.in(userIds)).where(SYS_USER_ROLE.ROLE_ID.eq(Utils.getLongVal(superAdminRoleId))).remove(); // 删除超管角色 + List userRoles = new ArrayList<>(); + SysUserRole userRole; + if ("1001002".equals(userTagCd)) { // 超管角色用户 + for (Long userId : userIds) { + userRole = new SysUserRole(); + userRole.setUserId(userId); + userRole.setRoleId(Utils.getLongVal(superAdminRoleId)); + userRoles.add(userRole); + } + } + if (!userRoles.isEmpty()) { + sysUserRoleMapper.insertBatch(userRoles); + } + // 发布用户权限变更事件 + eventPublisher.publish(new PermissionChangeEvent(this, new PermissionMeta(userIds))); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/controller/TeacherStatisticsController.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/controller/TeacherStatisticsController.java new file mode 100644 index 0000000..1c0bd74 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/controller/TeacherStatisticsController.java @@ -0,0 +1,98 @@ +package com.sz.admin.teacher.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsCreateDTO; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsListDTO; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsUpdateDTO; +import com.sz.admin.teacher.pojo.vo.TeacherStatisticsVO; +import com.sz.admin.teacher.service.TeacherStatisticsService; +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.*; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + *

+ * 教师统计总览表 Controller + *

+ * + * @author sz + * @since 2024-02-19 + */ +@Tag(name = "教师统计总览表") +@RestController +@RequestMapping("teacher-statistics") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class TeacherStatisticsController { + + private final TeacherStatisticsService teacherStatisticsService; + + @Operation(summary = "新增") + @SaCheckPermission(value = "teacher.statistics.create", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping + public ApiResult create(@RequestBody TeacherStatisticsCreateDTO dto) { + teacherStatisticsService.create(dto); + return ApiResult.success(); + } + + @Operation(summary = "修改") + @SaCheckPermission(value = "teacher.statistics.update", orRole = GlobalConstant.SUPER_ROLE) + @PutMapping + public ApiResult update(@RequestBody TeacherStatisticsUpdateDTO dto) { + teacherStatisticsService.update(dto); + return ApiResult.success(); + } + + @Operation(summary = "删除") + @SaCheckPermission(value = "teacher.statistics.remove", orRole = GlobalConstant.SUPER_ROLE) + @DeleteMapping + public ApiResult remove(@RequestBody SelectIdsDTO dto) { + teacherStatisticsService.remove(dto); + return ApiResult.success(); + } + + @Operation(summary = "列表查询") + @SaCheckPermission(value = "teacher.statistics.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping + public ApiResult> list(TeacherStatisticsListDTO dto) { + return ApiPageResult.success(teacherStatisticsService.page(dto)); + } + + @Operation(summary = "详情") + @SaCheckPermission(value = "teacher.statistics.query_table", orRole = GlobalConstant.SUPER_ROLE) + @GetMapping("/{id}") + public ApiResult detail(@PathVariable Long id) { + return ApiResult.success(teacherStatisticsService.detail(id)); + } + + @Operation(summary = "导入", parameters = { + @Parameter(name = "file", description = "上传文件", schema = @Schema(type = "string", format = "binary"), required = true)}) + @SaCheckPermission(value = "teacher.statistics.import", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping("/import") + public void importExcel(@ModelAttribute ImportExcelDTO dto) { + teacherStatisticsService.importExcel(dto); + } + + @Operation(summary = "导出") + @SaCheckPermission(value = "teacher.statistics.export", orRole = GlobalConstant.SUPER_ROLE) + @PostMapping("/export") + public void exportExcel(@RequestBody TeacherStatisticsListDTO dto, HttpServletResponse response) { + teacherStatisticsService.exportExcel(dto, response); + } + + @Operation(summary = "远程搜索测试接口") + @GetMapping("/remote/{keyword}") + public ApiResult> remoteSearch(@PathVariable String keyword) { + return ApiResult.success(teacherStatisticsService.remoteSearch(keyword)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/mapper/TeacherStatisticsMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/mapper/TeacherStatisticsMapper.java new file mode 100644 index 0000000..5a9a2b0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/mapper/TeacherStatisticsMapper.java @@ -0,0 +1,16 @@ +package com.sz.admin.teacher.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.admin.teacher.pojo.po.TeacherStatistics; + +/** + *

+ * 教师统计总览表 Mapper 接口 + *

+ * + * @author sz-admin + * @since 2024-06-19 + */ +public interface TeacherStatisticsMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsCreateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsCreateDTO.java new file mode 100644 index 0000000..47bea1b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsCreateDTO.java @@ -0,0 +1,71 @@ +package com.sz.admin.teacher.pojo.dto; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * TeacherStatistics添加DTO + *

+ * + * @author sz-admin + * @since 2024-06-19 + */ +@Data +@Schema(description = "TeacherStatistics添加DTO") +public class TeacherStatisticsCreateDTO { + + @Schema(description = "统计年限") + private String year; + + @Schema(description = "统计月份") + private String month; + + @Schema(description = "统计年月") + private String duringTime; + + @Schema(description = "教师id") + private String teacherId; + + @Schema(description = "讲师区分类型") + private Integer teacherCommonType; + + @Schema(description = "授课总数") + private Integer totalTeaching; + + @Schema(description = "服务班次数") + private Integer totalClassCount; + + @Schema(description = "课时总数") + private BigDecimal totalHours; + + @Schema(description = "核对状态") + private Integer checkStatus; + + @Schema(description = "核对时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime checkTime; + + @Schema(description = "最近一次同步时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastSyncTime; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "文件地址(JSON)") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "内容html") + private String contentHtml; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsImportDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsImportDTO.java new file mode 100644 index 0000000..862c721 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsImportDTO.java @@ -0,0 +1,77 @@ +package com.sz.admin.teacher.pojo.dto; + +import cn.idev.excel.annotation.ExcelIgnore; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import org.springframework.format.annotation.DateTimeFormat; + +import cn.idev.excel.annotation.ExcelProperty; +/** + *

+ * TeacherStatistics导入DTO + *

+ * + * @author sz-admin + * @since 2024-06-19 + */ +@Data +@Schema(description = "TeacherStatistics导入DTO") +public class TeacherStatisticsImportDTO { + + @ExcelProperty(value = "统计年份") + @Schema(description = "统计年份") + private String year; + + @ExcelProperty(value = "统计月份") + @Schema(description = "统计月份") + private String month; + + @ExcelProperty(value = "统计年月") + @Schema(description = "统计年月") + private String duringTime; + + @ExcelProperty(value = "教师id") + @Schema(description = "教师id") + private String teacherId; + + @ExcelProperty(value = "讲师区分类型") + // 如果字典使用的是别名 使用如下设置 useAlias = true + // @DictFormat(dictType = "account_status", useAlias = true) + @Schema(description = "讲师区分类型") + private String teacherCommonType; + + @ExcelProperty(value = "授课总数") + @Schema(description = "授课总数") + private Integer totalTeaching; + + @ExcelProperty(value = "服务班次数") + @Schema(description = "服务班次数") + private Integer totalClassCount; + + @ExcelProperty(value = "课时总数") + @Schema(description = "课时总数") + private BigDecimal totalHours; + + @ExcelProperty(value = "核对状态") + /* @DictFormat(dictType = "account_status") */ + @Schema(description = "核对状态") + private String checkStatus; + + @ExcelProperty(value = "核对时间") + @Schema(description = "核对时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime checkTime; + + @Schema(description = "最近一次同步时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastSyncTime; + + @ExcelIgnore + // @ExcelProperty(value = "备注") + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsListDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsListDTO.java new file mode 100644 index 0000000..ff37f52 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsListDTO.java @@ -0,0 +1,63 @@ +package com.sz.admin.teacher.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import com.sz.core.common.entity.PageQuery; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * TeacherStatistics添加DTO + *

+ * + * @author sz + * @since 2024-06-19 + */ +@Data +@Schema(description = "TeacherStatistics查询DTO") +public class TeacherStatisticsListDTO extends PageQuery { + + @Schema(description = "统计年限") + private String year; + + @Schema(description = "统计月份") + private String month; + + @Schema(description = "统计年月") + private String duringTime; + + @Schema(description = "教师id") + private String teacherId; + + @Schema(description = "讲师区分类型") + private Integer teacherCommonType; + + @Schema(description = "授课总数") + private Integer totalTeaching; + + @Schema(description = "服务班次数") + private Integer totalClassCount; + + @Schema(description = "课时总数") + private BigDecimal totalHours; + + @Schema(description = "核对状态") + private Integer checkStatus; + + @Schema(description = "核对时间开始") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime checkTimeStart; + + @Schema(description = "核对时间结束") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime checkTimeEnd; + + @Schema(description = "最近一次同步时间") + private LocalDateTime lastSyncTime; + + @Schema(description = "远程搜索KV属性ID") + private Long remoteTeacherId; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsUpdateDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsUpdateDTO.java new file mode 100644 index 0000000..5a8422c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/dto/TeacherStatisticsUpdateDTO.java @@ -0,0 +1,74 @@ +package com.sz.admin.teacher.pojo.dto; + +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import org.springframework.format.annotation.DateTimeFormat; + +/** + *

+ * TeacherStatistics添加DTO + *

+ * + * @author sz-admin + * @since 2024-06-19 + */ +@Data +@Schema(description = "TeacherStatistics修改DTO") +public class TeacherStatisticsUpdateDTO { + + @Schema(description = "id") + private Long id; + + @Schema(description = "统计年限") + private String year; + + @Schema(description = "统计月份") + private String month; + + @Schema(description = "统计年月") + private String duringTime; + + @Schema(description = "教师id") + private String teacherId; + + @Schema(description = "讲师区分类型") + private Integer teacherCommonType; + + @Schema(description = "授课总数") + private Integer totalTeaching; + + @Schema(description = "服务班次数") + private Integer totalClassCount; + + @Schema(description = "课时总数") + private BigDecimal totalHours; + + @Schema(description = "核对状态") + private Integer checkStatus; + + @Schema(description = "核对时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime checkTime; + + @Schema(description = "最近一次同步时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastSyncTime; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "文件地址(JSON)") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "内容html") + private String contentHtml; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/po/TeacherStatistics.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/po/TeacherStatistics.java new file mode 100644 index 0000000..fa942ea --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/po/TeacherStatistics.java @@ -0,0 +1,98 @@ +package com.sz.admin.teacher.pojo.po; + +import com.mybatisflex.annotation.*; + +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +import com.sz.mysql.EntityChangeListener; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 教师统计总览表 + *

+ * + * @author sz + * @since 2024-02-19 + */ +@Data +@Table(value = "teacher_statistics", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "教师统计总览表") +public class TeacherStatistics implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "id") + private Long id; + + @Schema(description = "统计年限") + private String year; + + @Schema(description = "统计月份") + private String month; + + @Schema(description = "统计年月") + private String duringTime; + + @Schema(description = "教师id") + private String teacherId; + + @Schema(description = "讲师区分类型") + private Integer teacherCommonType; + + @Schema(description = "授课总数") + private Integer totalTeaching; + + @Schema(description = "服务班次数") + private Integer totalClassCount; + + @Schema(description = "课时总数") + private BigDecimal totalHours; + + @Schema(description = "核对状态") + private Integer checkStatus; + + @Schema(description = "核对时间") + private LocalDateTime checkTime; + + @Schema(description = "最近一次同步时间") + private LocalDateTime lastSyncTime; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建人ID") + private Long createId; + + @Schema(description = "生成时间") + private LocalDateTime createTime; + + @Schema(description = "更新人ID") + private Long updateId; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "部门范围id") + @Column(typeHandler = JacksonTypeHandler.class) + private List deptScope; + + @Schema(description = "文件地址(JSON)") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @Schema(description = "内容html") + private String contentHtml; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/vo/TeacherStatisticsVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/vo/TeacherStatisticsVO.java new file mode 100644 index 0000000..3aa22e5 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/pojo/vo/TeacherStatisticsVO.java @@ -0,0 +1,126 @@ +package com.sz.admin.teacher.pojo.vo; + +import cn.idev.excel.annotation.ExcelIgnore; +import cn.idev.excel.annotation.ExcelProperty; +import com.mybatisflex.annotation.Column; +import com.mybatisflex.core.handler.JacksonTypeHandler; +import com.sz.excel.annotation.CellMerge; +import com.sz.excel.annotation.DictFormat; +import com.sz.core.common.entity.UploadResult; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * TeacherStatistics查询返回 + *

+ * + * @author sz-admin + * @since 2024-06-19 + */ +@Data +@Schema(description = "TeacherStatistics返回vo") +public class TeacherStatisticsVO { + + @ExcelIgnore + @Schema(description = "id") + private Long id; + + @ExcelProperty(value = "统计年限") + @Schema(description = "统计年限") + private String year; + + @ExcelProperty(value = "统计月份") + @Schema(description = "统计月份") + private String month; + + @ExcelProperty(value = "统计年月") + @Schema(description = "统计年月") + @CellMerge + private String duringTime; + + @ExcelProperty(value = "教师id") + @Schema(description = "教师id") + private String teacherId; + + @ExcelProperty(value = "讲师区分类型") + // 如果字典使用的是别名 使用如下设置 useAlias = true + // @DictFormat(dictType = "account_status", isSelected = true, useAlias = true) + @Schema(description = "讲师区分类型") + private Integer teacherCommonType; + + @ExcelProperty(value = "授课总数") + @Schema(description = "授课总数") + private Integer totalTeaching; + + @ExcelProperty(value = "服务班次数") + @Schema(description = "服务班次数") + private Integer totalClassCount; + + @ExcelProperty(value = "课时总数") + @Schema(description = "课时总数") + private BigDecimal totalHours; + + @ExcelProperty(value = "核对状态") + @Schema(description = "核对状态") + @DictFormat(dictType = "account_status") + private Integer checkStatus; + + @ExcelProperty(value = "核对时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "核对时间") + private LocalDateTime checkTime; + + @ExcelProperty(value = "最近一次同步时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "最近一次同步时间") + private LocalDateTime lastSyncTime; + + @ExcelProperty(value = "备注") + @Schema(description = "备注") + private String remark; + + @ExcelProperty(value = "创建人") + @DictFormat(dictType = "dynamic_user_options") + @Schema(description = "创建人") + private Long createId; + + @ExcelProperty(value = "创建时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @ExcelProperty(value = "更新人") + @DictFormat(dictType = "dynamic_user_options") + @Schema(description = "更新人") + private Long updateId; + + @ExcelProperty(value = "更新时间") + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @ExcelIgnore + @Schema(description = "文件地址(JSON)") + @Column(typeHandler = JacksonTypeHandler.class) + private List url; + + @ExcelIgnore + @Schema(description = "内容html") + private String contentHtml; + + @Data + public static class TeacherTypeEnum { + + private long id; + + private String teacherId; + + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/service/TeacherStatisticsService.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/service/TeacherStatisticsService.java new file mode 100644 index 0000000..efe3830 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/service/TeacherStatisticsService.java @@ -0,0 +1,43 @@ +package com.sz.admin.teacher.service; + +import com.mybatisflex.core.service.IService; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsCreateDTO; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsListDTO; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsUpdateDTO; +import com.sz.admin.teacher.pojo.po.TeacherStatistics; +import com.sz.admin.teacher.pojo.vo.TeacherStatisticsVO; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import jakarta.servlet.http.HttpServletResponse; + +import java.util.List; + +/** + *

+ * 教师统计总览表 Service + *

+ * + * @author sz + * @since 2024-02-19 + */ +public interface TeacherStatisticsService extends IService { + + void create(TeacherStatisticsCreateDTO dto); + + void update(TeacherStatisticsUpdateDTO dto); + + PageResult page(TeacherStatisticsListDTO dto); + + List list(TeacherStatisticsListDTO dto); + + void remove(SelectIdsDTO dto); + + TeacherStatisticsVO detail(Long id); + + void importExcel(ImportExcelDTO dto); + + void exportExcel(TeacherStatisticsListDTO dto, HttpServletResponse response); + + List remoteSearch(String keyword); +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/service/impl/TeacherStatisticsServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/service/impl/TeacherStatisticsServiceImpl.java new file mode 100644 index 0000000..5474c3d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/admin/teacher/service/impl/TeacherStatisticsServiceImpl.java @@ -0,0 +1,163 @@ +package com.sz.admin.teacher.service.impl; + +import com.mybatisflex.core.paginate.Page; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.admin.teacher.mapper.TeacherStatisticsMapper; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsCreateDTO; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsImportDTO; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsListDTO; +import com.sz.admin.teacher.pojo.dto.TeacherStatisticsUpdateDTO; +import com.sz.admin.teacher.pojo.po.TeacherStatistics; +import com.sz.admin.teacher.pojo.vo.TeacherStatisticsVO; +import com.sz.admin.teacher.service.TeacherStatisticsService; +import com.sz.core.common.entity.ImportExcelDTO; +import com.sz.core.common.entity.PageResult; +import com.sz.core.common.entity.SelectIdsDTO; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.datascope.SimpleDataScopeHelper; +import com.sz.core.util.*; +import com.sz.excel.core.ExcelResult; +import com.sz.excel.utils.ExcelUtils; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.stereotype.Service; + +import java.io.OutputStream; +import java.util.List; + +/** + *

+ * 教师统计总览表 服务实现类 + *

+ * + * @author sz + * @since 2024-02-19 + */ +@Service +@RequiredArgsConstructor +public class TeacherStatisticsServiceImpl extends ServiceImpl implements TeacherStatisticsService { + + @Override + public void create(TeacherStatisticsCreateDTO dto) { + TeacherStatistics teacherStatistics = BeanCopyUtils.copy(dto, TeacherStatistics.class); + // 唯一性校验 + save(teacherStatistics); + } + + @Override + public void update(TeacherStatisticsUpdateDTO dto) { + TeacherStatistics teacherStatistics = BeanCopyUtils.copy(dto, TeacherStatistics.class); + QueryWrapper wrapper; + // id有效性校验 + wrapper = QueryWrapper.create().eq(TeacherStatistics::getId, dto.getId()); + CommonResponseEnum.INVALID_ID.assertTrue(count(wrapper) <= 0); + // 唯一性校验 + saveOrUpdate(teacherStatistics); + } + + @Override + public PageResult page(TeacherStatisticsListDTO dto) { + try { + SimpleDataScopeHelper.start(TeacherStatistics.class); // 指定要追加条件的表PO实体 + Page page = pageAs(PageUtils.getPage(dto), buildQueryWrapper(dto), TeacherStatisticsVO.class); // 调试sql + return PageUtils.getPageResult(page); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public List list(TeacherStatisticsListDTO dto) { + try { + SimpleDataScopeHelper.start(TeacherStatistics.class); // 指定要追加条件的表PO实体 + return listAs(buildQueryWrapper(dto), TeacherStatisticsVO.class); + } finally { + SimpleDataScopeHelper.clearDataScope(); + } + } + + @Override + public void remove(SelectIdsDTO dto) { + CommonResponseEnum.INVALID_ID.assertTrue(dto.getIds().isEmpty()); + removeByIds(dto.getIds()); + } + + @Override + public TeacherStatisticsVO detail(Long id) { + TeacherStatistics teacherStatistics = getById(id); + CommonResponseEnum.INVALID_ID.assertNull(teacherStatistics); + return BeanCopyUtils.copy(teacherStatistics, TeacherStatisticsVO.class); + } + + @SneakyThrows + @Override + public void importExcel(ImportExcelDTO dto) { + ExcelResult excelResult = ExcelUtils.importExcel(dto.getFile().getInputStream(), TeacherStatisticsImportDTO.class, true); + List list = excelResult.getList(); + List cpList = BeanCopyUtils.copyList(list, TeacherStatistics.class); + saveBatch(cpList); + List errorList = excelResult.getErrorList(); + String analysis = excelResult.getAnalysis(); + System.out.println(" analysis : " + analysis); + System.out.println(" isCover : " + dto.getIsCover()); + System.out.println("list ==" + JsonUtils.toJsonString(list)); + } + + @SneakyThrows + @Override + public void exportExcel(TeacherStatisticsListDTO dto, HttpServletResponse response) { + List list = list(dto); + String fileName = "教师统计"; + OutputStream os = FileUtils.getOutputStream(response, fileName + ".xlsx"); + ExcelUtils.exportExcel(list, fileName, TeacherStatisticsVO.class, os, true); + } + + private static QueryWrapper buildQueryWrapper(TeacherStatisticsListDTO dto) { + QueryWrapper wrapper = QueryWrapper.create().from(TeacherStatistics.class); + if (Utils.isNotNull(dto.getYear())) { + wrapper.eq(TeacherStatistics::getYear, dto.getYear()); + } + if (Utils.isNotNull(dto.getMonth())) { + wrapper.eq(TeacherStatistics::getMonth, dto.getMonth()); + } + if (Utils.isNotNull(dto.getDuringTime())) { + wrapper.eq(TeacherStatistics::getDuringTime, dto.getDuringTime()); + } + if (Utils.isNotNull(dto.getTeacherId())) { + wrapper.eq(TeacherStatistics::getTeacherId, dto.getTeacherId()); + } + if (Utils.isNotNull(dto.getTeacherCommonType())) { + wrapper.eq(TeacherStatistics::getTeacherCommonType, dto.getTeacherCommonType()); + } + if (Utils.isNotNull(dto.getTotalTeaching())) { + wrapper.eq(TeacherStatistics::getTotalTeaching, dto.getTotalTeaching()); + } + if (Utils.isNotNull(dto.getTotalClassCount())) { + wrapper.eq(TeacherStatistics::getTotalClassCount, dto.getTotalClassCount()); + } + if (Utils.isNotNull(dto.getTotalHours())) { + wrapper.eq(TeacherStatistics::getTotalHours, dto.getTotalHours()); + } + if (Utils.isNotNull(dto.getCheckStatus())) { + wrapper.eq(TeacherStatistics::getCheckStatus, dto.getCheckStatus()); + } + if (Utils.isNotNull(dto.getCheckTimeStart()) && Utils.isNotNull(dto.getCheckTimeEnd())) { + wrapper.between(TeacherStatistics::getCheckTime, dto.getCheckTimeStart(), dto.getCheckTimeEnd()); + } + if (Utils.isNotNull(dto.getRemoteTeacherId())) { + wrapper.eq(TeacherStatistics::getId, dto.getRemoteTeacherId()); + } + return wrapper; + } + + @SneakyThrows + @Override + public List remoteSearch(String keyword) { + Thread.sleep(1000); + QueryWrapper wrapper = QueryWrapper.create().from(TeacherStatistics.class).like(TeacherStatistics::getTeacherId, keyword); + return listAs(wrapper, TeacherStatisticsVO.TeacherTypeEnum.class); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/controller/MiniUserController.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/controller/MiniUserController.java new file mode 100644 index 0000000..3e09294 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/controller/MiniUserController.java @@ -0,0 +1,37 @@ +package com.sz.applet.miniuser.controller; + +import com.sz.applet.miniuser.pojo.dto.MiniLoginDTO; +import com.sz.applet.miniuser.pojo.vo.MiniUserVO; +import com.sz.applet.miniuser.service.MiniUserService; +import com.sz.core.common.entity.ApiResult; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 小程序用户表 Controller + *

+ * + * @author sz + * @since 2024-04-26 + */ +@Tag(name = "微信小程序用户") +@RestController +@RequestMapping("wechat/mini/user") +@RequiredArgsConstructor +public class MiniUserController { + + private final MiniUserService miniUserService; + + @Operation(summary = "登录") + @PostMapping("login") + public ApiResult login(@RequestBody MiniLoginDTO dto) { + return ApiResult.success(miniUserService.doLogin(dto)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/mapper/MiniUserMapper.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/mapper/MiniUserMapper.java new file mode 100644 index 0000000..eef7cfb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/mapper/MiniUserMapper.java @@ -0,0 +1,16 @@ +package com.sz.applet.miniuser.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.sz.applet.miniuser.pojo.po.MiniUser; + +/** + *

+ * 小程序用户表 Mapper 接口 + *

+ * + * @author sz + * @since 2024-04-26 + */ +public interface MiniUserMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/dto/MiniLoginDTO.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/dto/MiniLoginDTO.java new file mode 100644 index 0000000..17b046d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/dto/MiniLoginDTO.java @@ -0,0 +1,18 @@ +package com.sz.applet.miniuser.pojo.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * MiniLoginDTO + * + * @author sz + * @since 2024/4/26 14:25 + * @version 1.0 + */ +@Data +public class MiniLoginDTO { + + @Schema(description = "小程序登录凭证") + private String code; +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/po/MiniLoginUser.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/po/MiniLoginUser.java new file mode 100644 index 0000000..826e92e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/po/MiniLoginUser.java @@ -0,0 +1,37 @@ +package com.sz.applet.miniuser.pojo.po; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * MiniLoginUser + * + * @author sz + * @since 2024/4/28 14:15 + * @version 1.0 + */ +@Data +public class MiniLoginUser { + + @Schema(description = "用户ID(MiniUser表主键)") + private Long userId; + + @Schema(description = "小程序openid") + private String openid; + + @Schema(description = "用户名") + private String username; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "手机号,手机号为空则未绑定") + private String phone; + + @Schema(description = "LOGO") + private String logo; + + @Schema(description = "邮箱,邮箱为空则未绑定") + private String email; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/po/MiniUser.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/po/MiniUser.java new file mode 100644 index 0000000..5622c9a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/po/MiniUser.java @@ -0,0 +1,68 @@ +package com.sz.applet.miniuser.pojo.po; + +import com.mybatisflex.annotation.*; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import com.sz.mysql.EntityChangeListener; +import java.time.LocalDateTime; +/** + *

+ * 小程序用户表 + *

+ * + * @author sz + * @since 2024-04-26 + */ +@Data +@Table(value = "mini_user", onInsert = EntityChangeListener.class, onUpdate = EntityChangeListener.class) +@Schema(description = "小程序用户表") +public class MiniUser implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id(keyType = KeyType.Auto) + @Schema(description = "ID") + private Integer id; + + @Schema(description = "关联的系统用户ID") + private Integer sysUserId; + + @Schema(description = "小程序用户的唯一标识") + private String openid; + + @Schema(description = "公众号的唯一标识") + private String unionid; + + @Schema(description = "昵称") + private String nickname; + + @Schema(description = "真实姓名") + private String name; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "用户头像URL") + private String avatarUrl; + + @Schema(description = "是否订阅公众号(1是0否)") + private Integer subscribe; + + @Schema(description = "性别,0-未知 1-男性,2-女性") + private Integer sex; + + @Schema(description = "删除标识") + private String delFlag; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/vo/MiniUserVO.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/vo/MiniUserVO.java new file mode 100644 index 0000000..d80a913 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/pojo/vo/MiniUserVO.java @@ -0,0 +1,18 @@ +package com.sz.applet.miniuser.pojo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + *

+ * MiniUser查询返回 + *

+ * + * @author sz + * @since 2024-04-26 + */ +@Data +@Schema(description = "MiniUser返回vo") +public class MiniUserVO { + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/service/MiniUserService.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/service/MiniUserService.java new file mode 100644 index 0000000..f9ee99f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/service/MiniUserService.java @@ -0,0 +1,23 @@ +package com.sz.applet.miniuser.service; + +import com.mybatisflex.core.service.IService; +import com.sz.applet.miniuser.pojo.dto.MiniLoginDTO; +import com.sz.applet.miniuser.pojo.po.MiniLoginUser; +import com.sz.applet.miniuser.pojo.po.MiniUser; + +import com.sz.applet.miniuser.pojo.vo.MiniUserVO; + +/** + *

+ * 小程序用户表 Service + *

+ * + * @author sz + * @since 2024-04-26 + */ +public interface MiniUserService extends IService { + + MiniUserVO doLogin(MiniLoginDTO dto); + + MiniLoginUser getUserByOpenId(String openId, String unionid); +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/service/impl/MiniUserServiceImpl.java b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/service/impl/MiniUserServiceImpl.java new file mode 100644 index 0000000..0b654bf --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/applet/miniuser/service/impl/MiniUserServiceImpl.java @@ -0,0 +1,64 @@ +package com.sz.applet.miniuser.service.impl; + +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import com.sz.applet.miniuser.mapper.MiniUserMapper; +import com.sz.applet.miniuser.pojo.dto.MiniLoginDTO; +import com.sz.applet.miniuser.pojo.po.MiniLoginUser; +import com.sz.applet.miniuser.pojo.po.MiniUser; +import com.sz.applet.miniuser.pojo.vo.MiniUserVO; +import com.sz.applet.miniuser.service.MiniUserService; +import com.sz.core.util.JsonUtils; +import com.sz.core.util.Utils; +import com.sz.wechat.mini.MiniWechatService; +import com.sz.wechat.mini.LoginInfoResult; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import static com.sz.applet.miniuser.pojo.po.table.MiniUserTableDef.MINI_USER; + +/** + *

+ * 小程序用户表 服务实现类 + *

+ * + * @author sz + * @since 2024-04-26 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class MiniUserServiceImpl extends ServiceImpl implements MiniUserService { + + private final MiniWechatService miniWechatService; + + @Override + public MiniUserVO doLogin(MiniLoginDTO dto) { + String accessToken = miniWechatService.getAccessToken(); + LoginInfoResult loginInfoResult = miniWechatService.miniLogin(dto.getCode(), accessToken); + log.info(" 小程序登录返回信息:{}", JsonUtils.toJsonString(loginInfoResult)); + // [do something ...] 结合实际业务进行处理 + return null; + } + + @Override + public MiniLoginUser getUserByOpenId(String openId, String unionid) { + QueryWrapper wrapper = QueryWrapper.create().where(MINI_USER.OPENID.eq(openId)); + MiniUser miniUser = getOne(wrapper); + if (miniUser == null) { + // [do something ...] 创建新的微信用户信息 + } else { + // 绑定了sys_user账户 + if (Utils.isNotNull(miniUser.getSysUserId())) { + // [do something ...] + } else { + // 未绑定sys_user账户 + // [do something ...] + } + } + + return null; + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/configuration/Knife4jConfiguration.java b/sz-service/sz-service-admin/src/main/java/com/sz/configuration/Knife4jConfiguration.java new file mode 100644 index 0000000..db2cd4c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/configuration/Knife4jConfiguration.java @@ -0,0 +1,18 @@ +package com.sz.configuration; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class Knife4jConfiguration { + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI().info(new Info().title("sz-admin后台管理系统API").version("1.0").description("Sz-Admin RESTful APIs") + .termsOfService("http://127.0.0.1:9991").license(new License().name("Apache 2.0").url("http://127.0.0.1:9991"))); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/configuration/MapperConfiguration.java b/sz-service/sz-service-admin/src/main/java/com/sz/configuration/MapperConfiguration.java new file mode 100644 index 0000000..e9bd64c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/configuration/MapperConfiguration.java @@ -0,0 +1,15 @@ +package com.sz.configuration; + +import lombok.extern.slf4j.Slf4j; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Configuration; + +/** + * @author sz + * @since 2022/8/26 15:14 + */ +@Slf4j +@Configuration +@MapperScan(basePackages = {"com.sz.admin.*.mapper", "com.sz.generator.mapper", "com.sz.applet.*.mapper"}) +public class MapperConfiguration { +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/DebounceAspect.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/DebounceAspect.java new file mode 100644 index 0000000..549d248 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/DebounceAspect.java @@ -0,0 +1,98 @@ +package com.sz.platform.debounce; + +import com.sz.core.common.annotation.Debounce; +import com.sz.core.common.annotation.DebounceIgnore; +import com.sz.core.common.entity.ApiPageResult; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.Utils; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; + +/** + * 接口防抖切面 + *

+ * DebounceAspect + * + * @author sz + * @version 1.0 + * @since 2024/9/18 11:13 + */ +@Component +@Aspect +@Order(value = Integer.MIN_VALUE) +@RequiredArgsConstructor +public class DebounceAspect { + + private final RedisDebounceService debounceService; + + private final HttpServletRequest request; + + private final DebounceProperties debounceProperties; + + @Pointcut("(execution(* com.sz..*Controller.*(..)))") + public void methodArgs() { + } + + @Around("methodArgs()") + public Object debounceInterceptor(ProceedingJoinPoint point) throws Throwable { + Method method = ((MethodSignature) point.getSignature()).getMethod(); + String httpMethod = request.getMethod(); + boolean isDebounceAnno = method.isAnnotationPresent(Debounce.class); + // 检查:是否开启了防抖、是否标注了 @DebounceIgnore 注解 + if (!debounceProperties.isEnabled() || method.isAnnotationPresent(DebounceIgnore.class)) { + return point.proceed(); // 直接执行,不做防抖处理 + } + // 忽略GET请求 + if (debounceProperties.isIgnoreGetMethod() && !isDebounceAnno && "GET".equalsIgnoreCase(httpMethod)) { + return point.proceed(); // 直接执行,不做防抖处理 + } + long lockTime = debounceProperties.getGlobalLockTime(); + if (isDebounceAnno) { + Debounce debounce = method.getAnnotation(Debounce.class); + lockTime = debounce.time(); + } + + String lockKey = Utils.generateDebounceRequestId(request); + // 尝试获取分布式锁 + boolean lockAcquired = debounceService.acquireLock(lockKey, lockTime); + if (!lockAcquired) { + // 锁获取失败,返回防抖提示 + if (CompletableFuture.class.isAssignableFrom(method.getReturnType())) { + return CompletableFuture.completedFuture(ApiResult.error(CommonResponseEnum.DEBOUNCE)); // 异步返回结构。 + } else { + // 获取返回类型 + Class returnType = method.getReturnType(); + + // 如果返回类型是 ApiPageResult + if (returnType.isAssignableFrom(ApiPageResult.class)) { + return ApiPageResult.error(CommonResponseEnum.DEBOUNCE); // 返回 ApiPageResult + } + // 如果返回类型是 ApiResult + else if (returnType.isAssignableFrom(ApiResult.class)) { + return ApiResult.error(CommonResponseEnum.DEBOUNCE); // 返回 ApiResult + } + // 如果返回类型是其他类型,比如 String。 + else if (returnType.isAssignableFrom(String.class)) { + return CommonResponseEnum.DEBOUNCE.getMessage(); // 返回简单的字符串 + } + // 如果是其他类型,抛出异常或者做其他处理 + else { + throw new IllegalStateException("无法处理的返回类型:" + method.getReturnType().getName()); + } + } + } + return point.proceed(); // 执行方法 + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/DebounceProperties.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/DebounceProperties.java new file mode 100644 index 0000000..aa21d21 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/DebounceProperties.java @@ -0,0 +1,25 @@ +package com.sz.platform.debounce; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * DebounceProperties + * + * @author sz + * @since 2024/9/18 17:19 + * @version 1.0 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "sz.debounce") +public class DebounceProperties { + + private boolean enabled = true; + + private long globalLockTime = 1000; + + private boolean ignoreGetMethod; + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/RedisDebounceService.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/RedisDebounceService.java new file mode 100644 index 0000000..8e770ba --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/debounce/RedisDebounceService.java @@ -0,0 +1,38 @@ +package com.sz.platform.debounce; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +/** + * RedisDebounceService + * + * @author sz + * @since 2024/9/18 10:05 + * @version 1.0 + */ +@Service +@RequiredArgsConstructor +public class RedisDebounceService { + + private final StringRedisTemplate redisTemplate; + + private static final String DEBOUNCE_PREFIX = "debounce:"; + + // 尝试获取分布式锁 + public boolean acquireLock(String key, long debounceInterval) { + ValueOperations ops = redisTemplate.opsForValue(); + // 这里使用redis锁保证分布式场景下的稳定性 + Boolean result = ops.setIfAbsent(DEBOUNCE_PREFIX + key, "true", debounceInterval, TimeUnit.MILLISECONDS); + return Boolean.TRUE.equals(result); + } + + // 释放分布式锁 + public void releaseLock(String key) { + redisTemplate.delete(DEBOUNCE_PREFIX + key); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/enums/AdminResponseEnum.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/enums/AdminResponseEnum.java new file mode 100644 index 0000000..3585454 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/enums/AdminResponseEnum.java @@ -0,0 +1,51 @@ +package com.sz.platform.enums; + +import com.sz.core.common.enums.ErrorPrefixEnum; +import com.sz.core.common.enums.ResponseEnumTemplate; + +/** + * 异常枚举类 适用于Admin模块的 操作 + */ +public enum AdminResponseEnum implements ResponseEnumTemplate { + + // @formatter:off + MENU_NAME_EXISTS(1001, "Menu路由名称已存在"), + DEVICE_OFFLINE(1002, "设备为离线状态无法刷新"), + DEVICE_ADD_PROXY_FAIL(1003, "添加拉流代理失败"), + DEVICE_PTZ_CONTROL_FAIL(1004, "设备PTZ控制失败"), + CHANNEL_PRESET_FAIL(1005, "当前预置位被设置为守望位,请先关闭或者修改守望位"), + OPERATION_FAIL(1006, "操作失败"); + + ; + // @formatter:on + + /** + * 返回码 + */ + private final int code; + + /** + * 返回消息 + */ + private final String message; + + AdminResponseEnum(int code, String message) { + this.code = code; + this.message = message; + } + + @Override + public int getCode() { + return this.code; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public ErrorPrefixEnum getCodePrefixEnum() { + return ErrorPrefixEnum.ADMIN; + } +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/enums/DynamicDictEnum.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/enums/DynamicDictEnum.java new file mode 100644 index 0000000..3cc4594 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/enums/DynamicDictEnum.java @@ -0,0 +1,30 @@ +package com.sz.platform.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * 动态字典枚举类(可选工具类,非强依赖) + * + * DynamicDictEnum + * + * @author sz + * @since 2024/8/22 10:11 + * @version 1.0 + */ + +@Getter +@RequiredArgsConstructor +public enum DynamicDictEnum { + + // @formatter:off + DYNAMIC_USER_OPTIONS("user_options", "用户信息"), + DYNAMIC_DEPT_OPTIONS("dept_options", "部门信息"), + DYNAMIC_ROLE_OPTIONS("role_options", "角色信息") + ; + // @formatter:on + private final String typeCode; // 类型代码 + + private final String name; // 名称 + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/GlobalEventListener.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/GlobalEventListener.java new file mode 100644 index 0000000..bbcb09a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/GlobalEventListener.java @@ -0,0 +1,36 @@ +package com.sz.platform.event; + +import com.sz.admin.system.service.SysUserService; +import com.sz.core.util.JsonUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * EventListener 事件监听器 + * + * @author sz + * @since 2024/2/29 16:27 + * @version 1.0 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class GlobalEventListener { + + private final SysUserService sysUserService; + + @EventListener + public void handlePermissionChangeEvent(PermissionChangeEvent event) { + PermissionMeta permissionMeta = event.getPayload(); + log.warn("[事件监听]-权限变更, data: {}", JsonUtils.toJsonString(permissionMeta)); + List userIds = permissionMeta.getUserIds(); + for (Object userId : userIds) { + sysUserService.syncUserInfo(userId); + } + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/PermissionChangeEvent.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/PermissionChangeEvent.java new file mode 100644 index 0000000..27f2da8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/PermissionChangeEvent.java @@ -0,0 +1,17 @@ +package com.sz.platform.event; + +import com.sz.core.common.event.BaseEvent; + +/** + * 权限变更事件(用户角色变更、角色权限变更) + * + * @author sz + * @since 2024/2/29 15:44 + * @version 1.0 + */ +public class PermissionChangeEvent extends BaseEvent { + + public PermissionChangeEvent(Object source, PermissionMeta payload) { + super(source, payload); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/PermissionMeta.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/PermissionMeta.java new file mode 100644 index 0000000..529a2b6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/event/PermissionMeta.java @@ -0,0 +1,27 @@ +package com.sz.platform.event; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * PermissionChangeMeta + * + * @author sz + * @since 2024/2/29 15:44 + * @version 1.0 + */ +@Data +public class PermissionMeta { + + public PermissionMeta() { + } + + public PermissionMeta(List userIds) { + this.userIds = userIds; + } + + private List userIds = new ArrayList<>(); + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/handler/PermissionChangeHandler.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/handler/PermissionChangeHandler.java new file mode 100644 index 0000000..1061f38 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/handler/PermissionChangeHandler.java @@ -0,0 +1,18 @@ +package com.sz.platform.handler; + +import com.sz.core.common.entity.UserPermissionChangeMessage; +import com.sz.core.util.JsonUtils; +import com.sz.redis.handler.UserPermissionChangeMsgHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class PermissionChangeHandler implements UserPermissionChangeMsgHandler { + + @Override + public void handlerMsg(UserPermissionChangeMessage message) { + log.info(" [signal] message = {}", JsonUtils.toJsonString(message)); + // [do something ...] 同步更新变更用户的权限信息 + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/handler/WebsocketMessageHandler.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/handler/WebsocketMessageHandler.java new file mode 100644 index 0000000..31bef9b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/handler/WebsocketMessageHandler.java @@ -0,0 +1,19 @@ +package com.sz.platform.handler; + +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.util.JsonUtils; +import com.sz.redis.handler.WsToServiceMsgHandler; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class WebsocketMessageHandler implements WsToServiceMsgHandler { + + @Override + public void handlerMsg(TransferMessage transferMessage) { + // [do something ...] 在业务层接收透传过来的 websocket信息,进行业务处理 + log.info(" [WsToService] transferMessage = {}", JsonUtils.toJsonString(transferMessage)); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/AppStartListener.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/AppStartListener.java new file mode 100644 index 0000000..093f154 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/AppStartListener.java @@ -0,0 +1,33 @@ +package com.sz.platform.listener; + +import com.sz.redis.RedisTemplateClient; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.annotation.Order; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +/** + * @author sz + * @since 2022/9/9 16:21 + * + */ +@Slf4j +@Component +@Order(value = 1) +@RequiredArgsConstructor +public class AppStartListener implements CommandLineRunner, RedisTemplateClient { + + private final RedisTemplate redisTemplate; + + @Override + public void run(String... args) throws Exception { + log.info(" ===================== app is running finish ... ====================="); + } + + @Override + public RedisTemplate getTemplate() { + return redisTemplate; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysConfigListener.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysConfigListener.java new file mode 100644 index 0000000..3632116 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysConfigListener.java @@ -0,0 +1,36 @@ +package com.sz.platform.listener; + +import com.sz.admin.system.pojo.po.SysConfig; +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.mysql.EntityChangeListener; +import com.sz.redis.RedisCache; +import com.sz.socket.SocketService; + +public class TableSysConfigListener extends EntityChangeListener { + + @Override + public void onInsert(Object o) { + super.onInsert(o); + onChange(o); + } + + @Override + public void onUpdate(Object o) { + super.onUpdate(o); + onChange(o); + } + + private void onChange(Object o) { + SysConfig sysConfig = (SysConfig) o; + RedisCache cache = SpringApplicationContextUtils.getInstance().getBean(RedisCache.class); + if (("T").equals(sysConfig.getFrontendVisible())) { + cache.putFrontendConfig(sysConfig.getConfigKey(), sysConfig.getConfigValue()); + } else { + cache.deleteFrontendConfig(sysConfig.getConfigKey()); + } + // socket 推送,参数更新事件 + SocketService service = SpringApplicationContextUtils.getInstance().getBean(SocketService.class); + service.syncFrontendConfig(); + } + +} \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysDeptListener.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysDeptListener.java new file mode 100644 index 0000000..37d0646 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysDeptListener.java @@ -0,0 +1,45 @@ +package com.sz.platform.listener; + +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.mysql.EntityChangeListener; +import com.sz.redis.RedisCache; + +import static com.sz.core.common.constant.GlobalConstant.DYNAMIC_DICT_PREFIX; +import static com.sz.platform.enums.DynamicDictEnum.DYNAMIC_DEPT_OPTIONS; + +/** + * sys_dept表的监听器 + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/29 + */ +public class TableSysDeptListener extends EntityChangeListener { + + @Override + public void onInsert(Object o) { + super.onInsert(o); + onChange(o); + } + + @Override + public void onUpdate(Object o) { + super.onUpdate(o); + onChange(o); + } + + /** + * 触发change事件 + * + * @param o + * 对象 + */ + private void onChange(Object o) { + RedisCache cache = SpringApplicationContextUtils.getInstance().getBean(RedisCache.class); + cache.clearDict(DYNAMIC_DICT_PREFIX + DYNAMIC_DEPT_OPTIONS.getTypeCode()); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysRoleListener.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysRoleListener.java new file mode 100644 index 0000000..b16c566 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysRoleListener.java @@ -0,0 +1,45 @@ +package com.sz.platform.listener; + +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.mysql.EntityChangeListener; +import com.sz.redis.RedisCache; + +import static com.sz.core.common.constant.GlobalConstant.DYNAMIC_DICT_PREFIX; +import static com.sz.platform.enums.DynamicDictEnum.DYNAMIC_ROLE_OPTIONS; + +/** + * sys_role表的监听器 + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/29 + */ +public class TableSysRoleListener extends EntityChangeListener { + + @Override + public void onInsert(Object o) { + super.onInsert(o); + onChange(o); + } + + @Override + public void onUpdate(Object o) { + super.onUpdate(o); + onChange(o); + } + + /** + * 触发change事件 + * + * @param o + * 对象 + */ + private void onChange(Object o) { + RedisCache cache = SpringApplicationContextUtils.getInstance().getBean(RedisCache.class); + cache.clearDict(DYNAMIC_DICT_PREFIX + DYNAMIC_ROLE_OPTIONS.getTypeCode()); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysUserListener.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysUserListener.java new file mode 100644 index 0000000..36a1160 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/listener/TableSysUserListener.java @@ -0,0 +1,43 @@ +package com.sz.platform.listener; + +import com.sz.core.util.SpringApplicationContextUtils; +import com.sz.mysql.EntityChangeListener; +import com.sz.redis.RedisCache; + +import static com.sz.core.common.constant.GlobalConstant.DYNAMIC_DICT_PREFIX; +import static com.sz.platform.enums.DynamicDictEnum.DYNAMIC_USER_OPTIONS; + +/** + * sys_user表监听器 + * + * TableUserChangeListener + * + * @author sz + * @since 2024/8/22 10:00 + * @version 1.0 + */ +public class TableSysUserListener extends EntityChangeListener { + + @Override + public void onInsert(Object o) { + super.onInsert(o); + onChange(o); + } + + @Override + public void onUpdate(Object o) { + super.onUpdate(o); + onChange(o); + } + + /** + * 触发change事件 + * + * @param o + * 对象 + */ + private void onChange(Object o) { + RedisCache cache = SpringApplicationContextUtils.getInstance().getBean(RedisCache.class); + cache.clearDict(DYNAMIC_DICT_PREFIX + DYNAMIC_USER_OPTIONS.getTypeCode()); + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/DefaultStaticDictLoader.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/DefaultStaticDictLoader.java new file mode 100644 index 0000000..d30ab39 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/DefaultStaticDictLoader.java @@ -0,0 +1,63 @@ +package com.sz.platform.loader; + +import com.sz.admin.system.mapper.SysDictMapper; +import com.sz.core.common.dict.DictLoader; +import com.sz.core.common.entity.DictVO; +import com.sz.redis.RedisCache; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 静态字典loader + * + * StaticDictLoader + * + * @author sz + * @since 2024/8/21 9:06 + * @version 1.0 + */ +@Component +@RequiredArgsConstructor +public class DefaultStaticDictLoader implements DictLoader { + + private final RedisCache redisCache; + + private final SysDictMapper sysDictMapper; + + @Override + public Map> loadDict() { + if (redisCache.hasKey()) { + return redisCache.getAllDict(); + } + + // 查询所有字典 + List dictVOS = sysDictMapper.listDict(""); + if (dictVOS.isEmpty()) { + return Map.of(); + } + Map> result = dictVOS.stream().collect(Collectors.groupingBy(DictVO::getSysDictTypeCode, LinkedHashMap::new, // 使用 LinkedHashMap + // 作为分组的容器,有序解决乱序问题 + Collectors.toList())); + redisCache.putAllDict(result); + return result; + } + + @Override + public List getDict(String typeCode) { + if (redisCache.hasHashKey(typeCode)) { + return redisCache.getDictByType(typeCode); + } + + List list = sysDictMapper.listDict(typeCode); + if (list.isEmpty()) { + return List.of(); + } + redisCache.setDict(typeCode, list); + return list; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/DeptOptionDictLoader.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/DeptOptionDictLoader.java new file mode 100644 index 0000000..daa111c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/DeptOptionDictLoader.java @@ -0,0 +1,66 @@ +package com.sz.platform.loader.dynamic; + +import com.sz.admin.system.pojo.vo.sysdept.DeptOptionsVO; +import com.sz.admin.system.service.SysDeptService; +import com.sz.core.common.dict.DynamicDictLoader; +import com.sz.core.common.entity.DictVO; +import com.sz.platform.enums.DynamicDictEnum; +import com.sz.redis.RedisCache; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 动态字典——部门loader + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/28 + */ +@Component +@RequiredArgsConstructor +public class DeptOptionDictLoader implements DynamicDictLoader { + + private final RedisCache redisCache; + + private final SysDeptService sysDeptService; + + @Override + public String getTypeCode() { + return DynamicDictEnum.DYNAMIC_DEPT_OPTIONS.getTypeCode(); + } + + @Override + public String getTypeName() { + return DynamicDictEnum.DYNAMIC_DEPT_OPTIONS.getName(); + } + + @Override + public Map> loadDict() { + String key = getDynamicTypeCode(); + String name = getTypeName(); + + if (redisCache.hasHashKey(key)) { + return Map.of(key, redisCache.getDictByType(key)); + } + + DictVO dictVO; + List list = new ArrayList<>(); + List deptOptions = sysDeptService.getDeptOptions(); + for (int i = 0; i < deptOptions.size(); i++) { + DeptOptionsVO option = deptOptions.get(i); + dictVO = DictVO.builder().id(option.getId().toString()).codeName(option.getName()).alias("").sort(i + 1).sysDictTypeCode(key).sysDictTypeName(name) + .callbackShowStyle("info").isDynamic(true).isLock("F").isShow("T").build(); + list.add(dictVO); + } + redisCache.setDict(key, list); + return Map.of(key, list); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/RoleOptionDictLoader.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/RoleOptionDictLoader.java new file mode 100644 index 0000000..5f23a9b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/RoleOptionDictLoader.java @@ -0,0 +1,66 @@ +package com.sz.platform.loader.dynamic; + +import com.sz.admin.system.pojo.vo.sysrole.RoleOptionsVO; +import com.sz.admin.system.service.SysRoleService; +import com.sz.core.common.dict.DynamicDictLoader; +import com.sz.core.common.entity.DictVO; +import com.sz.platform.enums.DynamicDictEnum; +import com.sz.redis.RedisCache; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 动态字典——角色loader + *

+ * 详细描述类的功能或用途(可选)。 + *

+ * + * @author sz + * @version 1.0 + * @since 2025/7/28 + */ +@Component +@RequiredArgsConstructor +public class RoleOptionDictLoader implements DynamicDictLoader { + + private final RedisCache redisCache; + + private final SysRoleService sysRoleService; + + @Override + public String getTypeCode() { + return DynamicDictEnum.DYNAMIC_ROLE_OPTIONS.getTypeCode(); + } + + @Override + public String getTypeName() { + return DynamicDictEnum.DYNAMIC_ROLE_OPTIONS.getName(); + } + + @Override + public Map> loadDict() { + String key = getDynamicTypeCode(); + String name = getTypeName(); + + if (redisCache.hasHashKey(key)) { + return Map.of(key, redisCache.getDictByType(key)); + } + + DictVO dictVO; + List list = new ArrayList<>(); + List roleOptions = sysRoleService.getRoleOptions(); + for (int i = 0; i < roleOptions.size(); i++) { + RoleOptionsVO option = roleOptions.get(i); + dictVO = DictVO.builder().id(option.getId().toString()).codeName(option.getRoleName()).alias(option.getPermissions()).sort(i + 1) + .sysDictTypeCode(key).sysDictTypeName(name).callbackShowStyle("info").isDynamic(true).isLock("F").isShow("T").build(); + list.add(dictVO); + } + redisCache.setDict(key, list); + return Map.of(key, list); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/UserOptionDictLoader.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/UserOptionDictLoader.java new file mode 100644 index 0000000..cc5e6a3 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/loader/dynamic/UserOptionDictLoader.java @@ -0,0 +1,69 @@ +package com.sz.platform.loader.dynamic; + +import com.sz.admin.system.pojo.vo.sysuser.UserOptionVO; +import com.sz.admin.system.service.SysUserService; +import com.sz.core.common.entity.DictVO; +import com.sz.platform.enums.DynamicDictEnum; +import com.sz.core.common.dict.DynamicDictLoader; +import com.sz.redis.RedisCache; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 动态字典——系统用户loader + * + * DynamicUserOptionDictLoader + * + * @author sz + * @since 2024/8/21 13:17 + * @version 1.0 + */ +@Component +@RequiredArgsConstructor +public class UserOptionDictLoader implements DynamicDictLoader { + + private final RedisCache redisCache; + + private final SysUserService sysUserService; + + @Override + public String getTypeCode() { + return DynamicDictEnum.DYNAMIC_USER_OPTIONS.getTypeCode(); + } + + @Override + public String getTypeName() { + return DynamicDictEnum.DYNAMIC_USER_OPTIONS.getName(); + } + + @Override + public Map> loadDict() { + String key = getDynamicTypeCode(); + String name = getTypeName(); + if (redisCache.hasHashKey(key)) { + return Map.of(key, redisCache.getDictByType(key)); + } + + DictVO dictVO; + List list = new ArrayList<>(); + List userOptions = sysUserService.getUserOptions(); + for (int i = 0; i < userOptions.size(); i++) { + UserOptionVO option = userOptions.get(i); + dictVO = DictVO.builder().id(option.getId().toString()).codeName(option.getNickname()).alias(option.getUsername()).sort(i + 1).sysDictTypeCode(key) + .sysDictTypeName(name).callbackShowStyle("primary").isDynamic(true).isLock("F").isShow("T").build(); + list.add(dictVO); + } + redisCache.setDict(key, list); + return Map.of(key, list); + } + + @Override + public List getDict(String typeCode) { + return loadDict().get(typeCode); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/AppletStrategy.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/AppletStrategy.java new file mode 100644 index 0000000..db2859e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/AppletStrategy.java @@ -0,0 +1,92 @@ +package com.sz.platform.strategy; + +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import com.sz.applet.miniuser.pojo.po.MiniLoginUser; +import com.sz.applet.miniuser.service.MiniUserService; +import com.sz.core.common.enums.CommonResponseEnum; +import com.sz.core.util.JsonUtils; +import com.sz.core.util.Utils; +import com.sz.security.core.util.LoginUtils; +import com.sz.security.pojo.ClientVO; +import com.sz.security.pojo.LoginInfo; +import com.sz.security.pojo.LoginVO; +import com.sz.security.service.IAuthStrategy; +import com.sz.wechat.mini.MiniWechatService; +import com.sz.wechat.mini.LoginInfoResult; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 小程序认证策略 + * + * AppletStrategy + * + * @author sz + * @since 2024/4/26 16:08 + * @version 1.0 + */ + +@Slf4j +@Service("applet" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class AppletStrategy implements IAuthStrategy { + + private final MiniWechatService miniWechatService; + + private final MiniUserService miniUserService; + + @Override + public LoginVO login(LoginInfo info, ClientVO client) { + String clientId = client.getClientId(); + String code = info.getCode(); + CommonResponseEnum.INVALID.message("无效的小程序code").assertFalse(Utils.isNotNull(code)); + + String accessToken = miniWechatService.getAccessToken(); + LoginInfoResult result = miniWechatService.miniLogin(code, accessToken); + log.info(" 小程序登录返回信息:{}", JsonUtils.toJsonString(result)); + String openid = result.getOpenid(); + String unionid = result.getUnionId(); + String sessionKey = result.getSessionKey(); // 小程序登录凭证 + + MiniLoginUser miniLoginUser = miniUserService.getUserByOpenId(openid, unionid); + + // 设置登录模型 + SaLoginParameter model = createLoginModel(client); + Long userId = miniLoginUser.getUserId(); + // 设置jwt额外数据 + Map extraData = createExtraData(clientId, userId); + // 执行登录 + LoginUtils.performMiniLogin(userId, miniLoginUser, model, extraData); + // 构造返回对象 + return createLoginVO(miniLoginUser); + } + + private SaLoginParameter createLoginModel(ClientVO client) { + SaLoginParameter model = new SaLoginParameter(); + model.setDeviceType(client.getDeviceTypeCd()); + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + return model; + } + + private Map createExtraData(String clientId, Long userId) { + Map extraData = new HashMap<>(); + extraData.put("clientId", clientId); + extraData.put("userId", userId); + return extraData; + } + + private LoginVO createLoginVO(MiniLoginUser miniLoginUser) { + LoginVO loginVo = new LoginVO(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setUserInfo(miniLoginUser); + return loginVo; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/EmailAuthStrategy.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/EmailAuthStrategy.java new file mode 100644 index 0000000..07bc9f4 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/EmailAuthStrategy.java @@ -0,0 +1,25 @@ +package com.sz.platform.strategy; + +import com.sz.security.pojo.ClientVO; +import com.sz.security.pojo.LoginInfo; +import com.sz.security.pojo.LoginVO; +import com.sz.security.service.IAuthStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * EmailAuthStrategy + * + * @author sz + * @since 2024/1/23 10:29 + * @version 1.0 + */ +@Slf4j +@Service("email" + IAuthStrategy.BASE_NAME) +public class EmailAuthStrategy implements IAuthStrategy { + + @Override + public LoginVO login(LoginInfo body, ClientVO client) { + return null; + } +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/PasswordStrategy.java b/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/PasswordStrategy.java new file mode 100644 index 0000000..9bfe1f0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/platform/strategy/PasswordStrategy.java @@ -0,0 +1,99 @@ +package com.sz.platform.strategy; + +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import com.sz.admin.system.service.SysLoginLogService; +import com.sz.admin.system.service.SysUserService; +import com.sz.core.common.entity.BaseUserInfo; +import com.sz.core.common.entity.LoginUser; +import com.sz.core.common.exception.common.BaseException; +import com.sz.core.util.AESUtil; +import com.sz.redis.RedisCache; +import com.sz.security.core.util.LoginUtils; +import com.sz.security.pojo.ClientVO; +import com.sz.security.pojo.LoginInfo; +import com.sz.security.pojo.LoginVO; +import com.sz.security.service.IAuthStrategy; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 密码认证策略 + *

+ * PasswordStrategy + * + * @author sz + * @version 1.0 + * @since 2024/1/23 10:29 + */ +@Slf4j +@Service("password" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class PasswordStrategy implements IAuthStrategy { + + private final SysUserService sysUserService; + + private final SysLoginLogService sysLoginLogService; + + private final RedisCache redisCache; + + @SneakyThrows + @Override + public LoginVO login(LoginInfo info, ClientVO client) { + LoginVO loginVO = new LoginVO(); + String username = info.getUsername(); + try { + String clientId = client.getClientId(); + String password = info.getPassword(); // 前端加密后的密码 + String secretKey = redisCache.getLoginSecret(info.getRequestId()); + String passwordReal = AESUtil.aesDecrypt(password, secretKey, info.getIv()); // 解密后的密码 + redisCache.clearLoginSecret(info.getRequestId()); // 清除临时密钥 + // 设置登录模型 + SaLoginParameter model = createLoginModel(client); + LoginUser loginUser = sysUserService.buildLoginUser(username, passwordReal); + Long userId = loginUser.getUserInfo().getId(); + // 设置jwt额外数据 + Map extraData = createExtraData(clientId, userId); + // 执行登录 + LoginUtils.performLogin(loginUser, model, extraData); + loginVO = createLoginVO(loginUser.getUserInfo()); + sysLoginLogService.recordLoginLog(info.getUsername(), "1009001", "登陆成功"); + } catch (BaseException e) { + sysLoginLogService.recordLoginLog(username, "1009002", e.getMessage()); + throw e; + } catch (Exception e) { + sysLoginLogService.recordLoginLog(username, "1009002", "系统异常:" + e.getMessage()); + throw e; + } + return loginVO; + } + + private SaLoginParameter createLoginModel(ClientVO client) { + SaLoginParameter model = new SaLoginParameter(); + model.setDeviceType(client.getDeviceTypeCd()); + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + return model; + } + + private Map createExtraData(String clientId, Long userId) { + Map extraData = new HashMap<>(); + extraData.put("clientId", clientId); + extraData.put("userId", userId); + return extraData; + } + + private LoginVO createLoginVO(BaseUserInfo userInfo) { + LoginVO loginVo = new LoginVO(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setUserInfo(userInfo); + return loginVo; + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/redis/RedisService.java b/sz-service/sz-service-admin/src/main/java/com/sz/redis/RedisService.java new file mode 100644 index 0000000..e9737db --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/redis/RedisService.java @@ -0,0 +1,28 @@ +package com.sz.redis; + +import com.sz.core.common.constant.GlobalConstant; +import com.sz.core.common.entity.UserPermissionChangeMessage; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +/** + * 业务级 redis service + */ +@Component +@RequiredArgsConstructor +public class RedisService { + + private final RedisTemplate redisTemplate; + + /** + * 发布Permission 变更消息 + * + * @param message + * 消息 + */ + public void sendPermissionChangeMsg(UserPermissionChangeMessage message) { + redisTemplate.convertAndSend(GlobalConstant.CHANGE_PERMISSIONS_SIGNAL, message); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/socket/SocketService.java b/sz-service/sz-service-admin/src/main/java/com/sz/socket/SocketService.java new file mode 100644 index 0000000..cb1d7a8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/socket/SocketService.java @@ -0,0 +1,104 @@ +package com.sz.socket; + +import com.sz.admin.system.pojo.dto.sysmessage.PayloadBody; +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.enums.MessageTransferScopeEnum; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.core.util.JsonUtils; +import com.sz.redis.WebsocketRedisService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class SocketService { + + private final WebsocketRedisService websocketRedisService; + + /** + * 同步前端配置 + */ + public void syncFrontendConfig() { + TransferMessage tm = new TransferMessage(); + tm.setToPushAll(true); + SocketMessage sb = new SocketMessage(); + sb.setChannel(SocketChannelEnum.SYNC_FRONTEND_CONF); + tm.setMessage(sb); + websocketRedisService.sendServiceToWs(tm); + } + + /** + * 同步字典数据 + */ + public void syncDict() { + TransferMessage tm = new TransferMessage(); + tm.setToPushAll(true); + SocketMessage sb = new SocketMessage(); + sb.setChannel(SocketChannelEnum.SYNC_DICT); + tm.setMessage(sb); + websocketRedisService.sendServiceToWs(tm); + } + + /** + * 同步权限数据 + * + * @param userId + * 用户id + */ + public void syncPermission(Object userId) { + TransferMessage tm = new TransferMessage(); + tm.setToPushAll(false); + tm.setToUsers(List.of(userId)); + SocketMessage sb = new SocketMessage(); + sb.setChannel(SocketChannelEnum.SYNC_PERMISSIONS); + tm.setMessage(sb); + websocketRedisService.sendServiceToWs(tm); + } + + /** + * 强制(指定用户)下线 + * + * @param userId + * 用户id + */ + public void kickOff(Object userId) { + TransferMessage tm = new TransferMessage(); + tm.setToUsers(Collections.singletonList(userId)); + SocketMessage sb = new SocketMessage(); + sb.setChannel(SocketChannelEnum.KICK_OFF); + tm.setMessage(sb); + websocketRedisService.sendServiceToWs(tm); + } + + /** + * 发送消息 + * + * @param body + * 消息体 + * @param senderId + * 发送者ID + * @param receiverIds + * 接收者ID列表 + */ + public void sendMessage(PayloadBody body, String senderId, List receiverIds) { + SocketMessage message = SocketMessage.builder().data(JsonUtils.toJsonString(body)).channel(SocketChannelEnum.MESSAGE) + .scope(MessageTransferScopeEnum.SOCKET_CLIENT).build(); + TransferMessage msg = TransferMessage.builder().message(message).fromUser(senderId).toPushAll(false).toUsers(receiverIds).build(); + websocketRedisService.sendServiceToWs(msg); + } + + public void readMessage(String fromUserId, List toUsers) { + SocketMessage message = SocketMessage.builder().data(null).channel(SocketChannelEnum.READ).scope(MessageTransferScopeEnum.SOCKET_CLIENT).build(); + TransferMessage msg = new TransferMessage(); + msg.setMessage(message); + msg.setFromUser(fromUserId); + msg.setToPushAll(false); + msg.setToUsers(toUsers); + websocketRedisService.sendServiceToWs(msg); + } + +} diff --git a/sz-service/sz-service-admin/src/main/java/com/sz/www/test/controller/TestController.java b/sz-service/sz-service-admin/src/main/java/com/sz/www/test/controller/TestController.java new file mode 100644 index 0000000..df9ba45 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/java/com/sz/www/test/controller/TestController.java @@ -0,0 +1,204 @@ +package com.sz.www.test.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.sz.admin.monitor.pojo.dto.edgebox.AlarmReportDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.AlgorithmTaskDTO; +import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto; +import com.sz.admin.monitor.pojo.dto.edgebox.SetupChannelDTO; +import com.sz.admin.monitor.utils.AiBoxRequestUtil; +import com.sz.admin.monitor.utils.AlgMediaConfigResponse; +import com.sz.admin.system.pojo.dto.sysmessage.Message; +import com.sz.admin.system.service.SysMessageService; +import com.sz.core.common.entity.ApiResult; +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.enums.MessageTransferScopeEnum; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.redis.WebsocketRedisService; +import com.sz.security.core.util.LoginUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * !!! 【以下为功能演示内容,生产环境请删除】 + * + * 网站测试 + * + * @author sz + * @since 2024/5/24 + * @version 1.0 + */ +@Tag(name = "测试网站") +@RestController +@RequestMapping("www") +@RequiredArgsConstructor +@Profile({"dev", "local", "preview"}) +public class TestController { + + private static final Logger log = LoggerFactory.getLogger(TestController.class); + private final WebsocketRedisService websocketRedisService; + + private final SysMessageService sysMessageService; + + private final AiBoxRequestUtil aiBoxRequestUtil; + + @PostMapping("/result") + @Operation(summary = "获取报警信息报告") + public ApiResult getResult(@RequestBody BoxAlarmReportDto boxAlarmReportDto) + { + log.info("获取到报警信息:{}", JSON.toJSONString(boxAlarmReportDto)); + return ApiResult.success(); + } + @PostMapping("push/all") + @Operation(summary = "全体推送-升级公告(socket)") + public ApiResult sendUpgradeMsg() { + SocketMessage bean = new SocketMessage(); + bean.setData("【全体推送】 系统即将进行升级,预计需要几分钟时间。请您稍等片刻,感谢您的耐心等待"); + bean.setChannel(SocketChannelEnum.UPGRADE_CHANNEL); + bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT); + TransferMessage msg = new TransferMessage(); + msg.setMessage(bean); + msg.setFromUser("system"); + msg.setToPushAll(true); + websocketRedisService.sendServiceToWs(msg); + return ApiResult.success(); + } + + @PostMapping("push/user") + @Operation(summary = "定向推送-升级公告(socket)") + public ApiResult sendMsg() { + SocketMessage bean = new SocketMessage(); + bean.setData("【定向推送】 系统即将进行升级,预计需要几分钟时间。请您稍等片刻,感谢您的耐心等待"); + bean.setChannel(SocketChannelEnum.UPGRADE_CHANNEL); + bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT); + + TransferMessage msg = new TransferMessage(); + msg.setMessage(bean); + msg.setFromUser("system"); + msg.setToPushAll(false); + List toUsers = new ArrayList<>(); + toUsers.add("1"); // 向 loginId = 1 的用户推送消息。既 admin 账号 + msg.setToUsers(toUsers); + websocketRedisService.sendServiceToWs(msg); + return ApiResult.success(); + } + + @Operation(summary = "测试socket踢下线") + @PostMapping("kick") + public ApiResult testKickOff() { + TransferMessage tm = new TransferMessage(); + tm.setToPushAll(true); + SocketMessage sb = new SocketMessage(); + sb.setChannel(SocketChannelEnum.KICK_OFF); + tm.setMessage(sb); + websocketRedisService.sendServiceToWs(tm); + return ApiResult.success(); + } + + @Operation(summary = "测试消息发送") + @GetMapping("message/send") + public ApiResult sendMessage() { + SocketMessage bean = new SocketMessage(); + Map alarmData = new HashMap<>(); + alarmData.put("title", "系统警告"); + alarmData.put("content", "通道66发生了移位,请注意查看!"); + bean.setData(JSON.toJSONString(alarmData)); + bean.setChannel(SocketChannelEnum.MESSAGE); + bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT); + TransferMessage msg = new TransferMessage(); + msg.setMessage(bean); + msg.setFromUser("system"); + msg.setToPushAll(true); + Message message = new Message(); + message.setMessageTypeCd("msg"); + message.setSenderId(1L); + message.setTitle("系统警告"); + message.setContent("通道66发生了移位,请注意查看!"); + // 获取登录用户 + // LoginUser loginUser = LoginUtils.getLoginUser(); + System.out.println(LoginUtils.getLoginUser().getUserInfo()); + message.setReceiverIds(List.of(1)); + sysMessageService.create(message); + // websocketRedisService.sendServiceToWs(msg); + return ApiResult.success(); + } + + @Operation(summary = "测试盒子配置通道功能") + @GetMapping("/test") + public ApiResult test() { + SetupChannelDTO setupChannelDTO = new SetupChannelDTO(); + setupChannelDTO.setMediaUrl("rtsp://admin:rytec.2020@192.168.2.110:554/Streaming/Channels/901"); + setupChannelDTO.setMediaDesc("机柜球机"); + setupChannelDTO.setMediaName("机柜球机"); + // aiBoxRequestUtil.setupVideoChannel(setupChannelDTO); + return ApiResult.success(); + } + + @Operation(summary = "测试盒子配置任务功能") + @GetMapping("/test1") + public ApiResult test1() { + AlgorithmTaskDTO algTaskConfigDto = new AlgorithmTaskDTO(); + algTaskConfigDto.setAlgInfo(List.of(8, 52)); + algTaskConfigDto.setMediaName("机柜球机"); + algTaskConfigDto.setTaskDesc("机柜球机"); + algTaskConfigDto.setAlgTaskSession("55"); + AlgorithmTaskDTO.UserDataDto userData = new AlgorithmTaskDTO.UserDataDto(); + userData.setMethodConfig(List.of(46,207)); + userData.setEnableFireSmokeFilter(true); +// 可以有,也可以不需要,有默认值 + userData.setFireThreshold(0.6); + userData.setSmokeThreshold(0.6); + userData.setFireSmokeKeepSec(3); + userData.setFireSmokeAlarmIntervalSec(10); + userData.setFaceRegSimilarity(0.45); + userData.setFaceRegEnableGat1400(false); + userData.setFaceRegEnableMultiCheck(false); + userData.setFaceLowSimilarity(0d); + userData.setFaceIdUploadIntervalMs(0); + userData.setFrontFaceMinPixel(30); + userData.setFaceRepositories(1); + userData.setEnableFireDeepMode(false); + userData.setThresholdForFace(0.5); + algTaskConfigDto.setUserData(userData); + return null; + } + @Operation(summary = "测试盒子开启关闭任务功能") + @GetMapping("/test2") + public ApiResult tes2() { + //aiBoxRequestUtil.controlTask("55",0) + return ApiResult.success(); + } + @Operation(summary = "测试盒子删除任务功能") + @GetMapping("/test3") + public ApiResult tes3() { + //aiBoxRequestUtil.deleteTask("55") + return ApiResult.success(); + } + @Operation(summary = "测试盒子删除通道功能") + @GetMapping("/test4") + public ApiResult tes4() { + //aiBoxRequestUtil.deleteVideoChannel("机柜球机") + return ApiResult.success(); + } + @Operation(summary = "接收报警信息") + @PostMapping("/shou") + public void recevice(@RequestBody AlarmReportDTO alarmReportDto) + { + log.info("接收到报警信息:{}",alarmReportDto); + } + +} diff --git a/sz-service/sz-service-admin/src/main/resources/application-dev.yml b/sz-service/sz-service-admin/src/main/resources/application-dev.yml new file mode 100644 index 0000000..95c243e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/application-dev.yml @@ -0,0 +1,4 @@ +server: + servlet: + context-path: /api/admin + port: 9991 \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/application-local.yml b/sz-service/sz-service-admin/src/main/resources/application-local.yml new file mode 100644 index 0000000..ef5b8d7 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/application-local.yml @@ -0,0 +1,4 @@ +server: + servlet: + context-path: /api/admin + port: 9991 diff --git a/sz-service/sz-service-admin/src/main/resources/application-preview.yml b/sz-service/sz-service-admin/src/main/resources/application-preview.yml new file mode 100644 index 0000000..2170316 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/application-preview.yml @@ -0,0 +1,9 @@ +server: + servlet: + context-path: /api/admin + port: 9991 +sz: + cors: + allowed-origins: + - "https://preview.szadmin.cn" + - "https://*.szadmin.cn" \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/application-prod.yml b/sz-service/sz-service-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..ada910f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/application-prod.yml @@ -0,0 +1,9 @@ +server: + servlet: + context-path: /api/admin + port: 9991 +# 为了提高安全性,生产环境不建议使用*,需修改成指定的域名 +#sz: +# cors: +# allowed-origins: +# - "https://your_domain.com" \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/application.yml b/sz-service/sz-service-admin/src/main/resources/application.yml new file mode 100644 index 0000000..7d8129a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/application.yml @@ -0,0 +1,77 @@ +spring: + threads: + virtual: + # 启用虚拟线程 + enabled: true + profiles: + active: local + config: + import: + - file:config/${spring.profiles.active}/knife4j.yml + - file:config/${spring.profiles.active}/oss.yml + - file:config/${spring.profiles.active}/mybatis-flex.yml + - file:config/${spring.profiles.active}/mysql.yml + - file:config/${spring.profiles.active}/page-helper.yml + - file:config/${spring.profiles.active}/redis.yml + - file:config/${spring.profiles.active}/sa-token.yml + - file:config/${spring.profiles.active}/zlmediakit.yml + - file:config/${spring.profiles.active}/edgeBox.yml + mvc: + path-match: + matching-strategy: ant_path_matcher + application: + name: admin-service + servlet: + multipart: + max-file-size: 10MB + max-request-size: 15MB +app: + version: @project.version@ +sz: + # 是否启用数据权限拼接 + data-scope: + enabled: true + # 数据逻辑实现最小验证(查询)单位:dept 部门(dept_scope字段)、user 用户 (create_id 字段),默认user。 + logic-min-unit: user + debounce: + # 是否启用防抖功能 + enabled: true + # 全局防抖时间,单位毫秒(默认1000ms) + global-lock-time: 500 + # 是否忽略GET请求 + ignore-get-method: true + # 生成工具 + generator: + path: + # 前端项目地址 + web: D:/work/sz-admin + # 后端项目地址,默认自动检测springboot项目路径,无需配置。 + api: E:/code/Gitlab/sz-framework/sz-admin + # 模块名,指定代码生成的模块 + module-name: sz-service + service-name: sz-service-admin + global: + author: Lz + packages: com.sz.admin + ignore-table-prefix: + enabled: true + prefixes: + - t_ + # 微信生态 + wechat: + # 小程序 + mini: + app-id: your_app_id + app-secret: your_app_secret + cors: + # 定义允许跨域请求的源(Origin)。可以设置为特定的域名、IP 地址或通配符。 + allowed-origins: + - "*" +management: + endpoints: + web: + exposure: + include: "health,info" + endpoint: + health: + show-details: "never" \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.0.0/000_demo.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.0.0/000_demo.sql new file mode 100644 index 0000000..aca622b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.0.0/000_demo.sql @@ -0,0 +1,52 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250425_0924 +-- 以下为演示环境脚本,-- 仅供演示使用,实际业务请删除 +CREATE TABLE IF NOT EXISTS `teacher_statistics` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `year` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '统计年限', + `month` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '统计月份', + `during_time` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '统计年月', + `teacher_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '教师id', + `teacher_common_type` int NOT NULL COMMENT '讲师区分类型', + `total_teaching` int NULL DEFAULT NULL COMMENT '授课总数', + `total_class_count` int NULL DEFAULT NULL COMMENT '服务班次数', + `total_hours` decimal(10, 2) NULL DEFAULT NULL COMMENT '课时总数', + `check_status` int NOT NULL DEFAULT 0 COMMENT '核对状态', + `check_time` datetime NULL DEFAULT NULL COMMENT '核对时间', + `create_time` datetime NULL DEFAULT NULL COMMENT '生成时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `last_sync_time` datetime NULL DEFAULT NULL COMMENT '最近一次同步时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `dept_scope` json NULL COMMENT '部门范围', + PRIMARY KEY (`id`) USING BTREE + ) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '教师统计总览表' ROW_FORMAT = DYNAMIC; + +INSERT IGNORE INTO `teacher_statistics` (`id`, `year`, `month`, `during_time`, `teacher_id`, `teacher_common_type`, `total_teaching`, `total_class_count`, `total_hours`, `check_status`, `check_time`, `create_time`, `update_time`, `last_sync_time`, `remark`, `create_id`, `update_id`, `dept_scope`) VALUES (22, '2018', '12', '03', '1503', 1000001, 12, 22, 15.00, 1000001, '2024-07-08 10:39:56', '2024-07-08 10:40:16', NULL, '2024-07-08 10:39:57', 'test1 创建记录', 3, NULL, '[4]'); +INSERT IGNORE INTO `teacher_statistics` (`id`, `year`, `month`, `during_time`, `teacher_id`, `teacher_common_type`, `total_teaching`, `total_class_count`, `total_hours`, `check_status`, `check_time`, `create_time`, `update_time`, `last_sync_time`, `remark`, `create_id`, `update_id`, `dept_scope`) VALUES (23, '2019', '12', '03', '111', 1000001, 1, 2, 3.00, 1000001, '2024-07-08 10:41:09', '2024-07-08 10:41:18', NULL, '2024-07-08 10:41:11', 'test1 创建记录', 3, NULL, '[4]'); +INSERT IGNORE INTO `teacher_statistics` (`id`, `year`, `month`, `during_time`, `teacher_id`, `teacher_common_type`, `total_teaching`, `total_class_count`, `total_hours`, `check_status`, `check_time`, `create_time`, `update_time`, `last_sync_time`, `remark`, `create_id`, `update_id`, `dept_scope`) VALUES (24, '2020', '12', '2020-12', '023', 1000001, 1, 1, 1.00, 1000001, '2024-07-08 13:06:55', '2024-07-08 13:07:07', NULL, '2024-07-08 13:06:57', 'test1 创建记录', 3, NULL, '[4]'); +INSERT IGNORE INTO `teacher_statistics` (`id`, `year`, `month`, `during_time`, `teacher_id`, `teacher_common_type`, `total_teaching`, `total_class_count`, `total_hours`, `check_status`, `check_time`, `create_time`, `update_time`, `last_sync_time`, `remark`, `create_id`, `update_id`, `dept_scope`) VALUES (25, '2021', '12', '2021-12', '123', 1000001, 1, 1, 1.00, 1000001, '2024-07-08 13:13:56', '2024-07-08 13:13:59', NULL, NULL, 'test2 创建记录', 4, NULL, '[15]'); +INSERT IGNORE INTO `teacher_statistics` (`id`, `year`, `month`, `during_time`, `teacher_id`, `teacher_common_type`, `total_teaching`, `total_class_count`, `total_hours`, `check_status`, `check_time`, `create_time`, `update_time`, `last_sync_time`, `remark`, `create_id`, `update_id`, `dept_scope`) VALUES (26, '2022', '12', '2022-12', '13123', 1000001, 1, 1, 1.00, 1000001, '2024-07-08 13:15:36', '2024-07-08 13:15:37', '2024-07-08 13:15:46', NULL, 'test3 创建记录', 5, 5, '[15]'); +INSERT IGNORE INTO `teacher_statistics` (`id`, `year`, `month`, `during_time`, `teacher_id`, `teacher_common_type`, `total_teaching`, `total_class_count`, `total_hours`, `check_status`, `check_time`, `create_time`, `update_time`, `last_sync_time`, `remark`, `create_id`, `update_id`, `dept_scope`) VALUES (27, '2099', '12', '12', '123123', 1000001, 1, 1, 1.00, 1000001, NULL, '2024-07-08 13:20:29', NULL, NULL, '管理员创建', 1, NULL, '[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]'); + +INSERT IGNORE INTO `generator_table` (`table_id`, `table_name`, `table_comment`, `class_name`, `camel_class_name`, `tpl_category`, `package_name`, `module_name`, `business_name`, `function_name`, `function_author`, `type`, `options`, `parent_menu_id`, `path`, `path_api`, `path_web`, `menu_init_type`, `btn_permission_type`, `has_import`, `has_export`, `generate_type`, `create_id`, `update_id`, `create_time`, `update_time`, `is_autofill`) VALUES (1, 'teacher_statistics', '教师统计总览表', 'TeacherStatistics', 'teacherStatistics', 'crud', 'com.sz.admin', 'teacherstatistics', 'teacherStatistics', '教师统计总览表', 'sz-admin', '0', NULL, '0', '/', 'E:\\dev\\Code\\Github\\sz-boot-parent\\sz-service\\sz-service-admin', '', '1', '1', '1', '1', 'all', 1, NULL, '2024-05-10 21:45:32', NULL, '1'); + +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (1, 1, 'id', 'id', 'int', 'Long', 'input', 'number', NULL, 'id', 'Id', '1', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 1, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (2, 1, 'year', '统计年限', 'varchar(4)', 'String', 'input', 'string', NULL, 'year', 'Year', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 2, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (3, 1, 'month', '统计月份', 'varchar(2)', 'String', 'input', 'string', NULL, 'month', 'Month', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 3, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (4, 1, 'during_time', '统计年月', 'varchar(10)', 'String', 'date-picker', 'string', NULL, 'duringTime', 'DuringTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 4, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (5, 1, 'teacher_id', '教师id', 'varchar(32)', 'String', 'input', 'string', NULL, 'teacherId', 'TeacherId', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 5, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (6, 1, 'teacher_common_type', '讲师区分类型', 'int', 'Integer', 'select', 'number', NULL, 'teacherCommonType', 'TeacherCommonType', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'select', '', '0', NULL, 6, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (7, 1, 'total_teaching', '授课总数', 'int', 'Integer', 'input', 'number', NULL, 'totalTeaching', 'TotalTeaching', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 7, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (8, 1, 'total_class_count', '服务班次数', 'int', 'Integer', 'input', 'number', NULL, 'totalClassCount', 'TotalClassCount', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 8, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (9, 1, 'total_hours', '课时总数', 'decimal(10,2)', 'BigDecimal', 'input', 'number', 'java.math.BigDecimal', 'totalHours', 'TotalHours', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 9, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (10, 1, 'check_status', '核对状态', 'int', 'Integer', 'select', 'number', NULL, 'checkStatus', 'CheckStatus', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'radio', '', '0', NULL, 10, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (11, 1, 'check_time', '核对时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'checkTime', 'CheckTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'datetime', '', '0', NULL, 11, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (12, 1, 'create_time', '生成时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'createTime', 'CreateTime', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', 'FieldFill.INSERT', 'EQ', 'datetime', '', '0', NULL, 12, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (13, 1, 'update_time', '更新时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'updateTime', 'UpdateTime', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', 'FieldFill.UPDATE', 'EQ', 'datetime', '', '0', NULL, 13, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (14, 1, 'last_sync_time', '最近一次同步时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'lastSyncTime', 'LastSyncTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'datetime', '', '0', NULL, 14, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (15, 1, 'remark', '备注', 'varchar(255)', 'String', 'input', 'string', NULL, 'remark', 'Remark', '0', '0', '0', '1', '1', '1', '0', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 15, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); + + diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.0.0/001_demo.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.0.0/001_demo.sql new file mode 100644 index 0000000..1532271 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.0.0/001_demo.sql @@ -0,0 +1,31 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250526_1636 +-- 以下为演示环境脚本,-- 仅供演示使用,实际业务请删除 +UPDATE `sys_menu` SET `use_data_scope` = 'T' WHERE `id` = '85b54322630f43a39296488a5e76ba16'; +DELETE FROM `generator_table` WHERE `table_id` = 1; +DELETE FROM `generator_table_column` WHERE `table_id` = 1; +ALTER TABLE `teacher_statistics` + MODIFY COLUMN `create_time` datetime DEFAULT NULL COMMENT '生成时间' AFTER `create_id`, + MODIFY COLUMN `update_time` datetime DEFAULT NULL COMMENT '更新时间' AFTER `update_id`; + +INSERT INTO `generator_table` (`table_id`, `table_name`, `table_comment`, `class_name`, `camel_class_name`, `tpl_category`, `package_name`, `module_name`, `business_name`, `function_name`, `function_author`, `type`, `options`, `parent_menu_id`, `path`, `path_api`, `path_web`, `menu_init_type`, `btn_permission_type`, `has_import`, `has_export`, `generate_type`, `create_id`, `update_id`, `create_time`, `update_time`, `is_autofill`) VALUES (1, 'teacher_statistics', '教师统计总览表', 'TeacherStatistics', 'teacherStatistics', 'crud', 'com.sz.admin', 'teacher', 'teacherStatistics', '教师统计总览表', 'sz-admin', '0', '', '0', '/', 'E:\\code\\Github\\sz\\sz-boot-parent\\sz-service\\sz-service-admin', '', '1', '1', '1', '1', 'all', 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '1'); + +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (16, 1, 'id', 'ID', 'bigint', 'Long', 'input', 'number', '', 'id', 'Id', '1', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '', 'EQ', 'input-number', '', '0', '', 1, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (17, 1, 'year', '统计年限', 'varchar(4)', 'String', 'input', 'string', '', 'year', 'Year', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '', 2, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (18, 1, 'month', '统计月份', 'varchar(2)', 'String', 'input', 'string', '', 'month', 'Month', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '', 3, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (19, 1, 'during_time', '统计年月', 'varchar(10)', 'String', 'date-picker', 'string', '', 'duringTime', 'DuringTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '', 4, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (20, 1, 'teacher_id', '教师id', 'varchar(32)', 'String', 'input', 'string', '', 'teacherId', 'TeacherId', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '', 5, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (21, 1, 'teacher_common_type', '讲师区分类型', 'int', 'Integer', 'select', 'number', '', 'teacherCommonType', 'TeacherCommonType', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'select', '', '0', '', 6, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (22, 1, 'total_teaching', '授课总数', 'int', 'Integer', 'input', 'number', '', 'totalTeaching', 'TotalTeaching', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input-number', '', '0', '', 7, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (23, 1, 'total_class_count', '服务班次数', 'int', 'Integer', 'input', 'number', '', 'totalClassCount', 'TotalClassCount', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input-number', '', '0', '', 8, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (24, 1, 'total_hours', '课时总数', 'decimal(10,2)', 'BigDecimal', 'input', 'number', 'java.math.BigDecimal', 'totalHours', 'TotalHours', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input-number', '', '0', '', 9, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (25, 1, 'check_status', '核对状态', 'int', 'Integer', 'select', 'number', '', 'checkStatus', 'CheckStatus', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'radio', '', '0', '', 10, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (26, 1, 'check_time', '核对时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'checkTime', 'CheckTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'BETWEEN', 'datetime', '', '0', '', 11, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (27, 1, 'last_sync_time', '最近一次同步时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'lastSyncTime', 'LastSyncTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'BETWEEN', 'datetime', '', '0', '', 12, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (28, 1, 'remark', '备注', 'varchar(255)', 'String', 'input', 'string', '', 'remark', 'Remark', '0', '0', '0', '1', '1', '1', '0', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '', 13, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (29, 1, 'create_id', '创建人ID', 'bigint', 'Long', 'input', 'number', '', 'createId', 'CreateId', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.INSERT', 'EQ', 'input-number', 'dynamic_user_options', '0', '', 14, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (30, 1, 'create_time', '生成时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'createTime', 'CreateTime', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.INSERT', 'BETWEEN', 'datetime', '', '0', '', 15, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (31, 1, 'update_id', '更新人ID', 'bigint', 'Long', 'input', 'number', '', 'updateId', 'UpdateId', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.UPDATE', 'EQ', 'input-number', 'dynamic_user_options', '0', '', 16, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (32, 1, 'update_time', '更新时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'updateTime', 'UpdateTime', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.UPDATE', 'BETWEEN', 'datetime', '', '0', '', 17, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (33, 1, 'dept_scope', '部门范围', 'json', 'String', 'input', 'string', '', 'deptScope', 'DeptScope', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', '0', '', 'EQ', '', '', '0', '', 18, 1, 1, '2025-05-27 09:37:08', '2025-05-27 13:23:24', '0'); diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/001_teacher.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/001_teacher.sql new file mode 100644 index 0000000..f1a193c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/001_teacher.sql @@ -0,0 +1,10 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20251013_1836 +-- 以下为演示环境脚本,-- 仅供演示使用,实际业务请删除 + +ALTER TABLE `teacher_statistics` ADD COLUMN `url` json DEFAULT NULL COMMENT '文件地址(JSON)'; + +--changeset 升职哦(sz):20251021_2100 +UPDATE `teacher_statistics` SET `url` = '[{\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/bg1.png\", \"etag\": \"73be62dc9778dc13478c59f0c236feca\", \"size\": 105636, \"dirTag\": \"teacher\", \"fileId\": 158, \"filename\": \"bg1.png\", \"metaData\": {\"original-filename\": \"bg1.png\"}, \"objectName\": \"teacher/20251021/bg1.png\", \"contextType\": \"image/png\"}, {\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/bg7.png\", \"etag\": \"6b6857c36b4fded86645d0ed2662869b\", \"size\": 66861, \"dirTag\": \"teacher\", \"fileId\": 156, \"filename\": \"bg7.png\", \"metaData\": {\"original-filename\": \"bg7.png\"}, \"objectName\": \"teacher/20251021/bg7.png\", \"contextType\": \"image/png\"}, {\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/bg10.png\", \"etag\": \"9a546cb494af380c9e2cf5efac2ae362\", \"size\": 87531, \"dirTag\": \"teacher\", \"fileId\": 157, \"filename\": \"bg10.png\", \"metaData\": {\"original-filename\": \"bg10.png\"}, \"objectName\": \"teacher/20251021/bg10.png\", \"contextType\": \"image/png\"}]' WHERE `id` = 26; +UPDATE `teacher_statistics` SET `url` = '[{\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/bg4.png\", \"etag\": \"c4a227a6f24d5b818bf46a49d28cf282\", \"size\": 90015, \"dirTag\": \"teacher\", \"fileId\": 153, \"filename\": \"bg4.png\", \"metaData\": {\"original-filename\": \"bg4.png\"}, \"objectName\": \"teacher/20251021/bg4.png\", \"contextType\": \"image/png\"}, {\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/bg5.png\", \"etag\": \"a6e547dcfe5a50a060d5f895857f0c9b\", \"size\": 70640, \"dirTag\": \"teacher\", \"fileId\": 152, \"filename\": \"bg5.png\", \"metaData\": {\"original-filename\": \"bg5.png\"}, \"objectName\": \"teacher/20251021/bg5.png\", \"contextType\": \"image/png\"}, {\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/微信图片_20240420160033.jpg\", \"etag\": \"322e08e6b47cd85dec6a7b8dc9e88476\", \"size\": 20276, \"dirTag\": \"teacher\", \"fileId\": 151, \"filename\": \"微信图片_20240420160033.jpg\", \"metaData\": {\"original-filename\": \"微信图片_20240420160033.jpg\"}, \"objectName\": \"teacher/20251021/微信图片_20240420160033.jpg\", \"contextType\": \"image/jpeg\"}, {\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/教师统计.xlsx\", \"etag\": \"47c4e1a9be3987a477d2c9672f761968\", \"size\": 5481, \"dirTag\": \"teacher\", \"fileId\": 154, \"filename\": \"教师统计.xlsx\", \"metaData\": {\"original-filename\": \"教师统计.xlsx\"}, \"objectName\": \"teacher/20251021/教师统计.xlsx\", \"contextType\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"}, {\"url\": \"https://minioapi.szadmin.cn/test/teacher/20251021/题库导入模板.xlsx\", \"etag\": \"54e2201ec376091aeb3f25581feba1c1\", \"size\": 13862, \"dirTag\": \"teacher\", \"fileId\": 155, \"filename\": \"题库导入模板.xlsx\", \"metaData\": {\"original-filename\": \"题库导入模板.xlsx\"}, \"objectName\": \"teacher/20251021/题库导入模板.xlsx\", \"contextType\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"}]' WHERE `id` = 27; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/002_demo.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/002_demo.sql new file mode 100644 index 0000000..43bcc56 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/002_demo.sql @@ -0,0 +1,66 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20251105_1934 +DELETE FROM `sys_role` WHERE id = 3 and permissions = 'teacher_statics_menu'; +-- 创建新的演示角色 +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (3, '教师统计-全部', '演示:数据权限-全部', 'F', '2024-05-10 21:53:15', '2025-11-05 13:39:50', NULL, 1, 'T', 'teacher_statics_menu_1006001'); +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (4, '教师统计-部门及以下', '演示:数据权限-部门及以下', 'F', '2025-11-05 11:24:40', '2025-11-05 13:39:45', 1, 1, 'T', 'teacher_statics_menu_1006002'); +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (5, '教师统计-仅本部', '演示:数据权限-仅本部', 'F', '2025-11-05 11:25:21', '2025-11-05 13:40:02', 1, 1, 'T', 'teacher_statics_menu_1006003'); +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (6, '教师统计-仅本人', '演示:数据权限-仅本人', 'F', '2025-11-05 13:39:19', '2025-11-05 13:40:08', 1, 1, 'T', 'teacher_statics_menu_1006004'); +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (7, '教师统计-自定义', '演示:数据权限-自定义', 'F', '2025-11-05 13:46:50', '2025-11-05 13:46:50', 1, 1, 'T', 'teacher_statics_menu_1006005'); +-- 为新的角色分配菜单权 +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', 3, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 3, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('cb3500315dba4c2d83e4d92edf36dff7', 3, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('7391f12ad51049c2b86d231d39708c71', 3, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('73d312f4fa8949ddba3d9807c0c56f00', 3, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('91ccb13b5c174583803a4c492a5dfdb6', 3, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('8061d8e79be744bf91b7b438f8e8e887', 3, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 3, 'scope', '1006001'); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', 4, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 4, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('cb3500315dba4c2d83e4d92edf36dff7', 4, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('7391f12ad51049c2b86d231d39708c71', 4, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('73d312f4fa8949ddba3d9807c0c56f00', 4, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('91ccb13b5c174583803a4c492a5dfdb6', 4, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('8061d8e79be744bf91b7b438f8e8e887', 4, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 4, 'scope', '1006002'); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', 6, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 6, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('cb3500315dba4c2d83e4d92edf36dff7', 6, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('7391f12ad51049c2b86d231d39708c71', 6, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('73d312f4fa8949ddba3d9807c0c56f00', 6, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('91ccb13b5c174583803a4c492a5dfdb6', 6, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('8061d8e79be744bf91b7b438f8e8e887', 6, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 6, 'scope', '1006004'); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', 5, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 5, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('cb3500315dba4c2d83e4d92edf36dff7', 5, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('7391f12ad51049c2b86d231d39708c71', 5, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('73d312f4fa8949ddba3d9807c0c56f00', 5, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('91ccb13b5c174583803a4c492a5dfdb6', 5, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('8061d8e79be744bf91b7b438f8e8e887', 5, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 5, 'scope', '1006003'); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', 7, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 7, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('cb3500315dba4c2d83e4d92edf36dff7', 7, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('7391f12ad51049c2b86d231d39708c71', 7, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('73d312f4fa8949ddba3d9807c0c56f00', 7, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('91ccb13b5c174583803a4c492a5dfdb6', 7, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('8061d8e79be744bf91b7b438f8e8e887', 7, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('85b54322630f43a39296488a5e76ba16', 7, 'scope', '1006005'); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('d90946bc9ed54e598e3c4471dbd1f496', 2, 'menu', NULL); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`, `permission_type`, `data_scope_cd`) VALUES ('7a4544831af34e69aa73148bf84b9924', 2, 'menu', NULL); + +-- 为自定义角色分配数据权限 +INSERT IGNORE INTO `sys_data_role_relation` (`role_id`, `relation_type_cd`, `relation_id`, `menu_id`) VALUES (7, '1007001', 3, '85b54322630f43a39296488a5e76ba16'); +INSERT IGNORE INTO `sys_data_role_relation` (`role_id`, `relation_type_cd`, `relation_id`, `menu_id`) VALUES (7, '1007001', 5, '85b54322630f43a39296488a5e76ba16'); +INSERT IGNORE INTO `sys_data_role_relation` (`role_id`, `relation_type_cd`, `relation_id`, `menu_id`) VALUES (7, '1007002', 15, '85b54322630f43a39296488a5e76ba16'); + +--changeset 升职哦(sz):20251106_2018 +DELETE `sys_user_role` FROM `sys_user_role` JOIN `sys_user` on `sys_user_role`.`user_id` = `sys_user`.`id` where `sys_user`.`username` in ('user', 'test1', 'test2', 'test3', 'test4'); +INSERT INTO `sys_user_role` (`role_id`, `user_id`) VALUES (3, 2); +INSERT INTO `sys_user_role` (`role_id`, `user_id`) VALUES (4, 3); +INSERT INTO `sys_user_role` (`role_id`, `user_id`) VALUES (5, 4); +INSERT INTO `sys_user_role` (`role_id`, `user_id`) VALUES (6, 5); +INSERT INTO `sys_user_role` (`role_id`, `user_id`) VALUES (7, 6); diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/003_generator.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/003_generator.sql new file mode 100644 index 0000000..8a3bc45 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.0/003_generator.sql @@ -0,0 +1,28 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20251108_1239 +--comment: 更新代码生成器的演示记录 +TRUNCATE TABLE generator_table; +TRUNCATE TABLE generator_table_column; + +INSERT INTO `generator_table` (`table_id`, `table_name`, `table_comment`, `class_name`, `camel_class_name`, `tpl_category`, `package_name`, `module_name`, `business_name`, `function_name`, `function_author`, `type`, `options`, `parent_menu_id`, `path`, `path_api`, `path_web`, `menu_init_type`, `btn_permission_type`, `btn_data_scope_type`, `has_import`, `has_export`, `generate_type`, `create_id`, `update_id`, `create_time`, `update_time`, `is_autofill`) VALUES (2, 'teacher_statistics', '教师统计总览表', 'TeacherStatistics', 'teacherStatistics', 'crud', 'com.sz.admin', 'teacher', 'teacherStatistics', '教师统计总览表', 'sz-admin', '0', '', '0', '/', 'E:\\dev\\Code\\Github\\sz-boot-parent\\sz-service\\sz-service-admin', '', '1', '1', '1', '1', '1', 'all', 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:28', '1'); + +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (34, 2, 'id', 'ID', 'bigint', 'Long', 'input', 'number', '', 'id', 'Id', '1', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '', 'EQ', 'input-number', '', '0', '{}', 1, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (35, 2, 'year', '统计年限', 'varchar(4)', 'String', 'input', 'string', '', 'year', 'Year', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '{}', 2, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (36, 2, 'month', '统计月份', 'varchar(2)', 'String', 'input', 'string', '', 'month', 'Month', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '{}', 3, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (37, 2, 'during_time', '统计年月', 'varchar(10)', 'String', 'date-picker', 'string', '', 'duringTime', 'DuringTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '{}', 4, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (38, 2, 'teacher_id', '教师id', 'varchar(32)', 'String', 'input', 'string', '', 'teacherId', 'TeacherId', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '{}', 5, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (39, 2, 'teacher_common_type', '讲师区分类型', 'int', 'Integer', 'select', 'number', '', 'teacherCommonType', 'TeacherCommonType', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'select', '', '0', '{}', 6, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (40, 2, 'total_teaching', '授课总数', 'int', 'Integer', 'input', 'number', '', 'totalTeaching', 'TotalTeaching', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input-number', '', '0', '{}', 7, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (41, 2, 'total_class_count', '服务班次数', 'int', 'Integer', 'input', 'number', '', 'totalClassCount', 'TotalClassCount', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input-number', '', '0', '{}', 8, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (42, 2, 'total_hours', '课时总数', 'decimal(10,2)', 'BigDecimal', 'input', 'number', 'java.math.BigDecimal', 'totalHours', 'TotalHours', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'input-number', '', '0', '{}', 9, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (43, 2, 'check_status', '核对状态', 'int', 'Integer', 'select', 'number', '', 'checkStatus', 'CheckStatus', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', '', 'EQ', 'radio', '', '0', '{}', 10, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (44, 2, 'check_time', '核对时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'checkTime', 'CheckTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'BETWEEN', 'datetime', '', '0', '{}', 11, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (45, 2, 'last_sync_time', '最近一次同步时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'lastSyncTime', 'LastSyncTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', '', 'BETWEEN', 'datetime', '', '0', '{}', 12, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (46, 2, 'remark', '备注', 'varchar(255)', 'String', 'input', 'string', '', 'remark', 'Remark', '0', '0', '0', '1', '1', '1', '0', '1', '1', '0', '0', '', 'EQ', 'input', '', '0', '{}', 13, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (47, 2, 'create_id', '创建人ID', 'bigint', 'Long', 'input', 'number', '', 'createId', 'CreateId', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.INSERT', 'EQ', 'input-number', 'dynamic_user_options', '0', '{}', 14, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (48, 2, 'create_time', '生成时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'createTime', 'CreateTime', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.INSERT', 'BETWEEN', 'datetime', '', '0', '{}', 15, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (49, 2, 'update_id', '更新人ID', 'bigint', 'Long', 'input', 'number', '', 'updateId', 'UpdateId', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.UPDATE', 'EQ', 'input-number', 'dynamic_user_options', '0', '{}', 16, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (50, 2, 'update_time', '更新时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'updateTime', 'UpdateTime', '0', '0', '0', '0', '0', '1', '0', '0', '1', '1', '0', 'FieldFill.UPDATE', 'BETWEEN', 'datetime', '', '0', '{}', 17, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (51, 2, 'dept_scope', '部门范围', 'json', 'String', 'input', 'string', '', 'deptScope', 'DeptScope', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '', 'EQ', '', '', '0', '{}', 18, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); +INSERT INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (52, 2, 'url', '文件地址(JSON)', 'json', 'List', 'input', 'string', 'com.mybatisflex.core.handler.JacksonTypeHandler,com.sz.core.common.entity.UploadResult,java.util.List,com.mybatisflex.annotation.Column', 'url', 'Url', '0', '0', '0', '1', '1', '1', '0', '0', '0', '0', '0', '', 'EQ', 'fileUpload', '', '0', '{\"file-download-list.align\":\"left\",\"upload-files.dir\":\"tmp\",\"upload-files.limit\":\"5\",\"upload-files.fileSize\":\"3\",\"upload-files.accept\":\"\",\"file-download-list.maxRows\":\"3\"}', 19, 1, 1, '2025-11-08 09:11:50', '2025-11-08 10:26:29', '0'); diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.1/001_teacher.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.1/001_teacher.sql new file mode 100644 index 0000000..005244c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/business/1.3.1/001_teacher.sql @@ -0,0 +1,17 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20251208_1936 +-- 以下为演示环境脚本,-- 仅供演示使用,实际业务请删除 + +ALTER TABLE `teacher_statistics` ADD COLUMN `content_html` mediumtext COLLATE utf8mb4_general_ci COMMENT '内容HTML'; + +--changeset 升职哦(sz):20251210_1936 +UPDATE `teacher_statistics` SET `content_html` = '

Sz-Admin v1.3.0-beta

基于 Spring Boot 3.x 、Jdk21、Vue 3 的轻量级脚手架

GitHub StarsGitHub ForksGitee StarsGitee ForksLicenseAsk DeepWiki

介绍

提示

接触了很多优秀的开源和闭源项目,在使用过程中也发现一些问题,不甘满足的我遂产生了想法:于是利用休息时间编写了一套后台管理系统,它灵活、简洁、高效,拥抱最新的技术,因此Sz-Admin便诞生了,也意为升职Admin,升职加薪节节高。

Sz Admin ,一个基于 Spring Boot 3、JDK21、Vue 3 和 Element-Plus 的开源后台管理框架,致力于为您提供一个流畅、直观且功能强大的开发框架。它不仅融合了最新的技术趋势,而且通过精心设计,确保了系统的简洁性和高效,让使用者可以专注业务。

在线体验

  • 官网地址:https://szadmin.cn/

  • 预览地址:https://preview.szadmin.cn/

  • 代码仓库:

    • 前端代码:
    git clone https://github.com/feiyuchuixue/sz-admin.git
    • 后端代码:
    git clone https://github.com/feiyuchuixue/sz-boot-parent.git
    • 部署脚本:
    git clone https://github.com/feiyuchuixue/sz-deploy.git

系统要求

  • JDK >= 21
  • MySQL >= 8.0.34
  • Maven >= 3.8
  • Node >= 18.x

功能列表

  • 账户管理:负责管理系统用户的创建、配置及权限分配,确保用户身份的合法性和操作的合规性。
  • 角色管理:实现角色与权限的精细绑定,通过角色分配简化用户权限管理,提高系统安全性和灵活性。
  • 菜单管理:定制化系统导航结构,通过权限细分确保用户仅访问授权的操作界面,增强操作的直观性和可控性。
  • 字典管理:维护系统内静态数据字典,如配置项、枚举值等,以统一管理和优化数据的一致性。
  • 参数管理:动态调整系统运行参数,无需重启即可实时生效,提升系统响应速度和运维效率。
  • 客户端管理:监管客户端接入,确保客户端的合法性和安全性,维护系统的整体稳定性。
  • 部门管理:构建组织架构,通过树状结构展示,支持数据权限的层级化管理,加强信息的有序性和安全性。
  • 代码生成器:自动化生成前后端代码模板,支持CRUD操作,加速开发周期,提升开发效率。
  • WebSocket:提供WebSocket支持。
  • 数据权限支持:通过精细控制和灵活配置,确保用户仅访问授权的数据,强化数据安全性和系统响应性。
  • 接口防抖:通过限制短时间内的重复请求,防止脏数据产生,确保数据的准确性和系统稳定性。

系统美照

登录页home页
账户管理角色管理
菜单管理字典管理
配置管理客户端管理
部门管理代码预览
代码生成配置1代码生成配置2
' where id = 22; +UPDATE `teacher_statistics` SET `content_html` = '

更新日志

v1.3.0-beta (20251109)| 大型更新

NOTE

升级指南

!存在潜在破坏性变更,请务必仔细阅读升级文档!

重要提示:升级至本版本前,请先清理 Redis 缓存中的用户信息,否则可能因数据结构变更导致登录异常

sz-boot-parent

新增

  • 支持 Spring Boot Actuator 监控。
  • login 相关密码传输支持 AES-GCM 加密,提升安全性。
  • 增加登录请求及验证码请求次数的限制配置。
  • [代码生成器] 支持多文件上传(fileUpload)。
  • [代码生成器] 支持数据权限创建。
  • 账户管理新增账户类型设置,支持超管账户指定。
  • 支持“超级管理员”角色参数配置。

重构

  • 破坏性变更:模板文件管理及下载等逻辑。
  • 破坏性变更:移除独立数据权限角色,合并至系统角色。
  • 破坏性变更:简化数据权限核心 SimplePermissionDialect,实现与处理流程更加清晰。
  • 破坏性变更:调整数据存储结构,login 相关方法引入 dataScope 缓存,移除 ruleMap、userRuleMap、deptRuleMap。因数据结构升级后可能需要清空redis缓存。

修复

  • 修复登录日志异步线程引发的记录异常。
  • 修复 IP 地址获取失败的问题。
  • 修复 Excel 导入时数据为空问题,移除代码模板中的 @Accessors(chain = true)。
  • 回退 FastExcel 版本至 1.2.0,解决部分 Excel 导出异常。

修改/移除

  • 移除生产环境配置中的 CORS 设置。
  • ImportExcel 方法支持数据库入库功能。
  • [演示案例] 教师统计,支持附件文件上传。
  • sys_data_role、sys_data_role_menu 相关业务标记为弃用,功能合并至 sys_role。
  • Dockerfile 镜像切换至 azul/zulu-openjdk(JDK 21)。
  • 移除 Flyway,数据库迁移已完全转至 liquibase。

优化

  • 登录列表倒序排序显示。
  • [代码生成器] 菜单按钮的查询与排序优化。
  • 修复[动态字典]部门、角色在 redisCache 中循环赋值导致的性能问题。
  • OSS 上传支持原始文件名元数据与特殊字符(如#)处理。
  • HttpReqResUtil 增加 getRequest 方法,支持全局 HttpServletRequest 获取。
  • StringUtils.getRealKey 方法增强字符串替换、null 处理与异常捕获。

sz-admin

新增

  • 新增 FileDownloadList 组件,实现 ProTable 中文件资源展示、支持多文件下载与预览、文件列表回显优化。
  • login 相关密码传输支持 AES-GCM 加密,提升安全性。
  • 账户管理支持账户类型设置,可直接指定管理员身份。

重构

  • [UploadFiles 组件] 增加多项功能并修正若干问题。
  • 角色管理-权限分配组件重构,提升交互体验。

优化

  • useDownload 组件优先采用 response header 中 filename 作为下载文件名。
  • 优化菜单表单的操作逻辑,新增提示说明。
  • 优化模板文件管理列表的文件操作列。
  • [ImportExcel] 增加模板信息展示及必填参数校验。
  • [file 组件] 优化 accept 文件类型检查,可选开启,默认不限制类型。
  • 文件下载和模板功能进一步优化,提升用户体验:
    • 优化 useDownload Hook 的实现
    • 文件模板相关逻辑调整
    • 菜单 Form 表单增加提示性 tooltip
    • 修正 blob 流响应拦截器的错误处理
    • 列表文件展示统一切换为 FileDownloadList 组件

修复

  • [ProTable] 因数据类型不匹配导致的列表字典项渲染样式异常。

修改

  • [演示案例] 教师统计,新增多文件上传及回显组件支持。

数据库变更

  • 更新 sys_menu 表:优化菜单数据,采用更简洁的路由名称,并将原本在菜单上的查询权限提取为按钮级权限。

  • 调整 sys_role_menu 表:新增字段 permission_type(权限类型,如功能权限、数据权限),新增字段 data_scope_cd(数据权限范围)。

  • 更新 sys_data_role_relation 表:新增字段 menu_id,用于关联菜单。

  • 表 sys_data_role_menusys_data_role 标记为废弃,相关业务已合并至 sys_role 和 sys_data_role_relation 表。

  • 优化 sys_temp_filesys_temp_file_history 表:将 url 字段类型调整为 JSON,并插入演示数据。

     !!注意:此更改会导致原有数据不兼容。
  • sys_temp_file 表新增 alias 字段,用于标识文件别名。

  • sys_rolesys_role_menusys_data_role_relationsys_user_role 表补充及调整了演示数据。

升级建议

  • 建议在升级前做好数据和数据库结构的完整备份,以保障您的数据安全。
  • 本次数据库结构及功能调整,可能影响部分旧数据兼容性及现有业务,请结合自身情况提前评估,并根据实际需求做好适配与数据处理。
  • 欢迎在升级过程中通过社区或交流群反馈遇到的问题,我们也会积极协助答疑与经验分享。

v1.2.6-beta (20250831)


' where id = 23; +UPDATE `teacher_statistics` SET `content_html` = '
+

Sz-Admin v1.3.0-beta

+

基于 Spring Boot 3.x 、Jdk21、Vue 3 的轻量级脚手架

+
GitHub StarsGitHub ForksGitee StarsGitee ForksLicenseAsk DeepWiki
+
+

+

' where id = 24; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/changelog-master.xml b/sz-service/sz-service-admin/src/main/resources/db/changelog/changelog-master.xml new file mode 100644 index 0000000..a00dbb9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/changelog-master.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.1.0-beta/001_system.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.1.0-beta/001_system.sql new file mode 100644 index 0000000..765f0ed --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.1.0-beta/001_system.sql @@ -0,0 +1,785 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250424_1500 +CREATE TABLE IF NOT EXISTS `generator_table` ( + `table_id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `table_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '表名称', + `table_comment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '表描述', + `class_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '实体类名称', + `camel_class_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'camel实体类名称', + `tpl_category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '使用的模版', + `package_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成包路径', + `module_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成模块名', + `business_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成业务名', + `function_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成功能名', + `function_author` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成作者名', + `type` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成方式(0 zip压缩包;1 自定义路径)', + `options` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '其他参数', + `parent_menu_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '上级菜单id', + `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成路径', + `path_api` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'api生成路径', + `path_web` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'web生成路径', + `menu_init_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否自动创建菜单路由(1 是)', + `btn_permission_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否自动创建按钮权限 (1 是)', + `has_import` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否支持导入(1 是)', + `has_export` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否支持导出(1 是)', + `generate_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'all' COMMENT '生成类型(全量:all,后端:server,接口:service)', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间', + `is_autofill` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '是否自动填充(1 是)', + PRIMARY KEY (`table_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Generator Table' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for generator_table_column +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `generator_table_column` ( + `column_id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', + `table_id` bigint NULL DEFAULT NULL COMMENT '归属表编号', + `column_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列名称', + `column_comment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列描述', + `column_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '列类型', + `java_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'JAVA类型', + `search_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '搜索类型', + `ts_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'ts类型', + `java_type_package` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'java类型包名', + `java_field` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'JAVA字段名', + `up_camel_field` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'get开头的驼峰字段名', + `is_pk` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否主键(1是)', + `is_increment` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否自增(1是)', + `is_required` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否必填(1是)', + `is_insert` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否为插入字段(1是)', + `is_edit` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否编辑字段(1是)', + `is_list` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否列表字段(1是)', + `is_query` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否查询字段(1是)', + `is_import` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否导入字段(1 是)', + `is_export` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否导出字段(1 是)', + `is_autofill` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否自动填充(1 是)', + `is_unique_valid` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否进行唯一校验(1 是)', + `autofill_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '自动填充类型', + `query_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '查询方式', + `html_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '显示类型', + `dict_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '字典类型', + `is_logic_del` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '是否逻辑删除(1 是)', + `options` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '其他设置', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间', + `dict_show_way` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '字典展示方式(0 唯一标识;1 别名)', + PRIMARY KEY (`column_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'Generator Table Column' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for mini_user +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `mini_user` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '小程序用户ID', + `sys_user_id` int NULL DEFAULT NULL COMMENT '关联的系统用户ID', + `openid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '小程序用户的唯一标识', + `unionid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '公众号的唯一标识', + `nickname` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称', + `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '真实姓名', + `phone` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `avatar_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户头像URL', + `subscribe` tinyint NULL DEFAULT NULL COMMENT '是否订阅公众号(1是0否)', + `sex` tinyint NULL DEFAULT NULL COMMENT '性别,0-未知 1-男性,2-女性', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '删除标识', + `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + INDEX `index_openid`(`openid` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '小程序用户表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_client +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_client` ( + `client_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '客户端id', + `client_key` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '客户端key', + `client_secret` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '客户端秘钥', + `grant_type_cd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT 'password' COMMENT '授权类型', + `device_type_cd` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '设备类型', + `active_timeout` int NULL DEFAULT 1800 COMMENT 'token活跃超时时间', + `timeout` int NULL DEFAULT 604800 COMMENT 'token固定超时', + `client_status_cd` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '0' COMMENT '状态(正常 禁用)', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT 'F' COMMENT '删除标志', + `create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '备注', + `is_lock` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT 'F' COMMENT '是否锁定', + PRIMARY KEY (`client_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '系统授权表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_config` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '参数配置ID', + `config_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '参数名', + `config_key` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '参数key', + `config_value` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '参数value', + `is_lock` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '是否锁定', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '参数配置表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_data_role +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_data_role` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '数据角色ID', + `role_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', + `data_scope_cd` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据权限,data_scope字典', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '简介', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '删除与否', + `is_lock` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '是否锁定', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统数据角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_data_role_menu +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_data_role_menu` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `role_id` bigint NULL DEFAULT NULL COMMENT 'sys_data_role_id (数据角色表ID)', + `menu_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'sys_menu_id (菜单表)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 73 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统数据角色-菜单表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_data_role_relation +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_data_role_relation` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `role_id` bigint NULL DEFAULT NULL COMMENT 'sys_data_role_id (数据角色表ID)', + `relation_type_cd` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '关联类型,data_scope_relation_type', + `relation_id` bigint NULL DEFAULT NULL COMMENT '关联表id,联动relation_type_cd(部门ID或个人ID)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 74 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统数据角色-关联表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_dept +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_dept` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '部门ID', + `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '部门名称', + `pid` bigint NOT NULL COMMENT '父级ID', + `deep` int NULL DEFAULT NULL COMMENT '层级', + `sort` int NULL DEFAULT NULL COMMENT '排序', + `has_children` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '是否有子级', + `is_lock` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '是否锁定', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '删除标识', + `remark` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '部门表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_dept_closure +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_dept_closure` ( + `ancestor_id` bigint NOT NULL COMMENT '祖先节点ID', + `descendant_id` bigint NOT NULL COMMENT '后代节点ID', + `depth` int NOT NULL COMMENT '祖先节点到后代节点的距离' +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '部门祖籍关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_dept_leader +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_dept_leader` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '部门领导人ID', + `dept_id` int NULL DEFAULT NULL, + `leader_id` bigint NOT NULL COMMENT '领导人ID(sys_user_id)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '部门领导人表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_dict +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_dict` ( + `id` bigint NOT NULL COMMENT '字典ID(规则)', + `sys_dict_type_id` bigint NOT NULL COMMENT '关联sys_dict_type ID', + `code_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称', + `alias` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '字典(Key)别名,某些情况下如果不想使用id作为key', + `sort` int NOT NULL COMMENT '排序(正序)', + `callback_show_style` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '回显样式', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '备注', + `is_lock` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '是否锁定', + `is_show` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'T' COMMENT '是否展示', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '是否删除', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `delete_id` bigint NULL DEFAULT NULL COMMENT '删除人ID', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_dict_type +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_dict_type` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '字典类型ID', + `type_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '字典类型名(中文)', + `type_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典类型码(英文)', + `is_lock` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '是否锁定,锁定的属性无法在页面进行修改', + `is_show` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'T' COMMENT '显示与否', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '删除与否', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '描述', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `delete_id` bigint NULL DEFAULT NULL COMMENT '删除人ID', + `type` enum('system','business') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'business' COMMENT '字典类型: system 系统, business 业务', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1009 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典类型' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_export_info +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_export_info` ( + `id` int NOT NULL AUTO_INCREMENT, + `file_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '导出的文件名称', + `export_status_cd` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '导出状态,关联字典表export_status', + `create_id` int NULL DEFAULT NULL, + `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '导出信息' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_file +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_file` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '文件ID', + `filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '文件名', + `dir_tag` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '目录标识', + `size` bigint NULL DEFAULT NULL COMMENT '文件大小', + `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '文件域名', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `object_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '对象名(唯一)', + `context_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '文件类型', + `e_tag` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'eTag标识', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 100 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '文件表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_menu` ( + `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单表id', + `pid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '父级id', + `path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '路径', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '路由名称', + `title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '标题', + `icon` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT 'icon图标', + `component` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '组件路径', + `redirect` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '外链地址', + `sort` int NOT NULL COMMENT '排序', + `deep` int NOT NULL COMMENT '层级', + `menu_type_cd` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '菜单类型 (字典表menu_type)', + `permissions` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '按钮权限', + `is_hidden` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '是否隐藏', + `has_children` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '是否有子级', + `is_link` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '路由外链时填写的访问地址', + `is_full` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '菜单是否全屏', + `is_affix` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '菜单是否固定在标签页', + `is_keep_alive` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '当前路由是否缓存', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '是否删除', + `delete_id` bigint NULL DEFAULT NULL COMMENT '删除人ID', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + `use_data_scope` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '菜单是否开启数据权限', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统菜单表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_role` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '角色ID', + `role_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '简介', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '删除与否', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + `is_lock` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '是否锁定', + `permissions` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '标识,唯一', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_role_menu` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '系统角色-菜单ID', + `menu_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'sys_menu_id (菜单表)', + `role_id` bigint NULL DEFAULT NULL COMMENT 'sys_role_id (角色表)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 81 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色-菜单表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_temp_file +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_temp_file` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `sys_file_id` bigint NULL DEFAULT NULL COMMENT '文件ID', + `temp_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '模版名', + `url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '地址', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '逻辑删除', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '模版文件表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for sys_temp_file_history +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_temp_file_history` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `sys_temp_file_id` bigint NULL DEFAULT NULL COMMENT '模版文件ID', + `sys_file_id` bigint NULL DEFAULT NULL COMMENT '文件ID', + `temp_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '模版名', + `url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '地址', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '备注', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '模版文件历史表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_user` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID', + `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名', + `pwd` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '密码', + `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `nickname` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '昵称', + `sex` tinyint(1) NULL DEFAULT NULL COMMENT '性别(0 未知 1 男 2 女)', + `birthday` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生日', + `logo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '头像地址', + `age` int NULL DEFAULT NULL COMMENT '年龄,--废弃,以生日为主', + `id_card` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '身份证', + `email` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱地址', + `account_status_cd` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账户状态 (如 冻结;禁言;正常。 关联字典表account_status)', + `user_tag_cd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '标签(自定义关联到字典表)', + `last_login_time` datetime NULL DEFAULT NULL COMMENT '最近一次登录时间', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'F' COMMENT '是否删除', + `create_id` bigint NULL DEFAULT NULL COMMENT '创建人ID', + `update_id` bigint NULL DEFAULT NULL COMMENT '更新人ID', + PRIMARY KEY (`id`) USING BTREE, + INDEX `username_index`(`username` ASC) USING BTREE, + INDEX `create_time_index`(`create_time` DESC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统用户表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_user_data_role +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_user_data_role` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户-数据角色关联ID', + `role_id` bigint NULL DEFAULT NULL COMMENT '数据角色ID (sys_data_role_id)', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户ID(sys_user_id)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统用户-数据角色关联表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_user_dept +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_user_dept` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户-部门关系ID', + `dept_id` bigint NULL DEFAULT NULL COMMENT '部门ID (sys_dept_id)', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户ID(sys_user_id)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户-部门关系表' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for sys_user_role +-- ---------------------------- +CREATE TABLE IF NOT EXISTS `sys_user_role` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户-角色关联ID', + `role_id` bigint NULL DEFAULT NULL COMMENT '角色ID (sys_role_id)', + `user_id` bigint NULL DEFAULT NULL COMMENT '用户ID(sys_user_id)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统用户-角色关联表' ROW_FORMAT = DYNAMIC; + +--changeset 升职哦(sz):20250424_1553 + +INSERT IGNORE INTO `generator_table` (`table_id`, `table_name`, `table_comment`, `class_name`, `camel_class_name`, `tpl_category`, `package_name`, `module_name`, `business_name`, `function_name`, `function_author`, `type`, `options`, `parent_menu_id`, `path`, `path_api`, `path_web`, `menu_init_type`, `btn_permission_type`, `has_import`, `has_export`, `generate_type`, `create_id`, `update_id`, `create_time`, `update_time`, `is_autofill`) VALUES (1, 'teacher_statistics', '教师统计总览表', 'TeacherStatistics', 'teacherStatistics', 'crud', 'com.sz.admin', 'teacherstatistics', 'teacherStatistics', '教师统计总览表', 'sz-admin', '0', NULL, '0', '/', 'E:\\dev\\Code\\Github\\sz-boot-parent\\sz-service\\sz-service-admin', '', '1', '1', '1', '1', 'all', 1, NULL, '2024-05-10 21:45:32', NULL, '1'); + +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (1, 1, 'id', 'id', 'int', 'Long', 'input', 'number', NULL, 'id', 'Id', '1', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 1, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (2, 1, 'year', '统计年限', 'varchar(4)', 'String', 'input', 'string', NULL, 'year', 'Year', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 2, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (3, 1, 'month', '统计月份', 'varchar(2)', 'String', 'input', 'string', NULL, 'month', 'Month', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 3, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (4, 1, 'during_time', '统计年月', 'varchar(10)', 'String', 'date-picker', 'string', NULL, 'duringTime', 'DuringTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 4, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (5, 1, 'teacher_id', '教师id', 'varchar(32)', 'String', 'input', 'string', NULL, 'teacherId', 'TeacherId', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 5, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (6, 1, 'teacher_common_type', '讲师区分类型', 'int', 'Integer', 'select', 'number', NULL, 'teacherCommonType', 'TeacherCommonType', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'select', '', '0', NULL, 6, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (7, 1, 'total_teaching', '授课总数', 'int', 'Integer', 'input', 'number', NULL, 'totalTeaching', 'TotalTeaching', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 7, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (8, 1, 'total_class_count', '服务班次数', 'int', 'Integer', 'input', 'number', NULL, 'totalClassCount', 'TotalClassCount', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 8, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (9, 1, 'total_hours', '课时总数', 'decimal(10,2)', 'BigDecimal', 'input', 'number', 'java.math.BigDecimal', 'totalHours', 'TotalHours', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'input-number', '', '0', NULL, 9, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (10, 1, 'check_status', '核对状态', 'int', 'Integer', 'select', 'number', NULL, 'checkStatus', 'CheckStatus', '0', '0', '1', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'radio', '', '0', NULL, 10, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (11, 1, 'check_time', '核对时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'checkTime', 'CheckTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'datetime', '', '0', NULL, 11, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (12, 1, 'create_time', '生成时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'createTime', 'CreateTime', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', 'FieldFill.INSERT', 'EQ', 'datetime', '', '0', NULL, 12, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (13, 1, 'update_time', '更新时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'updateTime', 'UpdateTime', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1', '0', 'FieldFill.UPDATE', 'EQ', 'datetime', '', '0', NULL, 13, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (14, 1, 'last_sync_time', '最近一次同步时间', 'datetime', 'LocalDateTime', 'date-picker', 'string', 'java.time.LocalDateTime', 'lastSyncTime', 'LastSyncTime', '0', '0', '0', '1', '1', '1', '1', '1', '1', '0', '0', NULL, 'EQ', 'datetime', '', '0', NULL, 14, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); +INSERT IGNORE INTO `generator_table_column` (`column_id`, `table_id`, `column_name`, `column_comment`, `column_type`, `java_type`, `search_type`, `ts_type`, `java_type_package`, `java_field`, `up_camel_field`, `is_pk`, `is_increment`, `is_required`, `is_insert`, `is_edit`, `is_list`, `is_query`, `is_import`, `is_export`, `is_autofill`, `is_unique_valid`, `autofill_type`, `query_type`, `html_type`, `dict_type`, `is_logic_del`, `options`, `sort`, `create_id`, `update_id`, `create_time`, `update_time`, `dict_show_way`) VALUES (15, 1, 'remark', '备注', 'varchar(255)', 'String', 'input', 'string', NULL, 'remark', 'Remark', '0', '0', '0', '1', '1', '1', '0', '1', '1', '0', '0', NULL, 'EQ', 'input', '', '0', NULL, 15, 1, NULL, '2024-05-10 21:45:32', NULL, '0'); + +INSERT IGNORE INTO `sys_client` (`client_id`, `client_key`, `client_secret`, `grant_type_cd`, `device_type_cd`, `active_timeout`, `timeout`, `client_status_cd`, `del_flag`, `create_dept`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`, `is_lock`) VALUES ('195da9fcce574852b850068771cde034', 'sz-admin', '839ce050d3814949af9b2e1f815bc620', 'password', '1004001', 86400, 604800, '1003001', 'F', NULL, 1, '2024-01-22 13:43:51', 1, '2024-04-12 16:06:49', '演示client,禁止删除', 'T'); + +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (1, '主体名称', 'sys.dept.entityName', 'xx公司', 'T', 1, '2024-03-22 10:42:46', 1, '2024-05-10 19:55:41', '公司主体名称'); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (2, '系统账户-初始密码', 'sys.user.initPwd', 'sz123456', 'T', 1, '2024-04-10 09:56:58', 1, '2024-04-10 10:13:28', ''); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (3, '密码错误尝试次数限制', 'sys.pwd.errCnt', '5', 'T', 1, '2024-06-05 20:40:21', 1, '2024-06-05 20:50:11', '一段时间内的密码最大错误次数'); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (4, '密码错误冻结时间(分)', 'sys_pwd.lockTime', '30', 'T', 1, '2024-06-05 20:42:22', 1, '2024-06-05 20:43:30', '时间到期后自动解冻'); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (5, '业务字典起始号段', 'sys.dict.startNo', '2000', 'T', 1, '2024-07-08 17:29:16', NULL, NULL, '业务字典起始号段。1000作为默认的系统字典号段。'); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (6, '是否启用验证码', 'sys.captcha.state', 'true', 'T', 1, '2024-11-07 15:39:50', 1, '2025-01-08 15:54:37', ''); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (7, '验证码有效时间(秒)', 'sys.captcha.expire', '120', 'T', 1, '2025-01-08 22:06:40', NULL, NULL, NULL); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (8, '验证码请求次数限制', 'sys.captcha.requestLimit', '0', 'T', 1, '2025-01-08 22:09:28', 1, '2025-01-09 09:37:10', '一段时间内的验证码请求次数上限(0为不限制)'); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (9, '验证码计数周期(分)', 'sys.captcha.requestCycle', '1440', 'T', 1, '2025-01-08 22:13:09', 1, '2025-01-09 09:38:10', '默认一天'); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (10, '验证码水印', 'sys.captcha.waterText', 'Sz-Admin', 'T', 1, '2025-01-08 22:15:00', 1, '2025-01-09 09:39:15', '验证码右下角水印图案'); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (11, '是否启用验证码水印', 'sys.captcha.waterEnable', 'true', 'T', 1, '2025-01-08 22:18:10', 1, '2025-01-09 09:39:36', ''); +INSERT IGNORE INTO `sys_config` (`id`, `config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES (12, '水印字体', 'sys.captcha.waterFont', 'Arial', 'T', 1, '2025-01-09 08:58:33', NULL, NULL, '请确认服务器是否支持该字体,并注意在商业用途中需确保字体版权合法使用'); + +INSERT IGNORE INTO `sys_data_role` (`id`, `role_name`, `data_scope_cd`, `remark`, `del_flag`, `is_lock`, `create_time`, `update_time`, `create_id`, `update_id`) VALUES (1, '教师统计-本部门及以下', '1006002', '', 'F', 'T', '2024-07-15 15:35:05', '2024-07-15 16:57:19', 1, 1); +INSERT IGNORE INTO `sys_data_role` (`id`, `role_name`, `data_scope_cd`, `remark`, `del_flag`, `is_lock`, `create_time`, `update_time`, `create_id`, `update_id`) VALUES (2, '教师统计-仅本部门', '1006003', '', 'F', 'T', '2024-07-15 15:36:03', NULL, 1, NULL); +INSERT IGNORE INTO `sys_data_role` (`id`, `role_name`, `data_scope_cd`, `remark`, `del_flag`, `is_lock`, `create_time`, `update_time`, `create_id`, `update_id`) VALUES (3, '教师统计-仅本人', '1006004', '', 'F', 'T', '2024-07-15 15:36:46', NULL, 1, NULL); +INSERT IGNORE INTO `sys_data_role` (`id`, `role_name`, `data_scope_cd`, `remark`, `del_flag`, `is_lock`, `create_time`, `update_time`, `create_id`, `update_id`) VALUES (4, '教师统计-自定义', '1006005', '', 'F', 'T', '2024-07-15 15:37:27', NULL, 1, NULL); + +INSERT IGNORE INTO `sys_data_role_menu` (`id`, `role_id`, `menu_id`) VALUES (69, 2, '85b54322630f43a39296488a5e76ba16'); +INSERT IGNORE INTO `sys_data_role_menu` (`id`, `role_id`, `menu_id`) VALUES (70, 3, '85b54322630f43a39296488a5e76ba16'); +INSERT IGNORE INTO `sys_data_role_menu` (`id`, `role_id`, `menu_id`) VALUES (71, 4, '85b54322630f43a39296488a5e76ba16'); +INSERT IGNORE INTO `sys_data_role_menu` (`id`, `role_id`, `menu_id`) VALUES (72, 1, '85b54322630f43a39296488a5e76ba16'); + +INSERT IGNORE INTO `sys_data_role_relation` (`id`, `role_id`, `relation_type_cd`, `relation_id`) VALUES (69, 2, '1007001', 15); +INSERT IGNORE INTO `sys_data_role_relation` (`id`, `role_id`, `relation_type_cd`, `relation_id`) VALUES (70, 3, '1007001', 15); +INSERT IGNORE INTO `sys_data_role_relation` (`id`, `role_id`, `relation_type_cd`, `relation_id`) VALUES (71, 4, '1007002', 5); +INSERT IGNORE INTO `sys_data_role_relation` (`id`, `role_id`, `relation_type_cd`, `relation_id`) VALUES (72, 4, '1007002', 3); +INSERT IGNORE INTO `sys_data_role_relation` (`id`, `role_id`, `relation_type_cd`, `relation_id`) VALUES (73, 1, '1007001', 4); + +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (1, '技术部', 0, 1, 100, 'T', 'F', 'F', NULL, 1, 1, '2024-05-10 21:40:03', '2024-05-10 21:40:46'); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (2, '运营部', 0, 1, 200, 'T', 'F', 'F', NULL, 1, 1, '2024-05-10 21:40:13', '2024-05-10 21:41:34'); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (3, '财务部', 0, 1, 300, 'T', 'F', 'F', NULL, 1, 1, '2024-05-10 21:40:19', '2024-05-10 21:42:03'); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (4, '研发团队', 1, 4, 100, 'T', 'F', 'F', '', 1, 1, '2024-05-10 21:40:29', '2024-05-11 14:30:38'); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (5, '测试团队', 1, 2, 200, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:40:36', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (6, '运维团队', 1, 2, 300, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:40:46', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (7, '产品运营', 2, 2, 100, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:41:06', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (8, '用户运营', 2, 2, 200, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:41:34', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (9, '会计团队', 3, 2, 100, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:41:49', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (10, '审计团队', 3, 2, 200, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:42:03', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (11, '人力资源部', 0, 1, 400, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:42:19', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (12, '销售部', 0, 1, 500, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:42:27', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (13, '法务部', 0, 1, 600, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:42:37', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (14, '行政部', 0, 1, 700, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:42:43', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (15, '移动组', 4, 3, 100, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:43:28', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (16, '算法组', 4, 3, 200, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:43:36', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (17, '前端组', 4, 3, 300, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:43:44', NULL); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (18, '后端组', 4, 4, 400, 'T', 'F', 'F', '', 1, 1, '2024-05-10 21:43:53', '2024-05-10 21:44:12'); +INSERT IGNORE INTO `sys_dept` (`id`, `name`, `pid`, `deep`, `sort`, `has_children`, `is_lock`, `del_flag`, `remark`, `create_id`, `update_id`, `create_time`, `update_time`) VALUES (19, '架构组', 4, 3, 500, 'F', 'F', 'F', NULL, 1, NULL, '2024-05-10 21:44:04', NULL); + +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 1, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 1, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (2, 2, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 2, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (3, 3, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 3, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 4, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (4, 4, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 4, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 5, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (5, 5, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 5, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 6, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (6, 6, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 6, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 7, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (7, 7, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (2, 7, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 8, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (8, 8, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (2, 8, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 9, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (9, 9, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (3, 9, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 10, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (10, 10, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (3, 10, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (11, 11, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 11, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (12, 12, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 12, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (13, 13, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 13, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (14, 14, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 14, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 15, 3); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 15, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (15, 15, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (4, 15, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 16, 3); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 16, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (16, 16, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (4, 16, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 17, 3); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 17, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (17, 17, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (4, 17, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 18, 3); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 18, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (18, 18, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (4, 18, 1); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (0, 19, 3); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (1, 19, 2); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (19, 19, 0); +INSERT IGNORE INTO `sys_dept_closure` (`ancestor_id`, `descendant_id`, `depth`) VALUES (4, 19, 1); + +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1000001, 1000, '正常', '', 1, 'success', '', 'F', 'T', 'F', '2023-08-20 16:30:23', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1000002, 1000, '禁用', '', 2, 'info', '', 'F', 'T', 'F', '2023-08-20 16:33:45', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1000003, 1000, '禁言', '', 3, 'info', '', 'F', 'T', 'F', '2023-08-20 16:33:54', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1001001, 1001, '测试用户', '', 0, 'info', '', 'T', 'T', 'F', '2023-08-20 16:38:58', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1001002, 1001, '超级管理员', '', 0, 'info', '', 'T', 'T', 'F', '2023-08-20 16:39:05', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1001003, 1001, '普通用户', '', 0, 'info', '', 'T', 'T', 'F', '2023-08-20 16:39:11', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1002001, 1002, '目录', '', 1, 'warning', '', 'T', 'T', 'F', '2023-08-21 11:23:05', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1002002, 1002, '菜单', '', 2, 'success', '', 'T', 'T', 'F', '2023-08-21 11:23:17', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1002003, 1002, '按钮', '', 3, 'danger', '', 'T', 'T', 'F', '2023-08-21 11:23:22', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1003001, 1003, '正常', '', 1, 'success', '', 'F', 'T', 'F', '2024-01-22 09:44:52', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1003002, 1003, '禁用', '', 2, 'info', '', 'F', 'T', 'F', '2024-01-22 09:45:16', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1004001, 1004, 'PC', '', 1, 'success', 'pc端', 'F', 'T', 'F', '2024-01-22 10:03:19', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1004002, 1004, '小程序', '', 2, 'success', '小程序端', 'F', 'T', 'F', '2024-01-22 10:03:47', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1004003, 1004, 'Androd', '', 3, 'success', '', 'F', 'T', 'F', '2024-01-22 10:04:35', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1004004, 1004, 'IOS', '', 4, 'success', '', 'F', 'T', 'F', '2024-01-22 10:04:42', '2024-04-12 15:58:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1005001, 1005, '密码认证', 'password', 100, 'success', '', 'T', 'T', 'F', '2024-01-22 10:20:32', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1005002, 1005, '小程序认证', 'applet', 300, 'success', '', 'F', 'T', 'F', '2024-01-22 10:20:40', '2024-04-12 16:51:58', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1005003, 1005, '三方认证', 'third', 400, 'success', '', 'F', 'T', 'F', '2024-01-22 10:20:51', '2024-04-12 16:51:49', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1005004, 1005, '短信认证', 'sms', 200, 'success', '', 'F', 'T', 'F', '2024-01-22 10:20:57', '2024-04-12 16:51:41', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1006001, 1006, '全部', '', 1, 'primary', '', 'T', 'T', 'F', '2024-06-25 18:55:48', '2024-06-25 19:11:28', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1006002, 1006, '本部门及以下', '', 2, 'primary', '', 'T', 'T', 'F', '2024-06-25 18:56:57', '2024-06-25 19:11:29', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1006003, 1006, '仅本部门', '', 3, 'primary', '', 'T', 'T', 'F', '2024-06-25 18:57:22', '2024-06-25 19:11:32', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1006004, 1006, '仅本人', '', 4, 'primary', '', 'T', 'T', 'F', '2024-06-25 18:57:57', '2024-06-25 19:11:34', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1006005, 1006, '自定义', '', 5, 'primary', '', 'T', 'T', 'F', '2024-06-25 18:58:11', '2024-06-25 19:11:36', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1007001, 1007, '部门权限', '', 1, 'primary', '', 'T', 'T', 'F', '2024-06-25 18:59:00', '2024-06-25 19:11:38', NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1007002, 1007, '个人权限', '', 2, 'primary', '个人权限高优先级', 'T', 'T', 'F', '2024-06-25 18:59:27', '2024-06-25 19:11:41', NULL, NULL, NULL, NULL); + +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1000, '账户状态', 'account_status', 'T', 'T', 'F', '', '2023-08-20 11:09:46', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL, 'system'); +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1001, '用户标签', 'user_tag', 'T', 'T', 'F', '', '2023-08-20 14:22:40', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL, 'system'); +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1002, '菜单类型', 'menu_type', 'T', 'T', 'F', '', '2023-08-21 11:20:47', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL, 'system'); +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1003, '授权状态', 'sys_client_status', 'T', 'T', 'F', 'client授权状态', '2023-08-22 09:44:27', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL, 'system'); +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1004, '设备类型', 'device_type', 'T', 'T', 'F', '', '2023-08-22 10:02:11', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL, 'system'); +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1005, '授权类型', 'grant_type', 'T', 'T', 'F', '', '2023-08-22 10:15:58', '2025-04-24 15:45:52', NULL, NULL, NULL, NULL, 'system'); +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1006, '数据权限', 'data_scope', 'T', 'T', 'F', '', '2024-06-25 18:54:21', '2024-06-25 19:12:46', NULL, NULL, NULL, NULL, 'system'); +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1007, '数据权限关联类型', 'data_scope_relation_type', 'T', 'T', 'F', '自定义数据权限的关联类型', '2024-06-25 18:55:37', '2024-06-25 19:12:48', NULL, NULL, NULL, NULL, 'system'); + +INSERT IGNORE INTO `sys_file` (`id`, `filename`, `dir_tag`, `size`, `url`, `create_time`, `object_name`, `context_type`, `e_tag`, `create_id`) VALUES (97, '教师统计 (43) (203252.669).xlsx', 'tmp', 9866, 'https://minioapi.szadmin.cn/test/tmp/20241216/教师统计 (43) (203252.669).xlsx', '2024-12-16 20:32:53', 'tmp/20241216/教师统计 (43) (203252.669).xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', '8bba8015aa748013cc8295a13637fb3a', 1); +INSERT IGNORE INTO `sys_file` (`id`, `filename`, `dir_tag`, `size`, `url`, `create_time`, `object_name`, `context_type`, `e_tag`, `create_id`) VALUES (98, '教师统计 (203323.951).xlsx', 'tmp', 9866, 'https://minioapi.szadmin.cn/test/tmp/20241216/教师统计 (203323.951).xlsx', '2024-12-16 20:33:24', 'tmp/20241216/教师统计 (203323.951).xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', '8bba8015aa748013cc8295a13637fb3a', 1); +INSERT IGNORE INTO `sys_file` (`id`, `filename`, `dir_tag`, `size`, `url`, `create_time`, `object_name`, `context_type`, `e_tag`, `create_id`) VALUES (99, '微信图片_20240420160033.jpg', 'user', 20276, 'https://minioapi.szadmin.cn/test/user/20241216/微信图片_20240420160033.jpg', '2024-12-16 20:39:57', 'user/20241216/微信图片_20240420160033.jpg', 'image/jpeg', '322e08e6b47cd85dec6a7b8dc9e88476', 1); + +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('88b2e5def2ff474fa8bf3537d4a2fe5b', '0', '/system', 'system', '系统管理', 'Tools', '', '', 100, 1, '1002001', '', 'F', 'T', 'F', 'F', 'F', 'T', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('140c9ed43ef54542bbcdde8a5d928400', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/accountManage', 'accountManage', '账号管理', 'UserFilled', '/system/accountManage/index', '', 100, 2, '1002002', 'sys.user.query_table', 'F', 'T', 'F', 'F', 'F', 'T', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('c6dd479d5b304731be403d7551c60d70', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/roleManage', 'roleManage', '角色管理', 'User', '/system/roleManage/index', '', 200, 2, '1002002', 'sys.role.query_table', 'F', 'T', 'F', 'F', 'F', 'T', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('99c2ee7b882749e597bcd62385f368fb', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/menuMange', 'menuMange', '菜单管理', 'Menu', '/system/menuMange/index', '', 300, 2, '1002002', 'sys.menu.query_table', 'F', 'T', 'F', 'F', 'F', 'T', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('dcb6aabcd910469ebf3efbc7e43282d4', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/dictManage', 'dictManage', '字典管理', 'Reading', '/system/dictManage/index', '', 400, 2, '1002002', 'sys.dict.query_table', 'F', 'T', 'F', 'F', 'F', 'T', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('29d33eba6b73420287d8f7e64aea62b3', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/configManage', 'configManage', '参数管理', 'Key', '/system/configManage/index', '', 500, 2, '1002002', 'sys.config.query_table', 'F', 'T', 'F', 'F', 'F', 'T', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('9e731ff422184fc1be2022c5c985735e', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/clientManage', 'ClientManageView', '客户端管理', 'Operation', '/system/clientManage/index', '', 600, 2, '1002002', 'sys.client.query_table', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('8354d626cc65487594a7c38e98de1bad', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/deptManage', 'SysDeptView', '部门管理', 'svg-org', '/system/deptManage/index', '', 700, 2, '1002002', 'sys.dept.query_table', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('0444cd2c01584f0687264b6205536691', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/dataRoleManage', 'SysDataRoleView', '数据权限', 'svg-scope', '/system/dataRoleManage/index', '', 800, 2, '1002002', 'sys.data.role.query_table', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('c4896e8735a745bda9b47ecaf50f46f2', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/fileManage', 'SysFileView', '文件管理', 'Files', '/system/fileManage/index', '', 900, 2, '1002002', 'sys.file.query_table', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('8231a369712e4f8f8ac09fce232cd034', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/sysTempFile', 'SysTempFileView', '模版文件管理', 'DocumentCopy', '/system/sysTempFile/index', '', 1000, 2, '1002002', 'sys.temp.file.query_table', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('df2894b4c06e47cab84142d81edc494d', 'c6dd479d5b304731be403d7551c60d70', '', '', '新增角色', '', '', '', 100, 3, '1002003', 'sys.role.create_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('2868079355ce4b6c985b1b746dbb0952', 'c4896e8735a745bda9b47ecaf50f46f2', '', '', '新增', '', '', '', 100, 3, '1002003', 'sys.file.create', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('e931c84b8bc945a7b6ba2d58c8a93afc', '8231a369712e4f8f8ac09fce232cd034', '', '', '新增', '', '', '', 100, 3, '1002003', 'sys.temp.file.create', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('0f98b89c67e54cb0bcff2b56aa98832f', '140c9ed43ef54542bbcdde8a5d928400', '', '', '新增账号', '', '', '', 100, 3, '1002003', 'sys.user.create_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('9338bf2f57984825bc227bb618f9db81', '99c2ee7b882749e597bcd62385f368fb', '', '', '新增菜单', '', '', '', 100, 3, '1002003', 'sys.menu.create_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('4f39ef0fd2f748f6ab7d6d20d98bc4af', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', '新增字典类型', '', '', '', 100, 3, '1002003', 'sys.dict.add_type_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('8fd6721941494fd5bbe16bec82b235be', '8354d626cc65487594a7c38e98de1bad', '', '', '新增', '', '', '', 100, 3, '1002003', 'sys.dept.create', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('8d92cf6f2f3248569d5dd6cb6b958d7c', '0444cd2c01584f0687264b6205536691', '', '', '新增', '', '', '', 100, 3, '1002003', 'sys.data.role.create', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('ede76f5e60b640aa9de2ba7216b90ceb', '29d33eba6b73420287d8f7e64aea62b3', '', '', '新增参数', '', '', '', 100, 3, '1002003', 'sys.config.add_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('6c46fd01faf042fc9dd4a9c9b9ef2c5a', '9e731ff422184fc1be2022c5c985735e', '', '', '新增', '', '', '', 100, 3, '1002003', 'sys.client.create', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('8255bac5eae748a0a8500167963b3e00', '140c9ed43ef54542bbcdde8a5d928400', '', '', '编辑账号', '', '', '', 200, 3, '1002003', 'sys.user.update_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('87a26b76daad47c2a12c470605563c4a', '8231a369712e4f8f8ac09fce232cd034', '', '', '修改', '', '', '', 200, 3, '1002003', 'sys.temp.file.update', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('f42b249ccfd44fdcbc2dba48a308c1f6', '0444cd2c01584f0687264b6205536691', '', '', '修改', '', '', '', 200, 3, '1002003', 'sys.data.role.update', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('006bdbacd71a481f88b6acf895529acd', '8354d626cc65487594a7c38e98de1bad', '', '', '修改', '', '', '', 200, 3, '1002003', 'sys.dept.update', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('05194ef5fa7a4a308a44f6f5c6791c3a', '99c2ee7b882749e597bcd62385f368fb', '', '', '编辑菜单', '', '', '', 200, 3, '1002003', 'sys.menu.update_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('0933b165ffc14d558e8de43ccb6687f6', 'c6dd479d5b304731be403d7551c60d70', '', '', '编辑角色', '', '', '', 200, 3, '1002003', 'sys.role.update_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('3a54d488132b4331bf3cd5e6d86ffcf4', '29d33eba6b73420287d8f7e64aea62b3', '', '', '修改参数', '', '', '', 200, 3, '1002003', 'sys.config.update_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('5b33ac3d630543d09d1388fae4d13fc0', '9e731ff422184fc1be2022c5c985735e', '', '', '修改', '', '', '', 200, 3, '1002003', 'sys.client.update', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('49c75878b4d445f8be5f69e21e18b70d', 'c4896e8735a745bda9b47ecaf50f46f2', '', '', '修改', '', '', '', 200, 3, '1002003', 'sys.file.update', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('818cc6e1889d46579525ad8ab921eeb8', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', '编辑字典类型', '', '', '', 200, 3, '1002003', 'sys.dict.update_type_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('b428eba3f9a34025a46c394df5390b88', '29d33eba6b73420287d8f7e64aea62b3', '', '', '删除参数', '', '', '', 300, 3, '1002003', 'sys.config.delete_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('fa0c65ad783d4bf9b919a6db02ef1428', '99c2ee7b882749e597bcd62385f368fb', '', '', '删除菜单', '', '', '', 300, 3, '1002003', 'sys.menu.delete_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('f1ef824156c0402c90189d58afb1613e', '8231a369712e4f8f8ac09fce232cd034', '', '', '删除', '', '', '', 300, 3, '1002003', 'sys.temp.file.remove', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('cea01dcde9b24b5a8686bdc33c438cd7', '140c9ed43ef54542bbcdde8a5d928400', '', '', '删除账号', '', '', '', 300, 3, '1002003', 'sys.user.delete_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('c55de3135b864579bda79c279f4129a9', 'c4896e8735a745bda9b47ecaf50f46f2', '', '', '删除', '', '', '', 300, 3, '1002003', 'sys.file.remove', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('3ba9407560a1490583fefa10b22bc74f', '8354d626cc65487594a7c38e98de1bad', '', '', '删除', '', '', '', 300, 3, '1002003', 'sys.dept.remove', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('3f555e4a01174a1d9b29be439668e32f', '0444cd2c01584f0687264b6205536691', '', '', '删除', '', '', '', 300, 3, '1002003', 'sys.data.role.remove', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('445b73dda9a34ad681d2705a7abcf2f6', 'c6dd479d5b304731be403d7551c60d70', '', '', '删除角色', '', '', '', 300, 3, '1002003', 'sys.role.delete_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('9830d86487184961b90fc527c9604720', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', '删除字典类型', '', '', '', 300, 3, '1002003', 'sys.dict.delete_type_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('8d0b8b57a58e41a5a5e840cc2b3703f4', '9e731ff422184fc1be2022c5c985735e', '', '', '删除', '', '', '', 300, 3, '1002003', 'sys.client.remove', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('5b5fb3748c6a4ed5a4dda3877508c3a7', 'c6dd479d5b304731be403d7551c60d70', '', '', '设置权限', '', '', '', 400, 3, '1002003', 'sys.role.setting_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('ee36ad68586e42fa8a896215c544cb76', '99c2ee7b882749e597bcd62385f368fb', '', '', 'SQL按钮', '', '', '', 400, 3, '1002003', 'sys.menu.sql_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('6e25a716c1a646009a9be90b16f0a682', '140c9ed43ef54542bbcdde8a5d928400', '', '', '设置角色', '', '', '', 400, 3, '1002003', 'sys.user.role_set_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('81647226a2d047e8ab0b70472350ee69', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', '新增字典', '', '', '', 400, 3, '1002003', 'sys.dict.add_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('97f11d74c98047ba80f011a3da9d882c', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', '编辑字典', '', '', '', 500, 3, '1002003', 'sys.dict.update_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('330a1a0a857c4ad1a95327db5134e420', '140c9ed43ef54542bbcdde8a5d928400', '', '', '解锁', '', '', '', 500, 3, '1002003', 'sys.user.unlock_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('e91eeaea8f1546d3921839469fe247b6', '140c9ed43ef54542bbcdde8a5d928400', '', '', '重置密码', '', '', '', 600, 3, '1002003', 'sys.user_resetPwd', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('1a86a9d2b3ca49439277fff9f499c7cd', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', '删除字典', '', '', '', 600, 3, '1002003', 'sys.dict.delete_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('686a5522b0334d4da51aa15b3fd1a303', '140c9ed43ef54542bbcdde8a5d928400', '', '', '设置部门', '', '', '', 700, 3, '1002003', 'sys.user.dept_set_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('7a4544831af34e69aa73148bf84b9924', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', 'SQL按钮', '', '', '', 700, 3, '1002003', 'sys.dict.sql_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('30942929802f41cc850722c78db089e7', '140c9ed43ef54542bbcdde8a5d928400', '', '', '设置数据角色', '', '', '', 800, 3, '1002003', 'sys.user.data_role_set_btn', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('da1b46db642f42978f83ed5eb34870ce', '0', '/toolbox', 'toolbox', '工具箱', 'Briefcase', '', '', 200, 1, '1002001', '', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('0e529e8a9dbf450898b695e051c36d48', 'da1b46db642f42978f83ed5eb34870ce', '/toolbox/generator', 'generator', '代码生成', 'Brush', '/toolbox/generator/index', '', 100, 2, '1002002', 'generator.list', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('b5ce6412c26447348a7267de3ea11a21', '0e529e8a9dbf450898b695e051c36d48', '', '', '导入按钮', '', '', '', 100, 3, '1002003', 'generator.import', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('3d7eed8398d3457c897b2e8bf838e9c6', '0e529e8a9dbf450898b695e051c36d48', '', '', '编辑按钮', '', '', '', 200, 3, '1002003', 'generator.update', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('310d02bb121645d1b7a7f949f48c981b', '0e529e8a9dbf450898b695e051c36d48', '', '', '生成按钮', '', '', '', 300, 3, '1002003', 'generator.generator', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('2d6b78ad03de4cf1a3899f25cd7fe0ee', '0e529e8a9dbf450898b695e051c36d48', '', '', '删除按钮', '', '', '', 400, 3, '1002003', 'generator.remove', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('fbdcbcc0ccf547b4b78a4fc2cf303236', '0e529e8a9dbf450898b695e051c36d48', '', '', 'zip下载按钮', '', '', '', 500, 3, '1002003', 'generator.zip', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('012efc4ef8d24304a8562534f319524a', '0e529e8a9dbf450898b695e051c36d48', '', '', '预览按钮', '', '', '', 600, 3, '1002003', 'generator.preview', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('cb3500315dba4c2d83e4d92edf36dff7', '85b54322630f43a39296488a5e76ba16', '', '', '新增', '', '', '', 100, 1, '1002003', 'teacher.statistics.create', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('7391f12ad51049c2b86d231d39708c71', '85b54322630f43a39296488a5e76ba16', '', '', '修改', '', '', '', 200, 1, '1002003', 'teacher.statistics.update', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('73d312f4fa8949ddba3d9807c0c56f00', '85b54322630f43a39296488a5e76ba16', '', '', '删除', '', '', '', 300, 1, '1002003', 'teacher.statistics.remove', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('85b54322630f43a39296488a5e76ba16', '0', '/teacher/teacherStatistics', 'TeacherStatisticsView', '教师统计', 'svg-org', '/teacher/teacherStatistics/index', '', 300, 1, '1002002', 'teacher.statistics.query_table', 'F', 'T', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('91ccb13b5c174583803a4c492a5dfdb6', '85b54322630f43a39296488a5e76ba16', '', '', '导入', '', '', '', 400, 1, '1002003', 'teacher.statistics.import', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`)VALUES ('8061d8e79be744bf91b7b438f8e8e887', '85b54322630f43a39296488a5e76ba16', '', '', '导出', '', '', '', 500, 1, '1002003', 'teacher.statistics.export', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); + +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (1, '超级管理员', '', 'F', '2024-05-10 21:28:31', '2025-04-24 15:45:53', NULL, NULL, 'T', 'admin'); +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (2, '字典管理', '', 'F', '2024-05-10 21:52:39', '2025-04-24 15:45:53', NULL, NULL, 'F', 'dict_menu'); +INSERT IGNORE INTO `sys_role` (`id`, `role_name`, `remark`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `is_lock`, `permissions`) VALUES (3, '教师统计', '', 'F', '2024-05-10 21:53:15', '2025-04-24 15:45:53', NULL, NULL, 'F', 'teacher_statics_menu'); + +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (1, '88b2e5def2ff474fa8bf3537d4a2fe5b', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (2, '140c9ed43ef54542bbcdde8a5d928400', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (3, '0f98b89c67e54cb0bcff2b56aa98832f', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (4, '8255bac5eae748a0a8500167963b3e00', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (5, 'cea01dcde9b24b5a8686bdc33c438cd7', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (6, '6e25a716c1a646009a9be90b16f0a682', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (7, '330a1a0a857c4ad1a95327db5134e420', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (8, 'e91eeaea8f1546d3921839469fe247b6', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (9, '686a5522b0334d4da51aa15b3fd1a303', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (10, 'c6dd479d5b304731be403d7551c60d70', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (11, 'df2894b4c06e47cab84142d81edc494d', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (12, '0933b165ffc14d558e8de43ccb6687f6', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (13, '445b73dda9a34ad681d2705a7abcf2f6', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (14, '5b5fb3748c6a4ed5a4dda3877508c3a7', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (15, '99c2ee7b882749e597bcd62385f368fb', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (16, '9338bf2f57984825bc227bb618f9db81', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (17, '05194ef5fa7a4a308a44f6f5c6791c3a', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (18, 'fa0c65ad783d4bf9b919a6db02ef1428', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (19, 'ee36ad68586e42fa8a896215c544cb76', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (20, 'dcb6aabcd910469ebf3efbc7e43282d4', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (21, '4f39ef0fd2f748f6ab7d6d20d98bc4af', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (22, '818cc6e1889d46579525ad8ab921eeb8', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (23, '9830d86487184961b90fc527c9604720', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (24, '81647226a2d047e8ab0b70472350ee69', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (25, '97f11d74c98047ba80f011a3da9d882c', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (26, '1a86a9d2b3ca49439277fff9f499c7cd', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (27, '29d33eba6b73420287d8f7e64aea62b3', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (28, 'ede76f5e60b640aa9de2ba7216b90ceb', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (29, '3a54d488132b4331bf3cd5e6d86ffcf4', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (30, 'b428eba3f9a34025a46c394df5390b88', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (31, '9e731ff422184fc1be2022c5c985735e', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (32, '6c46fd01faf042fc9dd4a9c9b9ef2c5a', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (33, '5b33ac3d630543d09d1388fae4d13fc0', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (34, '8d0b8b57a58e41a5a5e840cc2b3703f4', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (35, '8354d626cc65487594a7c38e98de1bad', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (36, '8fd6721941494fd5bbe16bec82b235be', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (37, '006bdbacd71a481f88b6acf895529acd', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (38, '3ba9407560a1490583fefa10b22bc74f', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (39, '85b54322630f43a39296488a5e76ba16', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (40, 'cb3500315dba4c2d83e4d92edf36dff7', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (41, '7391f12ad51049c2b86d231d39708c71', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (42, '73d312f4fa8949ddba3d9807c0c56f00', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (43, '91ccb13b5c174583803a4c492a5dfdb6', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (44, '8061d8e79be744bf91b7b438f8e8e887', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (45, 'da1b46db642f42978f83ed5eb34870ce', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (46, '0e529e8a9dbf450898b695e051c36d48', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (47, 'b5ce6412c26447348a7267de3ea11a21', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (48, '3d7eed8398d3457c897b2e8bf838e9c6', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (49, '310d02bb121645d1b7a7f949f48c981b', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (50, '2d6b78ad03de4cf1a3899f25cd7fe0ee', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (51, 'fbdcbcc0ccf547b4b78a4fc2cf303236', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (52, '012efc4ef8d24304a8562534f319524a', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (53, 'dcb6aabcd910469ebf3efbc7e43282d4', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (54, '4f39ef0fd2f748f6ab7d6d20d98bc4af', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (55, '818cc6e1889d46579525ad8ab921eeb8', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (56, '9830d86487184961b90fc527c9604720', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (57, '81647226a2d047e8ab0b70472350ee69', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (58, '97f11d74c98047ba80f011a3da9d882c', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (59, '1a86a9d2b3ca49439277fff9f499c7cd', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (60, '88b2e5def2ff474fa8bf3537d4a2fe5b', 2); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (61, '85b54322630f43a39296488a5e76ba16', 3); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (62, 'cb3500315dba4c2d83e4d92edf36dff7', 3); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (63, '7391f12ad51049c2b86d231d39708c71', 3); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (64, '73d312f4fa8949ddba3d9807c0c56f00', 3); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (65, '91ccb13b5c174583803a4c492a5dfdb6', 3); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (66, '8061d8e79be744bf91b7b438f8e8e887', 3); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (67, '30942929802f41cc850722c78db089e7', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (68, '0444cd2c01584f0687264b6205536691', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (69, '8d92cf6f2f3248569d5dd6cb6b958d7c', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (70, 'f42b249ccfd44fdcbc2dba48a308c1f6', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (71, '3f555e4a01174a1d9b29be439668e32f', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (72, '7a4544831af34e69aa73148bf84b9924', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (73, 'c4896e8735a745bda9b47ecaf50f46f2', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (74, '2868079355ce4b6c985b1b746dbb0952', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (75, '49c75878b4d445f8be5f69e21e18b70d', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (76, 'c55de3135b864579bda79c279f4129a9', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (77, '8231a369712e4f8f8ac09fce232cd034', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (78, 'e931c84b8bc945a7b6ba2d58c8a93afc', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (79, '87a26b76daad47c2a12c470605563c4a', 1); +INSERT IGNORE INTO `sys_role_menu` (`id`, `menu_id`, `role_id`) VALUES (80, 'f1ef824156c0402c90189d58afb1613e', 1); + +INSERT IGNORE INTO `sys_temp_file` (`id`, `sys_file_id`, `temp_name`, `url`, `remark`, `del_flag`, `create_id`, `create_time`, `update_id`, `update_time`) VALUES (1, 98, '教师统计模板.xlsx', 'https://minioapi.szadmin.cn/test/tmp/20241216/教师统计 (203323.951).xlsx', '', 'F', 1, '2024-12-16 20:33:12', 1, '2024-12-16 20:33:36'); + +INSERT IGNORE INTO `sys_temp_file_history` (`id`, `sys_temp_file_id`, `sys_file_id`, `temp_name`, `url`, `remark`, `create_id`, `create_time`, `update_id`, `update_time`) VALUES (1, 1, 97, '教师统计模板.xlsx', 'https://minioapi.szadmin.cn/test/tmp/20241216/教师统计 (43) (203252.669).xlsx', '', 1, '2024-12-16 20:33:12', NULL, NULL); +INSERT IGNORE INTO `sys_temp_file_history` (`id`, `sys_temp_file_id`, `sys_file_id`, `temp_name`, `url`, `remark`, `create_id`, `create_time`, `update_id`, `update_time`) VALUES (2, 1, 98, '教师统计模板.xlsx', 'https://minioapi.szadmin.cn/test/tmp/20241216/教师统计 (203323.951).xlsx', '', 1, '2024-12-16 20:33:36', NULL, NULL); + +INSERT IGNORE INTO `sys_user` (`id`, `username`, `pwd`, `phone`, `nickname`, `sex`, `birthday`, `logo`, `age`, `id_card`, `email`, `account_status_cd`, `user_tag_cd`, `last_login_time`, `create_time`, `update_time`, `del_flag`, `create_id`, `update_id`) VALUES (1, 'admin', '$2a$10$lv0HmNLnLrKzfzrFNWc.ku3MFBM5.XsPvTdbz71gLogv.mSbvDN5S', '19988887777', '系统管理员', 1, '2022-01-01', 'https://minioapi.szadmin.cn/test/user/20241216/微信图片_20240420160033.jpg', 1, '', '', '1000001', '1001002', '2024-02-02 13:36:04', '2023-08-18 11:15:10', '2025-04-24 15:45:52', 'F', NULL, NULL); +INSERT IGNORE INTO `sys_user` (`id`, `username`, `pwd`, `phone`, `nickname`, `sex`, `birthday`, `logo`, `age`, `id_card`, `email`, `account_status_cd`, `user_tag_cd`, `last_login_time`, `create_time`, `update_time`, `del_flag`, `create_id`, `update_id`) VALUES (2, 'user', '$2a$10$Km4pU/DdW/.LXRYgR446S.HCdcjIHkp7uFisXtCVoaXyXfveBHjlO', NULL, '测试用户', 1, '2024-01-01', NULL, 0, NULL, NULL, '1000001', '1001003', NULL, '2024-05-09 21:50:02', '2024-05-10 22:30:54', 'F', NULL, NULL); +INSERT IGNORE INTO `sys_user` (`id`, `username`, `pwd`, `phone`, `nickname`, `sex`, `birthday`, `logo`, `age`, `id_card`, `email`, `account_status_cd`, `user_tag_cd`, `last_login_time`, `create_time`, `update_time`, `del_flag`, `create_id`, `update_id`) VALUES (3, 'test1', '$2a$10$QXRq4OGoHahxlXbULJxIXe0RgOCdW7C716bes9qh4gopIVROAVxXW', '', '测试1-本部及以下', NULL, '', '', 0, '', '', '1000001', '1001003', NULL, '2024-07-08 08:47:31', '2024-07-08 09:17:41', 'F', 1, 1); +INSERT IGNORE INTO `sys_user` (`id`, `username`, `pwd`, `phone`, `nickname`, `sex`, `birthday`, `logo`, `age`, `id_card`, `email`, `account_status_cd`, `user_tag_cd`, `last_login_time`, `create_time`, `update_time`, `del_flag`, `create_id`, `update_id`) VALUES (4, 'test2', '$2a$10$uMZA6KiYtvnLVHSukXiB2ufvKdp827nO/6p6jWn1ydEYoLA0kgPqK', '', '测试2-仅本部', NULL, '', '', 0, '', '', '1000001', '1001003', NULL, '2024-07-08 08:47:41', '2024-07-08 09:17:11', 'F', 1, 1); +INSERT IGNORE INTO `sys_user` (`id`, `username`, `pwd`, `phone`, `nickname`, `sex`, `birthday`, `logo`, `age`, `id_card`, `email`, `account_status_cd`, `user_tag_cd`, `last_login_time`, `create_time`, `update_time`, `del_flag`, `create_id`, `update_id`) VALUES (5, 'test3', '$2a$10$UWKoQfMAFxk/qdTI4vQLgOjho5xtjNJhdbHmJNoYuNZkuOq2WCoZm', '', '测试3-仅本人', NULL, '', '', 0, '', '', '1000001', '1001003', NULL, '2024-07-08 08:47:50', '2024-07-08 09:17:56', 'F', 1, 1); +INSERT IGNORE INTO `sys_user` (`id`, `username`, `pwd`, `phone`, `nickname`, `sex`, `birthday`, `logo`, `age`, `id_card`, `email`, `account_status_cd`, `user_tag_cd`, `last_login_time`, `create_time`, `update_time`, `del_flag`, `create_id`, `update_id`) VALUES (6, 'test4', '$2a$10$bCgJMtfSPhn6Mvn2AGx5z.NDVHXBvxl7/XEvlH52wbBpAWkLvwVVe', '', '测试4-自定义', NULL, '', '', 0, '', '', '1000001', '1001003', NULL, '2024-07-08 08:47:58', '2024-07-08 09:18:33', 'F', 1, 1); + +INSERT IGNORE INTO `sys_user_data_role` (`id`, `role_id`, `user_id`) VALUES (1, 2, 4); +INSERT IGNORE INTO `sys_user_data_role` (`id`, `role_id`, `user_id`) VALUES (2, 1, 3); +INSERT IGNORE INTO `sys_user_data_role` (`id`, `role_id`, `user_id`) VALUES (3, 3, 5); +INSERT IGNORE INTO `sys_user_data_role` (`id`, `role_id`, `user_id`) VALUES (4, 4, 6); + +INSERT IGNORE INTO `sys_user_dept` (`id`, `dept_id`, `user_id`) VALUES (1, 4, 2); +INSERT IGNORE INTO `sys_user_dept` (`id`, `dept_id`, `user_id`) VALUES (2, 4, 3); +INSERT IGNORE INTO `sys_user_dept` (`id`, `dept_id`, `user_id`) VALUES (3, 15, 4); +INSERT IGNORE INTO `sys_user_dept` (`id`, `dept_id`, `user_id`) VALUES (4, 15, 5); +INSERT IGNORE INTO `sys_user_role` (`id`, `role_id`, `user_id`) VALUES (1, 1, 1); +INSERT IGNORE INTO `sys_user_role` (`id`, `role_id`, `user_id`) VALUES (2, 2, 2); +INSERT IGNORE INTO `sys_user_role` (`id`, `role_id`, `user_id`) VALUES (3, 3, 2); +INSERT IGNORE INTO `sys_user_role` (`id`, `role_id`, `user_id`) VALUES (4, 3, 3); +INSERT IGNORE INTO `sys_user_role` (`id`, `role_id`, `user_id`) VALUES (5, 3, 4); +INSERT IGNORE INTO `sys_user_role` (`id`, `role_id`, `user_id`) VALUES (6, 3, 5); +INSERT IGNORE INTO `sys_user_role` (`id`, `role_id`, `user_id`) VALUES (7, 3, 6); \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.0-beta/001_sys_message.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.0-beta/001_sys_message.sql new file mode 100644 index 0000000..880ef9c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.0-beta/001_sys_message.sql @@ -0,0 +1,41 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250424_1750 +CREATE TABLE IF NOT EXISTS `sys_message` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '消息ID', + `message_type_cd` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '消息类型', + `sender_id` bigint NOT NULL COMMENT '发送人ID', + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '消息标题', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '消息内容', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '删除标识', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `create_id` bigint DEFAULT NULL COMMENT '创建人 ID', + `update_id` bigint DEFAULT NULL COMMENT '更新人 ID', + `menu_router` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单路由地址,冗余', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='消息管理'; + +CREATE TABLE IF NOT EXISTS `sys_message_user` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `message_id` bigint NOT NULL COMMENT '消息ID', + `receiver_id` bigint NOT NULL COMMENT '接收人ID', + `is_read` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '是否已读', + `read_time` datetime DEFAULT NULL COMMENT '阅读时间', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '删除标识', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='消息接收用户表'; + + +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1008, '消息类型', 'message_type', 'F', 'T', 'F', '系统消息的类型(待办、通知等)', '2025-04-21T15:22:15', NULL, NULL, NULL, NULL, NULL, 'system'); + +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1008001, '1008', '待办', 'todo', 1, 'warning', '', 'F', 'T', 'F', '2025-04-21T15:22:45', NULL, NULL, NULL, NULL, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1008002, '1008', '消息', 'msg', 2, 'success', '', 'F', 'T', 'F', '2025-04-21T15:23:01', NULL, NULL, NULL, NULL, NULL); + +INSERT IGNORE INTO `sys_message` (`id`, `message_type_cd`, `sender_id`, `title`, `content`, `del_flag`, `create_time`, `update_time`, `create_id`, `update_id`, `menu_router`) VALUES (1, 'msg', 1, '欢迎使用sz-admin', '如果喜欢这个项目或支持作者,欢迎Star、Fork、Watch 一键三连 🚀!!', 'F', '2025-04-24 16:14:25', '2025-04-24 16:14:25', 1, 1, NULL); +INSERT IGNORE INTO `sys_message_user` (`id`, `message_id`, `receiver_id`, `is_read`, `read_time`, `del_flag`) VALUES (1, 1, 1, 'F', NULL, 'F'); +INSERT IGNORE INTO `sys_message_user` (`id`, `message_id`, `receiver_id`, `is_read`, `read_time`, `del_flag`) VALUES (2, 1, 2, 'F', NULL, 'F'); +INSERT IGNORE INTO `sys_message_user` (`id`, `message_id`, `receiver_id`, `is_read`, `read_time`, `del_flag`) VALUES (3, 1, 3, 'F', NULL, 'F'); +INSERT IGNORE INTO `sys_message_user` (`id`, `message_id`, `receiver_id`, `is_read`, `read_time`, `del_flag`) VALUES (4, 1, 4, 'F', NULL, 'F'); +INSERT IGNORE INTO `sys_message_user` (`id`, `message_id`, `receiver_id`, `is_read`, `read_time`, `del_flag`) VALUES (5, 1, 5, 'F', NULL, 'F'); +INSERT IGNORE INTO `sys_message_user` (`id`, `message_id`, `receiver_id`, `is_read`, `read_time`, `del_flag`) VALUES (6, 1, 6, 'F', NULL, 'F'); \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.1-beta/001_sys_menu.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.1-beta/001_sys_menu.sql new file mode 100644 index 0000000..012281f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.1-beta/001_sys_menu.sql @@ -0,0 +1,14 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250508_2222 +UPDATE `sys_menu` SET `name` = 'AccountManage' WHERE `id` = '140c9ed43ef54542bbcdde8a5d928400'; +UPDATE `sys_menu` SET `name` = 'RoleManage' WHERE `id` = 'c6dd479d5b304731be403d7551c60d70'; +UPDATE `sys_menu` SET `name` = 'MenuManage' WHERE `id` = '99c2ee7b882749e597bcd62385f368fb'; +UPDATE `sys_menu` SET `name` = 'DictManage' WHERE `id` = 'dcb6aabcd910469ebf3efbc7e43282d4'; +UPDATE `sys_menu` SET `name` = 'ConfigManage' WHERE `id` = '29d33eba6b73420287d8f7e64aea62b3'; +UPDATE `sys_menu` SET `name` = 'ClientManageView' WHERE `id` = '9e731ff422184fc1be2022c5c985735e'; +UPDATE `sys_menu` SET `name` = 'SysDeptView' WHERE `id` = '8354d626cc65487594a7c38e98de1bad'; +UPDATE `sys_menu` SET `name` = 'SysDataRoleView' WHERE `id` = '0444cd2c01584f0687264b6205536691'; +UPDATE `sys_menu` SET `name` = 'SysFileView' WHERE `id` = 'c4896e8735a745bda9b47ecaf50f46f2'; +UPDATE `sys_menu` SET `name` = 'SysTempFileView' WHERE `id` = '8231a369712e4f8f8ac09fce232cd034'; +UPDATE `sys_menu` SET `name` = 'Generator' WHERE `id` = '0e529e8a9dbf450898b695e051c36d48'; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.2-beta/001_system.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.2-beta/001_system.sql new file mode 100644 index 0000000..9ed156a --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.2-beta/001_system.sql @@ -0,0 +1,5 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250526_2022 +--comment: 增加eTag长度,修复文件上传时eTag过长导致的错误 +ALTER TABLE `sys_file` MODIFY COLUMN `e_tag` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'eTag标识'; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.3-beta/001_system.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.3-beta/001_system.sql new file mode 100644 index 0000000..571a050 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.3-beta/001_system.sql @@ -0,0 +1,15 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250603_1400 +--comment: 更新 sys_temp_file 表,将url varchar 改为 json数组 +-- 1️⃣ 新增临时 JSON 数组字段 +ALTER TABLE sys_temp_file ADD COLUMN url_json JSON DEFAULT NULL COMMENT '地址(JSON数组格式)'; + +-- 2️⃣ 将原有 varchar(url) 数据更新为 JSON 数组格式,例如 ["原url"] +UPDATE sys_temp_file SET url_json = JSON_ARRAY(url); + +-- 3️⃣ 删除原来的 varchar(url) 字段 +ALTER TABLE sys_temp_file DROP COLUMN url; + +-- 4️⃣ 将临时字段 url_json 改名为 url +ALTER TABLE sys_temp_file CHANGE COLUMN url_json url JSON DEFAULT NULL COMMENT '地址(JSON数组格式)'; diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.4-beta/001_system.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.4-beta/001_system.sql new file mode 100644 index 0000000..4f1c7cb --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.4-beta/001_system.sql @@ -0,0 +1,6 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250614_1621 +--comment: 修正菜单路径拼写错误 +UPDATE `sys_menu` SET `path` = '/system/menuManage' WHERE `path` = '/system/menuMange'; +UPDATE `sys_menu` SET `component` = '/system/menuManage/index' WHERE `component` = '/system/menuMange/index'; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.6-beta/001_system.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.6-beta/001_system.sql new file mode 100644 index 0000000..d45cd38 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.2.6-beta/001_system.sql @@ -0,0 +1,42 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250717_1321 +--comment: 新增部门角色关联数据库表 +CREATE TABLE IF NOT EXISTS `sys_dept_role` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '部门-角色关联ID', + `dept_id` bigint(20) NULL DEFAULT NULL COMMENT '部门ID (sys_dept_id)', + `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID(sys_role_id)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统部门-角色关联表' ROW_FORMAT = DYNAMIC; + +--changeset 升职哦(sz):20250725_1327 +--comment: 新增登陆日志数据库表 +CREATE TABLE IF NOT EXISTS `sys_login_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '登陆ID', + `del_flag` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'F' COMMENT '删除标识', + `user_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户名', + `login_status` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登陆状态', + `login_time` datetime NULL DEFAULT NULL COMMENT '登陆时间', + `ip_address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登陆ip地址', + `login_location` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登陆地点', + `browser` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '浏览器类型', + `os` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '操作系统', + `msg` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '提示消息', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE + ) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '登陆日志表' ROW_FORMAT = DYNAMIC; + +--changeset 升职哦(sz):20250726_0927 +--comment: 新增登陆日志菜单 +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `create_time`, `update_time`, `create_id`, `update_id`, `del_flag`, `delete_id`, `delete_time`, `use_data_scope`) VALUES ('191878090b294ec5892a68081dd91428', '88b2e5def2ff474fa8bf3537d4a2fe5b', '/system/sysLoginLog', 'SysLoginLogView', '登陆日志', 'Location', '/system/sysLoginLog/index', '', 1100, 2, '1002002', 'sys.login.log.query_table', 'F', 'T', 'F', 'F', 'F', 'F', NULL, NULL, NULL, NULL, 'F', NULL, NULL, 'F'); +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `create_time`, `update_time`, `create_id`, `update_id`, `del_flag`, `delete_id`, `delete_time`, `use_data_scope`) VALUES ('52fb3db605334671bb0dfe4f50cb1147', '191878090b294ec5892a68081dd91428', '', '', '导出', '', '', '', 100, 3, '1002003', 'sys.login.log.export', 'F', 'F', 'F', 'F', 'F', 'F', NULL, NULL, NULL, NULL, 'F', NULL, NULL, 'F'); + +--changeset 升职哦(sz):20250729_0304 +--comment: 新增登陆状态字典 +INSERT IGNORE INTO `sys_dict_type` (`id`, `type_name`, `type_code`, `is_lock`, `is_show`, `del_flag`, `remark`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`, `type`) VALUES (1009, '登陆状态', 'login_status', 'F', 'T', 'F', '', '2025-07-29 22:49:03', '2025-07-29 22:49:03', NULL, 1, 1, NULL, 'system'); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1009002, 1009, '登陆失败', '', 1, 'danger', '', 'F', 'T', 'F', '2025-07-29 22:49:34', '2025-07-29 22:49:34', NULL, 1, 1, NULL); +INSERT IGNORE INTO `sys_dict` (`id`, `sys_dict_type_id`, `code_name`, `alias`, `sort`, `callback_show_style`, `remark`, `is_lock`, `is_show`, `del_flag`, `create_time`, `update_time`, `delete_time`, `create_id`, `update_id`, `delete_id`) VALUES (1009001, 1009, '登陆成功', '', 1, 'success', '', 'F', 'T', 'F', '2025-07-29 22:49:22', '2025-07-29 22:49:22', NULL, 1, 1, NULL); + +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('191878090b294ec5892a68081dd91428', 1); +INSERT IGNORE INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('52fb3db605334671bb0dfe4f50cb1147', 1); + diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/001_system.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/001_system.sql new file mode 100644 index 0000000..658d620 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/001_system.sql @@ -0,0 +1,86 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250920_1414 +--comment: 更新菜单权限标识 + +-- =============================================== +-- ⚠️【破坏性更新】请谨慎升级! +-- 菜单路由会发生改变 +-- =============================================== +-- 账号管理 +UPDATE sys_menu SET permissions = '', path = '/system/account' WHERE id = '140c9ed43ef54542bbcdde8a5d928400'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('0bef80d81a264f689d091613053c659e', '140c9ed43ef54542bbcdde8a5d928400', '', '', '查询账号', '', '', '', 99, 3, '1002003', 'sys.user.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 角色管理 +UPDATE sys_menu SET permissions = '', path = '/system/role' WHERE id = 'c6dd479d5b304731be403d7551c60d70'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('abecbec6abe74023abaa653f827a3b0f', 'c6dd479d5b304731be403d7551c60d70', '', '', '查询角色', '', '', '', 99, 3, '1002003', 'sys.role.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 菜单管理 +UPDATE sys_menu SET permissions = '', path = '/system/menu' WHERE id = '99c2ee7b882749e597bcd62385f368fb'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('9dfeebc408e1490e88bf10db3b5e1239', '99c2ee7b882749e597bcd62385f368fb', '', '', '查询菜单', '', '', '', 99, 3, '1002003', 'sys.menu.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 字典管理 +UPDATE sys_menu SET permissions = '', path = '/system/dict' WHERE id = 'dcb6aabcd910469ebf3efbc7e43282d4'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('d90946bc9ed54e598e3c4471dbd1f496', 'dcb6aabcd910469ebf3efbc7e43282d4', '', '', '查询字典', '', '', '', 99, 3, '1002003', 'sys.dict.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 参数管理 +UPDATE sys_menu SET permissions = '', path = '/system/conf' WHERE id = '29d33eba6b73420287d8f7e64aea62b3'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('bef8f1330490494f924314eec9687055', '29d33eba6b73420287d8f7e64aea62b3', '', '', '查询参数', '', '', '', 99, 3, '1002003', 'sys.config.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 客户端管理 +UPDATE sys_menu SET permissions = '', path = '/system/client' WHERE id = '9e731ff422184fc1be2022c5c985735e'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('6307bd1221fb474b8c8777afaed4440f', '9e731ff422184fc1be2022c5c985735e', '', '', '查询', '', '', '', 99, 3, '1002003', 'sys.client.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 部门管理 +UPDATE sys_menu SET permissions = '', path = '/system/dept' WHERE id = '8354d626cc65487594a7c38e98de1bad'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('31dca47db78f4c14b9cfe65226061b65', '8354d626cc65487594a7c38e98de1bad', '', '', '查询', '', '', '', 99, 3, '1002003', 'sys.dept.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 数据权限 +UPDATE sys_menu SET permissions = '', path = '/system/data' WHERE id = '0444cd2c01584f0687264b6205536691'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('2ae05bd0afaa4c6dbc173bf1dd0da2cf', '0444cd2c01584f0687264b6205536691', '', '', '查询', '', '', '', 99, 3, '1002003', 'sys.data.role.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 文件管理 +UPDATE sys_menu SET permissions = '', path = '/system/file' WHERE id = 'c4896e8735a745bda9b47ecaf50f46f2'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('62dd478ed2f54792b08ed9202e73d2cf', 'c4896e8735a745bda9b47ecaf50f46f2', '', '', '查询', '', '', '', 99, 3, '1002003', 'sys.file.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 模板文件管理 +UPDATE sys_menu SET permissions = '', path = '/system/fileTemp' WHERE id = '8231a369712e4f8f8ac09fce232cd034'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('47e5805374bc44a2831126676b8c78dd', '8231a369712e4f8f8ac09fce232cd034', '', '', '查询', '', '', '', 99, 3, '1002003', 'sys.temp.file.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); +-- 登录日志 +UPDATE sys_menu SET permissions = '' WHERE id = '191878090b294ec5892a68081dd91428'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('c555243b02814270948a240e8d2d3408', '191878090b294ec5892a68081dd91428', '', '', '查询', '', '', '', 99, 3, '1002003', 'sys.login.log.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); + +UPDATE sys_menu SET permissions = '' WHERE id = '0e529e8a9dbf450898b695e051c36d48'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('765d139874424930b0a672128712de9b', '0e529e8a9dbf450898b695e051c36d48', '', '', '查询', '', '', '', 99, 3, '1002003', 'generator.list', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); + +UPDATE sys_menu SET permissions = '' WHERE id = '85b54322630f43a39296488a5e76ba16'; +INSERT IGNORE INTO `sys_menu` (`id`, `pid`, `path`, `name`, `title`, `icon`, `component`, `redirect`, `sort`, `deep`, `menu_type_cd`, `permissions`, `is_hidden`, `has_children`, `is_link`, `is_full`, `is_affix`, `is_keep_alive`, `del_flag`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', '85b54322630f43a39296488a5e76ba16', '', '', '查询', '', '', '', 99, 2, '1002003', 'teacher.statistics.query_table', 'F', 'F', 'F', 'F', 'F', 'F', 'F'); + +--changeset 升职哦(sz):20250920_1520 +--comment: 更新角色菜单关联 +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('0bef80d81a264f689d091613053c659e', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('abecbec6abe74023abaa653f827a3b0f', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('9dfeebc408e1490e88bf10db3b5e1239', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('d90946bc9ed54e598e3c4471dbd1f496', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('bef8f1330490494f924314eec9687055', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('6307bd1221fb474b8c8777afaed4440f', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('31dca47db78f4c14b9cfe65226061b65', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('2ae05bd0afaa4c6dbc173bf1dd0da2cf', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('62dd478ed2f54792b08ed9202e73d2cf', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('47e5805374bc44a2831126676b8c78dd', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('c555243b02814270948a240e8d2d3408', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('765d139874424930b0a672128712de9b', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', 1); +INSERT INTO `sys_role_menu` (`menu_id`, `role_id`) VALUES ('ab1ac16c617d41979472ebe433c1f8e4', 3); + +--changeset 升职哦(sz):20251030_1925 +--comment: 修改sys_role_menu表, 增加字段 +ALTER TABLE `sys_role_menu` ADD COLUMN `permission_type` enum('menu','scope') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'menu' COMMENT '权限类型(功能权限;数据权限)'; +ALTER TABLE `sys_role_menu` ADD COLUMN `data_scope_cd` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '数据权限范围,data_scope字典'; +UPDATE `sys_role_menu` SET `permission_type` = 'menu' WHERE `permission_type` IS NULL; + +--changeset 升职哦(sz):20251031_1930 +ALTER TABLE `sys_data_role_relation` ADD COLUMN `menu_id` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单id'; + +--changeset 升职哦(sz):20251103_2312 +UPDATE `sys_menu` SET `is_hidden` = 'T' WHERE `id` = '0444cd2c01584f0687264b6205536691'; +UPDATE `sys_menu` SET `use_data_scope` = 'T' WHERE `pid` IN ( SELECT `id` FROM (SELECT `id` FROM `sys_menu` WHERE `is_hidden` = 'T' AND `menu_type_cd` != '1002003') AS temp); +ALTER TABLE `sys_data_role_menu` COMMENT='系统数据角色-菜单表【废弃, from 2025-v1.3.0】'; +ALTER TABLE `sys_data_role` COMMENT='系统数据角色表【废弃, from 2025-v1.3.0】'; + +--changeset 升职哦(sz):20251104_1933 +INSERT INTO `sys_config` (`config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES ('超级管理员角色权限配置', 'sys.admin.superAdminRoleId', '1', 'T', 1, '2025-11-04 13:06:45', 1, '2025-11-04 16:32:25', '超管权限,指定的生效角色 ID。'); +UPDATE `sys_dict` SET `sys_dict_type_id` = 1001, `code_name` = '测试用户', `alias` = '', `sort` = 3, `callback_show_style` = 'warning', `remark` = '', `is_lock` = 'T', `is_show` = 'T', `del_flag` = 'F', `create_time` = '2023-08-20 16:38:58', `update_time` = '2025-11-05 14:56:22', `delete_time` = NULL, `create_id` = NULL, `update_id` = 1, `delete_id` = NULL WHERE `id` = 1001001; +UPDATE `sys_dict` SET `sys_dict_type_id` = 1001, `code_name` = '超级管理员', `alias` = '', `sort` = 2, `callback_show_style` = 'danger', `remark` = '', `is_lock` = 'T', `is_show` = 'T', `del_flag` = 'F', `create_time` = '2023-08-20 16:39:05', `update_time` = '2025-11-05 14:56:34', `delete_time` = NULL, `create_id` = NULL, `update_id` = 1, `delete_id` = NULL WHERE `id` = 1001002; +UPDATE `sys_dict` SET `sys_dict_type_id` = 1001, `code_name` = '普通用户', `alias` = '', `sort` = 1, `callback_show_style` = 'primary', `remark` = '', `is_lock` = 't', `is_show` = 'T', `del_flag` = 'F', `create_time` = '2023-08-20 16:39:11', `update_time` = '2025-11-05 14:56:39', `delete_time` = NULL, `create_id` = NULL, `update_id` = 1, `delete_id` = NULL WHERE `id` = 1001003; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/002_breaking_change.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/002_breaking_change.sql new file mode 100644 index 0000000..62bdefa --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/002_breaking_change.sql @@ -0,0 +1,20 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20250924_1930 +-- =============================================== +-- ⚠️【破坏性更新】请谨慎升级! +-- 此操作会删除数据,请务必提前备份相关数据! +-- =============================================== +-- 删除 演示数据 +DELETE FROM `sys_file` WHERE id IN (97, 98, 99); +DELETE FROM `sys_temp_file` WHERE id = 1 and sys_file_id = 98; +DELETE FROM `sys_temp_file_history` WHERE sys_temp_file_id = 1; +-- 此改动为修正之前的设计缺陷,将sys_temp_file和sys_temp_file_history的url字段由varchar改为json类型,以支持存储多个文件地址 +ALTER TABLE `sys_temp_file` MODIFY COLUMN `url` json DEFAULT NULL COMMENT '地址(JSON数组对象)'; +ALTER TABLE `sys_temp_file_history` MODIFY COLUMN `url` json DEFAULT NULL COMMENT '地址(JSON数组对象)'; +ALTER TABLE `sys_temp_file` ADD COLUMN alias varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '标识,唯一'; + +--changeset 升职哦(sz):20251020_2250 +INSERT IGNORE INTO `sys_file` (`id`, `filename`, `dir_tag`, `size`, `url`, `create_time`, `object_name`, `context_type`, `e_tag`, `create_id`) VALUES (100, '教师统计模板.xlsx', 'tmp', 9866, 'https://minioapi.szadmin.cn/test/excel/教师统计模板.xlsx', '2025-10-20 22:36:53', 'tmp/20251020/教师统计模板.xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', '8bba8015aa748013cc8295a13637fb3a', 1); +INSERT IGNORE INTO `sys_temp_file` (`id`, `sys_file_id`, `temp_name`, `remark`, `del_flag`, `create_id`, `create_time`, `update_id`, `update_time`, `url`, `alias`) VALUES (2, 100, '教师统计模板.xlsx', '教师统计-导入模板', 'F', 1, '2025-10-20 22:37:22', 1, '2025-10-20 22:37:22', '[{\"url\": \"https://minioapi.szadmin.cn/test/excel/教师统计模板.xlsx\", \"etag\": \"8bba8015aa748013cc8295a13637fb3a\", \"size\": 9866, \"dirTag\": \"tmp\", \"fileId\": 100, \"filename\": \"教师统计模板.xlsx\", \"metaData\": null, \"objectName\": \"excel/教师统计模板.xlsx\", \"contextType\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"}]', 'jstj'); +INSERT IGNORE INTO `sys_temp_file_history` (`id`, `sys_temp_file_id`, `sys_file_id`, `temp_name`, `url`, `remark`, `create_id`, `create_time`, `update_id`, `update_time`) VALUES (3, 2, 100, '教师统计模板.xlsx', '[{\"url\": \"https://minioapi.szadmin.cn/test/excel/教师统计模板.xlsx\", \"etag\": \"8bba8015aa748013cc8295a13637fb3a\", \"size\": 9866, \"dirTag\": \"tmp\", \"fileId\": 100, \"filename\": \"教师统计模板.xlsx\", \"metaData\": null, \"objectName\": \"excel/教师统计模板.xlsx\", \"contextType\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"}]', '教师统计-导入模板', 1, '2025-10-20 22:37:22', 1, '2025-10-20 22:37:22'); \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/003_login.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/003_login.sql new file mode 100644 index 0000000..515e52f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/003_login.sql @@ -0,0 +1,9 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20251016_1914 + +INSERT IGNORE INTO `sys_config` (`config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES ('登录请求次数限制', 'sys.login.requestLimit', '100', 'F', 1, '2025-10-14 16:35:28', 1, '2025-10-15 16:40:34', '一段时间内的登录请求次数限制,根据requestId(Ip + UserAgent)判断;若为 0 则不限制'); +INSERT IGNORE INTO `sys_config` (`config_name`, `config_key`, `config_value`, `is_lock`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES ('登录次数计数周期(分)', 'sys.login.requestCycle', '10', 'F', 1, '2025-10-14 16:36:14', 1, '2025-10-16 16:51:44', '默认10分钟'); + +UPDATE `sys_config` SET `config_name` = '验证码请求次数限制', `config_key` = 'sys.captcha.requestLimit', `config_value` = '100', `is_lock` = 'T', `create_id` = 1, `create_time` = '2025-01-08 22:09:28', `update_id` = 1, `update_time` = '2025-10-16 17:30:09', `remark` = '一段时间内的验证码请求次数上限(0为不限制),默认100次' WHERE `config_key` = 'sys.captcha.requestLimit'; +UPDATE `sys_config` SET `config_name` = '验证码计数周期(分)', `config_key` = 'sys.captcha.requestCycle', `config_value` = '10', `is_lock` = 'T', `create_id` = 1, `create_time` = '2025-01-08 22:13:09', `update_id` = 1, `update_time` = '2025-10-16 17:30:40', `remark` = '默认10(分)' WHERE `config_key` = 'sys.captcha.requestCycle'; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/004_generator.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/004_generator.sql new file mode 100644 index 0000000..a4d3f08 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.0-beta/004_generator.sql @@ -0,0 +1,4 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20251105_2005 +ALTER TABLE `generator_table` ADD COLUMN `btn_data_scope_type` char(1) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否开启数据权限(1 是)' after `btn_permission_type`; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.2-beta/001_generator.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.2-beta/001_generator.sql new file mode 100644 index 0000000..d1cf045 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.2-beta/001_generator.sql @@ -0,0 +1,4 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20251212_1954 +ALTER TABLE `generator_table` ADD COLUMN `window_show_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '窗口展示方式(0 dialog弹窗;1 drawer 抽屉)'; diff --git a/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.2-beta/002_system.sql b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.2-beta/002_system.sql new file mode 100644 index 0000000..0c79112 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/db/changelog/framework/1.3.2-beta/002_system.sql @@ -0,0 +1,12 @@ +--liquibase formatted sql + +--changeset 升职哦(sz):20260112_2114 +ALTER TABLE `sys_config` ADD COLUMN `frontend_visible` enum('T','F') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT 'F' COMMENT '该参数是否需要前端加载、缓存及使用' after `is_lock`; + +--changeset 升职哦(sz):20260116_2025 +INSERT INTO `sys_config` (`config_name`, `config_key`, `config_value`, `is_lock`, `frontend_visible`, `create_id`, `create_time`, `update_id`, `update_time`, `remark`) VALUES ('资源访问模式', 'oss.accessMode', 'private', 'F', 'T', 1, '2026-01-13 09:59:09', 1, '2026-01-16 13:57:52', '用于控制前端资源文件(如 Minio OSS)访问方式。当值为 public 时,前端直接使用数据库中存储的完整资源 URL 进行加载,适用于公开访问的资源;当值为 private 时,前端通过 Minio 获取私有资源的临时授权地址进行加载,适用于需权限验证的私有资源。'); + +--changeset 升职哦(sz):20260116_2215 +UPDATE `sys_config` SET `is_lock` = 'T' WHERE `config_key` = 'oss.accessMode'; +UPDATE `sys_config` SET `is_lock` = 'T' WHERE `config_key` = 'sys.login.requestCycle'; +UPDATE `sys_config` SET `is_lock` = 'T' WHERE `config_key` = 'sys.login.requestLimit'; \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/jar/FFmpegCommandHandler.jar b/sz-service/sz-service-admin/src/main/resources/jar/FFmpegCommandHandler.jar new file mode 100644 index 0000000..1408776 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/jar/FFmpegCommandHandler.jar differ diff --git a/sz-service/sz-service-admin/src/main/resources/jar/examples.jar b/sz-service/sz-service-admin/src/main/resources/jar/examples.jar new file mode 100644 index 0000000..0290e12 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/jar/examples.jar differ diff --git a/sz-service/sz-service-admin/src/main/resources/jar/jna.jar b/sz-service/sz-service-admin/src/main/resources/jar/jna.jar new file mode 100644 index 0000000..7f1f35e Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/jar/jna.jar differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libAudioIntercom.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libAudioIntercom.so new file mode 100644 index 0000000..7971947 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libAudioIntercom.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCAlarm.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCAlarm.so new file mode 100644 index 0000000..5d44b68 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCAlarm.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCCoreDevCfg.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCCoreDevCfg.so new file mode 100644 index 0000000..dbb697b Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCCoreDevCfg.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCDisplay.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCDisplay.so new file mode 100644 index 0000000..5fba43f Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCDisplay.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCGeneralCfgMgr.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCGeneralCfgMgr.so new file mode 100644 index 0000000..6d8ae28 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCGeneralCfgMgr.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCIndustry.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCIndustry.so new file mode 100644 index 0000000..9b78dea Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCIndustry.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCPlayBack.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCPlayBack.so new file mode 100644 index 0000000..dd80c6a Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCPlayBack.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCPreview.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCPreview.so new file mode 100644 index 0000000..487c935 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCPreview.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCVoiceTalk.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCVoiceTalk.so new file mode 100644 index 0000000..a39ec12 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libHCVoiceTalk.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libStreamTransClient.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libStreamTransClient.so new file mode 100644 index 0000000..48c5171 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libStreamTransClient.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libSystemTransform.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libSystemTransform.so new file mode 100644 index 0000000..8b1caaa Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libSystemTransform.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libanalyzedata.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libanalyzedata.so new file mode 100644 index 0000000..81a84e7 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libanalyzedata.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libiconv2.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libiconv2.so new file mode 100644 index 0000000..01999aa Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDKCom/libiconv2.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDK_Log_Switch.xml b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDK_Log_Switch.xml new file mode 100644 index 0000000..8b7e236 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/lib/linux/HCNetSDK_Log_Switch.xml @@ -0,0 +1,12 @@ + + + + 3 + ./SDKLOG/ + true + + + 120 + 1 + + \ No newline at end of file diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libAudioRender.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libAudioRender.so new file mode 100644 index 0000000..a1d5ee4 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libAudioRender.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libHCCore.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libHCCore.so new file mode 100644 index 0000000..a7f8372 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libHCCore.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libNPQos.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libNPQos.so new file mode 100644 index 0000000..0e38ff2 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libNPQos.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libPlayCtrl.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libPlayCtrl.so new file mode 100644 index 0000000..1757406 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libPlayCtrl.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libSuperRender.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libSuperRender.so new file mode 100644 index 0000000..ad2dff5 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libSuperRender.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libcrypto.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libcrypto.so new file mode 100644 index 0000000..a531247 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libcrypto.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libcrypto.so.1.0.0 b/sz-service/sz-service-admin/src/main/resources/lib/linux/libcrypto.so.1.0.0 new file mode 100644 index 0000000..a531247 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libcrypto.so.1.0.0 differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libhcnetsdk.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libhcnetsdk.so new file mode 100644 index 0000000..c9d8ee3 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libhcnetsdk.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libhpr.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libhpr.so new file mode 100644 index 0000000..6edaa0a Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libhpr.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libopenal.so.1 b/sz-service/sz-service-admin/src/main/resources/lib/linux/libopenal.so.1 new file mode 100644 index 0000000..816d8bc Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libopenal.so.1 differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libssl.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libssl.so new file mode 100644 index 0000000..791b72a Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libssl.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/linux/libz.so b/sz-service/sz-service-admin/src/main/resources/lib/linux/libz.so new file mode 100644 index 0000000..b201b47 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/linux/libz.so differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/AudioRender.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/AudioRender.dll new file mode 100644 index 0000000..3bf543e Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/AudioRender.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCCore.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCCore.dll new file mode 100644 index 0000000..fadba3d Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCCore.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDK.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDK.dll new file mode 100644 index 0000000..2b0a138 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDK.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AnalyzeData.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AnalyzeData.dll new file mode 100644 index 0000000..c4298ef Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AnalyzeData.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AudioIntercom.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AudioIntercom.dll new file mode 100644 index 0000000..888d607 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AudioIntercom.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AudioRender.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AudioRender.dll new file mode 100644 index 0000000..3bf543e Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/AudioRender.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCAlarm.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCAlarm.dll new file mode 100644 index 0000000..adf4153 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCAlarm.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCAlarm.lib b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCAlarm.lib new file mode 100644 index 0000000..add03bb Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCAlarm.lib differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCCoreDevCfg.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCCoreDevCfg.dll new file mode 100644 index 0000000..f62213a Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCCoreDevCfg.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCDisplay.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCDisplay.dll new file mode 100644 index 0000000..3ad9fd7 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCDisplay.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCGeneralCfgMgr.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCGeneralCfgMgr.dll new file mode 100644 index 0000000..53838f8 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCGeneralCfgMgr.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCGeneralCfgMgr.lib b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCGeneralCfgMgr.lib new file mode 100644 index 0000000..4d400be Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCGeneralCfgMgr.lib differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCIndustry.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCIndustry.dll new file mode 100644 index 0000000..a4bcec0 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCIndustry.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPlayBack.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPlayBack.dll new file mode 100644 index 0000000..7d43335 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPlayBack.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPreview.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPreview.dll new file mode 100644 index 0000000..50c1df1 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPreview.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPreview.lib b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPreview.lib new file mode 100644 index 0000000..6279d3f Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCPreview.lib differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCVoiceTalk.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCVoiceTalk.dll new file mode 100644 index 0000000..aa67fa9 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/HCVoiceTalk.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/OpenAL32.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/OpenAL32.dll new file mode 100644 index 0000000..24ca039 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/OpenAL32.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/StreamTransClient.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/StreamTransClient.dll new file mode 100644 index 0000000..480b4cd Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/StreamTransClient.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/SystemTransform.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/SystemTransform.dll new file mode 100644 index 0000000..12ba69f Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/SystemTransform.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/libiconv2.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/libiconv2.dll new file mode 100644 index 0000000..cddc745 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/HCNetSDKCom/libiconv2.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/PlayCtrl.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/PlayCtrl.dll new file mode 100644 index 0000000..9b644aa Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/PlayCtrl.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/SuperRender.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/SuperRender.dll new file mode 100644 index 0000000..2584252 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/SuperRender.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/hlog.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/hlog.dll new file mode 100644 index 0000000..83266a5 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/hlog.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/hpr.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/hpr.dll new file mode 100644 index 0000000..1e3f1ad Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/hpr.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/libeay32.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/libeay32.dll new file mode 100644 index 0000000..de8c6be Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/libeay32.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/ssleay32.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/ssleay32.dll new file mode 100644 index 0000000..c086f10 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/ssleay32.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/lib/win/zlib1.dll b/sz-service/sz-service-admin/src/main/resources/lib/win/zlib1.dll new file mode 100644 index 0000000..23f8f92 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/lib/win/zlib1.dll differ diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/miniuser/MiniUserMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/miniuser/MiniUserMapper.xml new file mode 100644 index 0000000..9d0f681 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/miniuser/MiniUserMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + sys_user_id, openid, unionid, nickname, name, phone, avatar_url, subscribe, sex, del_flag, create_time, update_time + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/ProductMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/ProductMapper.xml new file mode 100644 index 0000000..e87a247 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/ProductMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + id, product_name, price, status, create_time + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysClientMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysClientMapper.xml new file mode 100644 index 0000000..1d3b3c9 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysClientMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + client_id, client_key, client_secret, grant_type_cd, device_type_cd, active_timeout, timeout, client_status_cd, del_flag, create_dept, create_id, create_time, update_id, update_time, remark, is_lock + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysConfigMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 0000000..2a24327 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + id, config_name, config_key, config_value, is_lock, frontend_visible, create_id, create_time, update_id, update_time, remark + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleMapper.xml new file mode 100644 index 0000000..8d1ec99 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleMapper.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + id, role_name, data_scope_cd, remark, del_flag, is_lock, create_time, update_time, create_id, update_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleMenuMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleMenuMapper.xml new file mode 100644 index 0000000..f6776b3 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleMenuMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + id, role_id, menu_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleRelationMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleRelationMapper.xml new file mode 100644 index 0000000..b3a3f36 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDataRoleRelationMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + id, role_id, relation_type_cd, relation_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptClosureMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptClosureMapper.xml new file mode 100644 index 0000000..2f71467 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptClosureMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + ancestor_id, descendant_id, depth + + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptLeaderMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptLeaderMapper.xml new file mode 100644 index 0000000..e888317 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptLeaderMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + id, dept_id, leader_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 0000000..7a63dbe --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + id, name, pid, deep, sort, has_children, is_lock, del_flag, remark, create_id, update_id, create_time, update_time + + + + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptRoleMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptRoleMapper.xml new file mode 100644 index 0000000..b7ea91e --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDeptRoleMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + id, role_id, user_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDictMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDictMapper.xml new file mode 100644 index 0000000..0a06298 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDictMapper.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + id, sys_dict_type_id, code_name, alias, sort, callback_show_style, remark, is_lock, is_show, del_flag, create_time, update_time, delete_time, create_id, update_id, delete_id + + + + + sd.id + , sd.sys_dict_type_id, sd.code_name, + sd.sort, sd.callback_show_style, + sd.remark, sd.is_lock, sd.is_show, + sd.create_time, sd.update_time, sd.del_flag, + sdt.type_name as sys_dict_type_name , + sdt.type_code as sys_dict_type_code, + sd.alias + + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDictTypeMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDictTypeMapper.xml new file mode 100644 index 0000000..81301e8 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id, type_name, type_code, is_lock, is_show, del_flag, remark, create_time, update_time, delete_time, create_id, update_id, delete_id, type + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysFileMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysFileMapper.xml new file mode 100644 index 0000000..34eb182 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysFileMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + id, filename, dir_tag, size, url, create_time, object_name, context_type, e_tag, create_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysLoginLogMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysLoginLogMapper.xml new file mode 100644 index 0000000..83b1576 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysLoginLogMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + id, del_flag, user_name, login_status, login_time, ip_address, login_location, browser, os, msg, remark + + + + INSERT INTO sys_login_log + + user_name, + login_status, + login_time, + ip_address, + login_location, + browser, + os, + msg, + remark, + + + #{loginLog.userName}, + #{loginLog.loginStatus}, + #{loginLog.loginTime}, + #{loginLog.ipAddress}, + #{loginLog.loginLocation}, + #{loginLog.browser}, + #{loginLog.os}, + #{loginLog.msg}, + #{loginLog.remark}, + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMenuMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 0000000..6839e0c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, pid, path, name, title, icon, component, redirect, sort, deep, menu_type_cd, permissions, is_hidden, has_children, is_link, is_full, is_affix, is_keep_alive, create_time, update_time, create_id, update_id, del_flag, delete_id, delete_time, use_data_scope + + + + + + + + + + UPDATE sys_menu AS m + JOIN ( + SELECT id, + IF(EXISTS (SELECT 1 FROM sys_menu WHERE pid = sub_m.id), 'T', 'F') AS has_children + FROM sys_menu AS sub_m + WHERE 1=1 and sub_m.del_flag = 'F' + ) AS subquery + ON m.id = subquery.id + SET m.has_children = 'T' + WHERE subquery.has_children = 'T'; + + + UPDATE sys_menu AS m + JOIN sys_menu AS parent + ON m.pid = parent.id + SET m.deep = parent.deep + 1 + WHERE 1=1 and m.del_flag = 'F'; + + + + UPDATE sys_menu AS m + SET del_flag = 'T' + WHERE m.id IN (SELECT id + FROM (WITH RECURSIVE MenuCTE AS (SELECT id, pid + FROM sys_menu + WHERE id = #{nodeId} + UNION ALL + SELECT sm.id, sm.pid + FROM sys_menu sm + JOIN MenuCTE cte ON sm.pid = cte.id) + SELECT id + FROM MenuCTE) AS subquery); + + + UPDATE sys_menu + SET del_flag = 'T' + WHERE id IN + + #{id} + + ; + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMessageMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMessageMapper.xml new file mode 100644 index 0000000..3b0272b --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMessageMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + id, message_type_cd, sender_id, title, content, del_flag, create_time, update_time, create_id, update_id, menu_router + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMessageUserMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMessageUserMapper.xml new file mode 100644 index 0000000..10333c6 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysMessageUserMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + id, message_id, receiver_id, is_read, read_time, del_flag + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysRoleMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 0000000..ec7b0a2 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + id, role_name, remark, del_flag, create_time, update_time, create_id, update_id, is_lock, permissions + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 0000000..c122161 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + id, menu_id, role_id, permission_type, data_scope_cd + + + + + INSERT INTO sys_role_menu (role_id, menu_id,permission_type,data_scope_cd) + VALUES + + (#{roleId}, #{menuId}, #{permissionType}, #{dataScopeCd}) + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysTempFileHistoryMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysTempFileHistoryMapper.xml new file mode 100644 index 0000000..f71c88d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysTempFileHistoryMapper.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + id, sys_temp_file_id, sys_file_id, temp_name, url, remark, create_id, create_time, update_id, update_time + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysTempFileMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysTempFileMapper.xml new file mode 100644 index 0000000..766418f --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysTempFileMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + id, sys_file_id, temp_name, url, remark, del_flag, create_id, create_time, update_id, update_time, alias + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserDataRoleMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserDataRoleMapper.xml new file mode 100644 index 0000000..5e63b1d --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserDataRoleMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + id, role_id, user_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserDeptMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserDeptMapper.xml new file mode 100644 index 0000000..ccec51c --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserDeptMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + id, dept_id, user_id + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000..d63d0b5 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, username, pwd, phone, nickname, sex, birthday, logo, age, id_card, email, account_status_cd, user_tag_cd, last_login_time, create_time, update_time, del_flag, create_id, update_id + + + + + + + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserRoleMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 0000000..92b44a0 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + id, role_id, user_id + + + + + INSERT INTO sys_user_role (role_id, user_id) + VALUES + + (#{roleId}, #{userId}) + + + + + + + + diff --git a/sz-service/sz-service-admin/src/main/resources/mapper/teacher/TeacherStatisticsMapper.xml b/sz-service/sz-service-admin/src/main/resources/mapper/teacher/TeacherStatisticsMapper.xml new file mode 100644 index 0000000..3e80a04 --- /dev/null +++ b/sz-service/sz-service-admin/src/main/resources/mapper/teacher/TeacherStatisticsMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id, year, month, during_time, teacher_id, teacher_common_type, total_teaching, total_class_count, total_hours, check_status, check_time, create_time, update_time, last_sync_time, remark + + + diff --git a/sz-service/sz-service-admin/src/main/resources/region/ip2region_v4.xdb b/sz-service/sz-service-admin/src/main/resources/region/ip2region_v4.xdb new file mode 100644 index 0000000..6f86c7d Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/region/ip2region_v4.xdb differ diff --git a/sz-service/sz-service-admin/src/main/resources/static/favicon.ico b/sz-service/sz-service-admin/src/main/resources/static/favicon.ico new file mode 100644 index 0000000..0f49b81 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/static/favicon.ico differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg1.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg1.png new file mode 100644 index 0000000..028073a Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg1.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg10.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg10.png new file mode 100644 index 0000000..022aabf Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg10.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg11.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg11.png new file mode 100644 index 0000000..914908e Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg11.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg12.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg12.png new file mode 100644 index 0000000..f0f3ce5 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg12.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg13.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg13.png new file mode 100644 index 0000000..c5697f3 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg13.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg14.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg14.png new file mode 100644 index 0000000..e29e7a3 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg14.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg15.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg15.png new file mode 100644 index 0000000..2425f41 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg15.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg16.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg16.png new file mode 100644 index 0000000..c1730ad Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg16.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg17.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg17.png new file mode 100644 index 0000000..10ea85b Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg17.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg18.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg18.png new file mode 100644 index 0000000..a63f0ac Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg18.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg19.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg19.png new file mode 100644 index 0000000..fe9c4cc Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg19.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg2.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg2.png new file mode 100644 index 0000000..7167036 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg2.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg20.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg20.png new file mode 100644 index 0000000..7db9563 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg20.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg3.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg3.png new file mode 100644 index 0000000..e932d2c Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg3.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg4.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg4.png new file mode 100644 index 0000000..63b2005 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg4.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg5.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg5.png new file mode 100644 index 0000000..4281ad4 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg5.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg6.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg6.png new file mode 100644 index 0000000..ac544e3 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg6.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg7.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg7.png new file mode 100644 index 0000000..c6df4f7 Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg7.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg8.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg8.png new file mode 100644 index 0000000..3b07dcd Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg8.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/background/bg9.png b/sz-service/sz-service-admin/src/main/resources/templates/background/bg9.png new file mode 100644 index 0000000..4b9844a Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/background/bg9.png differ diff --git a/sz-service/sz-service-admin/src/main/resources/templates/教师统计.xlsx b/sz-service/sz-service-admin/src/main/resources/templates/教师统计.xlsx new file mode 100644 index 0000000..ae0f68e Binary files /dev/null and b/sz-service/sz-service-admin/src/main/resources/templates/教师统计.xlsx differ diff --git a/sz-service/sz-service-websocket/pom.xml b/sz-service/sz-service-websocket/pom.xml new file mode 100644 index 0000000..462f86e --- /dev/null +++ b/sz-service/sz-service-websocket/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + + com.sz + sz-service + ${revision} + + + sz-service-websocket + + + com.sz + sz-common-db-redis + ${revision} + + + org.springframework.boot + spring-boot-starter-websocket + + + cn.dev33 + sa-token-spring-boot3-starter + + + cn.dev33 + sa-token-jwt + + + + + \ No newline at end of file diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/WebSocketApplication.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/WebSocketApplication.java new file mode 100644 index 0000000..052595e --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/WebSocketApplication.java @@ -0,0 +1,44 @@ +package com.sz.socket; + +import jakarta.annotation.PostConstruct; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan("com.sz") +public class WebSocketApplication { + + @Value("${app.version}") + private String appVersion; + + @Getter + private static String version; + + @PostConstruct + public void init() { + setVersion(appVersion); + } + + private static void setVersion(String appVersion) { + WebSocketApplication.version = appVersion; + } + + public static void main(String[] args) { + SpringApplication.run(WebSocketApplication.class, args); + String template = """ + __ _ + [ | _ / |_ + .--. ____ ______ .--. .--. .---. | | / ] .---.`| |-' + ( (`\\] [_ ]|______|( (`\\]/ .'`\\ \\/ /'`\\] | '' < / /__\\\\| | + `'.'. .' /_ `'.'.| \\__. || \\__. | |`\\ \\| \\__.,| |, + [\\__) )[_____] [\\__) )'.__.' '.___.'[__| \\_]'.__.'\\__/ + ------------------%s (v%s)------------------- + """; + String result = String.format(template, "https://szadmin.cn", getVersion()); + System.out.println(result); + } + +} diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/cache/SocketManagerCache.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/cache/SocketManagerCache.java new file mode 100644 index 0000000..885adab --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/cache/SocketManagerCache.java @@ -0,0 +1,59 @@ +package com.sz.socket.cache; + +import com.sz.core.common.entity.WsSession; +import lombok.extern.slf4j.Slf4j; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author sz + * @since 2023/9/6 17:01 + */ +@Slf4j +public class SocketManagerCache { + + public static final String SEC_WEBSOCKET_PROTOCOL_HEADER = "sec-websocket-protocol"; + + public static final String LOGIN_ID = "loginId"; + + /** + * sid <==> session 关系 + */ + public static ConcurrentHashMap onlineSessionMap = new ConcurrentHashMap<>(); + + /** + * loginId <==> sid 关系; 1对多,一个用户有可能在多个浏览器上登录 + */ + public static ConcurrentHashMap> onlineUserSessionIdMap = new ConcurrentHashMap<>(); + + public static void addOnlineSid(String loginId, String sid) { + if (onlineUserSessionIdMap.containsKey(loginId)) { + List sidArray = onlineUserSessionIdMap.get(loginId); + sidArray.add(sid); + onlineUserSessionIdMap.put(loginId, sidArray); + } else { + List sidArray = new ArrayList<>(); + sidArray.add(sid); + onlineUserSessionIdMap.put(loginId, sidArray); + } + } + + /** + * 清除断线的sid + * + * @param sid + * sid + */ + public static void removeUserSession(String sid) { + WsSession wsSession = onlineSessionMap.get(sid); + String loginId = wsSession.getLoginId(); + if (onlineUserSessionIdMap.containsKey(loginId)) { + List sids = onlineUserSessionIdMap.get(loginId); + sids.remove(sid); + onlineUserSessionIdMap.put(loginId, sids); + } + } + +} diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/ServiceMessageHandler.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/ServiceMessageHandler.java new file mode 100644 index 0000000..4240687 --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/ServiceMessageHandler.java @@ -0,0 +1,50 @@ +package com.sz.socket.configuration; + +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.core.util.JsonUtils; +import com.sz.redis.handler.ServiceToWsMsgHandler; +import com.sz.socket.sever.WebSocketServer; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 在业务层接收订阅额消息,并结合业务进行处理 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class ServiceMessageHandler implements ServiceToWsMsgHandler { + + private final WebSocketServer webSocketServer; + + @Override + public void handleTransferMessage(TransferMessage tm) { + log.info(" sz-service-websocket [service-to-ws] tm = {}", JsonUtils.toJsonString(tm)); + SocketMessage tmMessage = tm.getMessage(); + SocketChannelEnum channel = tmMessage.getChannel(); + switch (tmMessage.getScope()) { + case SERVER : // 通知到后台服务端 + if (SocketChannelEnum.CLOSE == channel) { + // todo ... + } + break; + case SOCKET_CLIENT : // 通知到socket客户端,即浏览器、移动端等 + // 推送给全体用户 + if (tm.isToPushAll()) { + webSocketServer.sendMessageToAllUser(tm.getMessage()); + // 推送给指定用户 + } else { + webSocketServer.sendMessage(tm.getToUsers(), tm.getMessage()); + } + break; + case SOCKET_SERVER : + // todo something .. + break; + default : + break; + } + } +} diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/WebSocketConfig.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/WebSocketConfig.java new file mode 100644 index 0000000..11606cb --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/WebSocketConfig.java @@ -0,0 +1,34 @@ +package com.sz.socket.configuration; + +import com.sz.socket.sever.WebSocketServer; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + +@Configuration +@EnableWebSocket +public class WebSocketConfig implements WebSocketConfigurer { + + private final WebSocketServer webSocketServer; + + public WebSocketConfig(WebSocketServer webSocketServer) { + this.webSocketServer = webSocketServer; + } + + @Resource + private WebSocketInterceptor webSocketInterceptor; + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { + webSocketHandlerRegistry + // 添加myHandler消息处理对象,和websocket访问地址 + .addHandler(webSocketServer, "/socket") + // 设置允许跨域访问 + .setAllowedOrigins("*") // !!!【建议指定域名,不要全部开放。】 + // 添加拦截器可实现用户链接前进行权限校验等操作 + .addInterceptors(webSocketInterceptor); + } + +} diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/WebSocketInterceptor.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/WebSocketInterceptor.java new file mode 100644 index 0000000..0d978f6 --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/configuration/WebSocketInterceptor.java @@ -0,0 +1,86 @@ +package com.sz.socket.configuration; + +import cn.dev33.satoken.jwt.SaJwtUtil; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.jwt.JWT; +import com.sz.core.util.StringUtils; +import com.sz.core.util.Utils; +import com.sz.redis.CommonKeyConstants; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.http.server.ServletServerHttpResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.WebSocketHandler; +import org.springframework.web.socket.server.HandshakeInterceptor; + +import java.util.Map; + +import static com.sz.socket.cache.SocketManagerCache.LOGIN_ID; +import static com.sz.socket.cache.SocketManagerCache.SEC_WEBSOCKET_PROTOCOL_HEADER; + +@Component +@RequiredArgsConstructor +@Slf4j +public class WebSocketInterceptor implements HandshakeInterceptor { + + private final RedisTemplate redisTemplate; + + /** + * 握手之前 + * + * @param request + * request + * @param response + * response + * @param wsHandler + * handler + * @param attributes + * 属性 + * @return 是否握手成功:true-成功,false-失败 + */ + @Override + public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) { + ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request; + ServletServerHttpResponse serverHttpResponse = (ServletServerHttpResponse) response; + String authorization = serverHttpRequest.getServletRequest().getHeader(SEC_WEBSOCKET_PROTOCOL_HEADER); + String keyt = StpUtil.getStpLogic().getConfigOrGlobal().getJwtSecretKey(); + if (Utils.isNotNull(authorization)) { + JWT jwt = SaJwtUtil.parseToken(authorization, "login", keyt, false); + if (!jwt.verify()) { + return false; + } + String loginId = jwt.getPayload().getClaimsJson().get(LOGIN_ID).toString(); + String key = StringUtils.getRealKey(CommonKeyConstants.TOKEN_SESSION, authorization); + // 从redis 里获取用户,验证是否是有效用户,如果失败则中断连接 + if (redisTemplate.hasKey(key)) { + // 自定义attribute + attributes.put(LOGIN_ID, loginId); + log.info("用户: [{}]建立连接, token:[{}]", loginId, authorization); + serverHttpResponse.getServletResponse().setHeader(SEC_WEBSOCKET_PROTOCOL_HEADER, authorization); + return true; + } + } + return false; + } + + /** + * 握手后 + * + * @param request + * request + * @param response + * response + * @param wsHandler + * wsHandler + * @param exception + * exception + */ + @Override + public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { + // 握手后 ... + } +} diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/ServerState.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/ServerState.java new file mode 100644 index 0000000..39ddf56 --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/ServerState.java @@ -0,0 +1,14 @@ +package com.sz.socket.sever; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.stereotype.Component; + +@Setter +@Getter +@Component +public class ServerState { + + private volatile boolean shuttingDown = false; + +} diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/WebSocketCleaner.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/WebSocketCleaner.java new file mode 100644 index 0000000..1c67f49 --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/WebSocketCleaner.java @@ -0,0 +1,46 @@ +package com.sz.socket.sever; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.SmartLifecycle; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class WebSocketCleaner implements SmartLifecycle { + + private boolean running = false; + + private final WebSocketServer webSocketServer; + + private final ServerState serverState; + + @Override + public void start() { + // 启动时的操作 + running = true; + } + + @Override + public void stop() { + serverState.setShuttingDown(true); + // 停止时的操作(优雅关闭) + webSocketServer.disconnectAll(); + running = false; + } + + @Override + public boolean isRunning() { + return running; + } + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public int getPhase() { + // 返回值越小,越先执行stop()方法 + return Integer.MAX_VALUE; + } +} diff --git a/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/WebSocketServer.java b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/WebSocketServer.java new file mode 100644 index 0000000..78cddbd --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/java/com/sz/socket/sever/WebSocketServer.java @@ -0,0 +1,221 @@ +package com.sz.socket.sever; + +import com.sz.core.common.entity.SocketMessage; +import com.sz.core.common.entity.TransferMessage; +import com.sz.core.common.entity.WsSession; +import com.sz.core.common.enums.SocketChannelEnum; +import com.sz.core.util.JsonUtils; +import com.sz.core.util.SocketUtil; +import com.sz.core.util.Utils; +import com.sz.redis.WebsocketRedisService; +import com.sz.socket.cache.SocketManagerCache; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static com.sz.socket.cache.SocketManagerCache.LOGIN_ID; + +@Component +@Slf4j +@RequiredArgsConstructor +public class WebSocketServer extends TextWebSocketHandler { + + private final WebsocketRedisService websocketRedisService; + + private final ServerState serverState; + + /** + * 接受客户端消息 + * + * @param session + * session + * @param message + * message + * @throws IOException + * e + */ + @Override + public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException { + if (serverState.isShuttingDown()) { + log.warn("Service is shutting down. Ignoring new messages."); + return; + } + + String sid = session.getId(); + SocketMessage msg; + try { + msg = JsonUtils.parseObject(message.getPayload(), SocketMessage.class); + } catch (Exception e) { + log.error("【websocket】消息解析失败,payload: {}, error: {}", message.getPayload(), e.getMessage()); + session.sendMessage(new TextMessage("{\"error\":\"消息格式错误\"}")); + return; + } + if (msg == null) { + log.warn("【websocket】消息解析结果为null,payload: {}", message.getPayload()); + session.sendMessage(new TextMessage("{\"error\":\"消息格式错误\"}")); + return; + } + SocketChannelEnum channel = msg.getChannel(); + switch (channel) { + default : + log.warn(" 【websocket】 unknown message: {}, send to service ... ", message); + TransferMessage tm = new TransferMessage(); + tm.setMessage(msg); + String channelUsername = websocketRedisService.getUserBySessionId(sid); + if (channelUsername != null) { + tm.setFromUser(channelUsername); + } + // 将消息透传给服务端,���务端需要注意消息的幂等处理 + websocketRedisService.sendWsToService(tm); + break; + } + } + + /** + * 连接建立后 + * + * @param session + * session + * @throws Exception + * e + */ + @Override + public void afterConnectionEstablished(WebSocketSession session) throws Exception { + if (serverState.isShuttingDown()) { + log.warn("Service is shutting down. Rejecting new connection."); + session.close(CloseStatus.SERVICE_RESTARTED); + return; + } + String sid = session.getId(); + String loginId = (String) session.getAttributes().get(LOGIN_ID); + WsSession wsSession = new WsSession(sid, loginId, session); + + SocketManagerCache.onlineSessionMap.put(sid, wsSession); + SocketManagerCache.addOnlineSid(loginId, sid); + websocketRedisService.addUserToOnlineChat(sid, loginId); + System.out.println("当前连接数:" + websocketRedisService.getConnectionCount()); + System.out.println("当前在线人数: " + websocketRedisService.getOnlineUserCount()); + System.out.println("当前内存中的用户: " + JsonUtils.toJsonString(websocketRedisService.getAllOnlineUsernames())); + } + + /** + * 连接关闭后 + * + * @param session + * session + * @param status + * status + * @throws Exception + * e + */ + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { + if (serverState.isShuttingDown()) { + log.warn("Service is shutting down. Skipping cleanup for closed connection."); + return; + } + String loginId = (String) session.getAttributes().get(LOGIN_ID); + log.info("【websocket消息】连接断开,loginId:[{}]", loginId); + if (session.isOpen()) { + try { + String sid = session.getId(); + websocketRedisService.removeUserBySessionId(sid); + // 注意删除顺序,先清除WSSession的Map + SocketManagerCache.removeUserSession(sid); + SocketManagerCache.onlineSessionMap.remove(sid); + session.close(); + } catch (IOException e) { + log.error("【websocket消息】连接断开异常,error", e); + throw new IllegalArgumentException(e); + } + } + } + + /** + * 根据loginId 推送消息 + * + * @param loginIds + * 登陆用户Id集合 + * @param socketMessage + * 消息对象 + */ + @SneakyThrows + public void sendMessage(List loginIds, SocketMessage socketMessage) { + log.info(" 定向推送。推送用户范围:{}, message: {}", loginIds, JsonUtils.toJsonString(socketMessage)); + for (Object loginId : loginIds) { + // 验证当前内存中【用户】是否存在 + boolean existsUsername = SocketManagerCache.onlineUserSessionIdMap.containsKey(Utils.getStringVal(loginId)); + if (existsUsername) { + List notifyUserSids = SocketManagerCache.onlineUserSessionIdMap.get(Utils.getStringVal(loginId)); + for (String notifyUserSid : notifyUserSids) { + // 验证当前内存中【session】是否存在 + boolean existsUserSession = SocketManagerCache.onlineSessionMap.containsKey(notifyUserSid); + if (existsUserSession) { + WsSession wsSession = SocketManagerCache.onlineSessionMap.get(notifyUserSid); + wsSession.getSession().sendMessage(new TextMessage(SocketUtil.transferMessage(socketMessage))); + } else { + log.info(" websocket定向推送。message: {}。用户:{}推送失败", JsonUtils.toJsonString(socketMessage), loginId); + } + } + } + } + } + + /** + * 根据loginId 推送消息 + * + * @param socketMessage + * 消息对象 + */ + @SneakyThrows + public void sendMessageToAllUser(SocketMessage socketMessage) { + log.info(" 全员推送。message: {}", JsonUtils.toJsonString(socketMessage)); + List allOnlineUsernames = new ArrayList<>(SocketManagerCache.onlineUserSessionIdMap.keySet()); + for (String loginId : allOnlineUsernames) { + List notifyUserSids = SocketManagerCache.onlineUserSessionIdMap.get(loginId); + for (String notifyUserSid : notifyUserSids) { + boolean existsUserSession = SocketManagerCache.onlineSessionMap.containsKey(notifyUserSid); + if (existsUserSession) { + WsSession wsSession = SocketManagerCache.onlineSessionMap.get(notifyUserSid); + wsSession.getSession().sendMessage(new TextMessage(SocketUtil.transferMessage(socketMessage))); + } else { + log.info(" websocket全员推送。message: {}。用户:{}推送失败", JsonUtils.toJsonString(socketMessage), loginId); + } + } + } + } + + public void disconnectAll() { + ConcurrentHashMap onlineSessionMap = SocketManagerCache.onlineSessionMap; + for (Map.Entry sessionEntry : onlineSessionMap.entrySet()) { + String sid = sessionEntry.getKey(); + WsSession wsSession = sessionEntry.getValue(); + // 清理 redis + websocketRedisService.removeUserBySessionId(sid); + // 断开websocket 连接 ... + WebSocketSession session = wsSession.getSession(); + if (session != null) { + try { + wsSession.getSession().close(CloseStatus.SERVICE_RESTARTED); + log.info(" 优雅退出,关闭 websocket 连接 ..."); + } catch (IOException e) { + log.error("【websocket消息】连接断开异常,error", e); + throw new IllegalArgumentException(e); + } + } + } + + } + +} diff --git a/sz-service/sz-service-websocket/src/main/resources/application.yml b/sz-service/sz-service-websocket/src/main/resources/application.yml new file mode 100644 index 0000000..7353268 --- /dev/null +++ b/sz-service/sz-service-websocket/src/main/resources/application.yml @@ -0,0 +1,19 @@ +server: + port: 9993 + shutdown: graceful + +spring: + threads: + virtual: + # 启用虚拟线程 + enabled: true + profiles: + active: local + config: + import: + - file:config/${spring.profiles.active}/redis.yml + - file:config/${spring.profiles.active}/sa-token.yml + application: + name: websocket-service +app: + version: @project.version@