15 Commits
Author SHA1 Message Date
odboy 98830dfdc7 !7 !6 chore(version): 更新项目版本号从1.5.0到1.5.2
Merge pull request !7 from Odboy/master
2026-01-17 02:20:15 +00:00
odboy 1c10dc2ce2 !6 chore(version): 更新项目版本号从1.5.0到1.5.2
Merge pull request !6 from Odboy/dev
2026-01-17 02:19:51 +00:00
odboy 65699dcab4 chore(version): 更新项目版本号从1.5.0到1.5.2 2026-01-17 10:19:14 +08:00
odboy b0a57c778b !5 !4 fix(test): 修复测试类中对象实例化错误
Merge pull request !5 from Odboy/master
2026-01-17 02:11:24 +00:00
odboy 8a38e532e2 !4 fix(test): 修复测试类中对象实例化错误
Merge pull request !4 from Odboy/dev
2026-01-17 02:10:58 +00:00
odboy df43cd2333 fix(test): 修复测试类中对象实例化错误
- 添加了 SystemDeptTb 类的导入声明
- 将 SystemDeptVo 对象替换为 SystemDeptTb 对象
- 确保测试代码使用正确的数据对象类型
2026-01-17 10:09:50 +08:00
odboy 65e94a204c !3 feat(system): 新增系统组件服务重构部门和用户选择功能
Merge pull request !3 from Odboy/dev
2026-01-17 02:04:58 +00:00
odboy da255fa7e0 feat(system): 新增系统组件服务重构部门和用户选择功能
- 新增 CuteDeptTreeVo 模型类用于部门树形结构
- 重命名并迁移 SystemProductLineTreeVo 到 CuteProductLineSelectProVo
- 重命名并迁移 SystemProductLineVo 到 CuteProductLineSelectVo
- 新增 CuteUserSelectVo 模型类用于用户选择组件
- 新增 CuteBaseService 提供基础部门查询服务
- 新增 CuteDeptTreeService 处理部门树形数据逻辑
- 新增 CuteFileUploadService 管理文件上传功能
- 新增 CuteProductLineSelectProService 和 CuteProductLineSelectService
- 新增 CuteUserSelectService 提供用户选择数据源
- 新增多个 API 控制器包括 CuteDeptTreeApi、CuteFileUploadApi 等
- 更新缓存键常量 USER_INFO 替代 ONLINE_USER
- 移除旧的 SystemComponentController 和相关方法
- 调整 SystemUserInfoDAO 使用新的缓存键名
- 修改 SystemUserVo 中的部门字段类型为 SystemDeptTb
2026-01-17 10:01:42 +08:00
odboy d413ea4469 refactor(system): 优化部门服务中的数据对象使用
- 将 SystemUserVo 中的 dept 字段类型从 SystemDeptVo 改为 SystemDeptTb
- 在 SystemDeptService 中统一使用 SystemDeptTb 对象替代 SystemDeptVo
- 删除了 getDeptVoById 方法并替换为直接使用 getDeptById
- 重构了部门树构建逻辑,优化了部门数据的查询和映射
- 修改了部门删除、查询、验证等相关方法的数据类型处理
- 添加了获取所有部门映射的私有方法以提高查询效率
2026-01-17 09:53:36 +08:00
odboy 4eaa383717 feat(dept): 新增部门树形组件功能
- 创建 CuteDeptTreeVo 模型类用于部门树形结构数据传输
- 实现 CuteDeptTreeService 服务类处理部门树形数据查询逻辑
- 开发 CuteDeptTreeApi 接口提供部门树形数据查询功能
- 将 SystemDeptService 中的 filterRootDeptList 和 queryDeptByArgs 方法改为 public 以便外部调用
- 前端创建 cute-dept-tree API 接口文件封装请求方法
- 更新 CuteDeptTree 组件使用新的部门树形接口并调整数据处理逻辑
- 修改组件 props 类型从 Number/String 改为 String 类型
2026-01-17 09:34:42 +08:00
odboy d113ebfa2f fix(select): 统一选择组件值类型为字符串
- 将 CuteProductLineSelect 组件的 value 类型从 [Number, String] 修改为 String
- 为 CuteProductLineSelectProVo 添加 value 和 label 字段注释说明
- 将 CuteProductLineSelectVo 的 value 字段类型从 Long 修改为 String
- 为 CuteUserSelectVo 添加 deptId、email、phone 字段注释说明
- 在 CuteProductLineSelectService 中将部门 ID 转换为字符串赋值给 value
2026-01-17 09:11:28 +08:00
odboy f2898da525 feat(user): 添加根据用户名列表查询用户基础数据功能
- 在CuteUserSelectService中新增listMetadataByUsernames方法
- 为CuteUserSelectApi添加listMetadataByUsernames接口
- 在前端cute-user-select.js中新增listMetadataByUsernames请求方法
- 修改CuteSingleUserSelect组件支持初始化时根据用户名加载用户信息
- 修改CuteUserSelect组件移除dataSource属性并支持初始化加载
- 更新CuteBusinessDemo演示页面用户字段默认值为空数组
2026-01-17 09:01:10 +08:00
odboy 462abff607 refactor(system): 重构系统组件服务结构
- 将产品线选择组件相关VO类从dal层移动到application层并重命名
- 新增CuteUserSelectVo、CuteBaseService、CuteFileUploadService等服务类
- 创建CuteProductLineSelectProService和CuteProductLineSelectService业务服务
- 新增CuteUserSelectService用户选择服务及对应的API接口
- 修改文件上传API使用新的服务类并添加权限控制
- 更新产品线选择API使用新服务类并移除旧的实现方法
- 删除系统用户服务中的旧用户元数据查询方法
- 更新前端用户选择组件调用新的API接口
- 移除旧的用户元数据选项查询API调用
2026-01-17 06:38:38 +08:00
odboy 89803b3908 feat(api): 添加文件上传组件专用接口支持本地和OSS上传
- 在api store中新增fileUploadApplicationApi和ossUploadApplicationApi两个专用接口地址
- 从getters中移除已废弃的deployUploadApi和databaseUploadApi
- 将上传组件改为使用新的专用接口,并通过mode参数区分本地和OSS上传
- 更新组件文档注释将上传方式从server改为local
- 创建CuteFileUploadApi控制器提供uploadLocal和uploadOSS接口
- 在SystemLocalStorageService中实现uploadLocal方法处理本地文件上传逻辑
- 更新演示页面默认使用本地上传模式
2026-01-17 05:59:42 +08:00
odboy df6dc89b96 feat(component): 添加产品线选择组件并重构系统组件API
- 新增 CuteProductLineSelect 组件API接口
- 重命名 SystemComponentController 为 CuteProductLineSelectProApi
- 迁移部门选择数据源接口到新API路径
- 更新前端组件导入路径和API调用方式
- 修改 CuteDeptTree 组件分页大小限制
- 为文件上传组件添加上传方式配置选项
- 调整字典详情和定时任务模块的API导入路径
2026-01-17 05:28:24 +08:00
86 changed files with 1630 additions and 813 deletions
@@ -0,0 +1,12 @@
import request from '@/utils/request'
export function listMetadata(query) {
return request({
url: 'api/component/CuteDeptTree/listMetadata',
method: 'post',
data: query
})
}
export default { listMetadata }
@@ -0,0 +1,8 @@
import request from '@/utils/request'
export function listMetadata() {
return request({
url: 'api/component/CuteProductLineSelectPro/listMetadata',
method: 'post'
})
}
@@ -0,0 +1,8 @@
import request from '@/utils/request'
export function listMetadata() {
return request({
url: 'api/component/CuteProductLineSelect/listMetadata',
method: 'post'
})
}
@@ -0,0 +1,22 @@
import request from '@/utils/request'
export function listMetadata(query) {
return request({
url: 'api/component/CuteUserSelect/listMetadata',
method: 'post',
data: {
blurry: query
}
})
}
export function listMetadataByUsernames(usernameList = []) {
return request({
url: 'api/component/CuteUserSelect/listMetadataByUsernames',
method: 'post',
data: usernameList
})
}
export default { listMetadata, listMetadataByUsernames }
@@ -1,15 +0,0 @@
import request from '@/utils/request'
export function listDeptSelectDataSource() {
return request({
url: 'api/component/listDeptSelectDataSource',
method: 'post'
})
}
export function listDeptSelectProDataSource() {
return request({
url: 'api/component/listDeptSelectProDataSource',
method: 'post'
})
}
+1 -16
View File
@@ -68,20 +68,5 @@ export function updateUserEmailByUsername(form) {
})
}
export function queryUserMetadataOptions(query) {
const params = {
page: 1,
size: 50,
args: {
blurry: query
}
}
return request({
url: 'api/user/queryUserMetadataOptions',
method: 'post',
data: params
})
}
export default { add, edit, del, resetUserPasswordByIds, queryUserMetadataOptions }
export default { add, edit, del, resetUserPasswordByIds }
+1 -1
View File
@@ -1,5 +1,5 @@
import Vue from 'vue'
import { get as getDictDetail } from '@/api/system/dictDetail'
import { get as getDictDetail } from '@/api/system/dict-detail'
export default class Dict {
constructor(dict) {
+4 -3
View File
@@ -3,8 +3,6 @@
* @type {any}
*/
const getters = {
deployUploadApi: state => state.api.deployUploadApi,
databaseUploadApi: state => state.api.databaseUploadApi,
size: state => state.app.size,
sidebar: state => state.app.sidebar,
device: state => state.app.device,
@@ -24,6 +22,9 @@ const getters = {
swaggerApi: state => state.api.swaggerApi,
websocketApi: state => state.api.websocketApi,
sidebarRouters: state => state.permission.sidebarRouters,
statusConst: state => state.pipeline.statusConst
statusConst: state => state.pipeline.statusConst,
// 上传组件专用
fileUploadApplicationApi: state => state.api.fileUploadApplicationApi,
ossUploadApplicationApi: state => state.api.ossUploadApplicationApi
}
export default getters
+3
View File
@@ -16,6 +16,9 @@ const api = {
fileUploadApi: baseUrl + '/api/localStorage/uploadFile',
// oss上传
ossUploadApi: baseUrl + '/api/ossStorage/uploadFile',
// 上传组件专用
fileUploadApplicationApi: baseUrl + '/api/component/CuteFileUpload/uploadLocal',
ossUploadApplicationApi: baseUrl + '/api/component/CuteFileUpload/uploadOSS',
// baseUrl,
baseApi: baseUrl
}
@@ -30,13 +30,13 @@
<script>
import { searchDept } from '@/api/system/dept'
import CuteDeptTreeApi from '@/api/application/cute-dept-tree'
export default {
name: 'CuteDeptTree',
props: {
value: {
type: [Number, String],
type: String,
required: false,
default: null
}
@@ -61,15 +61,11 @@ export default {
params['pid'] = node.data.id
}
setTimeout(() => {
searchDept({
page: 1,
size: 9999999,
args: params
}).then(res => {
CuteDeptTreeApi.listMetadata(params).then(res => {
if (resolve) {
resolve(res.content)
resolve(res)
} else {
this.deptData = res.content
this.deptData = res
}
})
}, 100)
@@ -14,7 +14,7 @@
:headers="headers"
:on-success="handleSuccess"
:on-error="handleError"
:action="ossUploadApi"
:action="mode === 'oss' ? ossUploadApplicationApi: fileUploadApplicationApi"
>
<i class="el-icon-upload" />
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
@@ -34,6 +34,14 @@ export default {
type: Object,
required: true,
default: null
},
/**
* 上传方式:local、oss
*/
mode: {
type: String,
required: true,
default: 'oss'
}
},
data() {
@@ -44,7 +52,8 @@ export default {
computed: {
...mapGetters([
'baseApi',
'ossUploadApi'
'fileUploadApplicationApi',
'ossUploadApplicationApi'
])
},
methods: {
@@ -13,7 +13,7 @@
:headers="headers"
:on-success="handleSuccess"
:on-error="handleError"
:action="ossUploadApi"
:action="mode === 'oss' ? ossUploadApplicationApi: fileUploadApplicationApi"
>
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传不超过100MB的文件</div>
@@ -32,6 +32,14 @@ export default {
type: Object,
required: true,
default: null
},
/**
* 上传方式:local、oss
*/
mode: {
type: String,
required: true,
default: 'oss'
}
},
data() {
@@ -42,7 +50,8 @@ export default {
computed: {
...mapGetters([
'baseApi',
'ossUploadApi'
'fileUploadApplicationApi',
'ossUploadApplicationApi'
])
},
methods: {
@@ -25,14 +25,14 @@
<script>
import { listDeptSelectDataSource } from '@/api/system/component'
import { listMetadata } from '@/api/application/cute-product-line-select'
import CsMessage from '@/utils/elementui/CsMessage'
export default {
name: 'CuteProductLineSelect',
props: {
value: {
type: [Number, String],
type: String,
default: null
},
disabled: {
@@ -56,7 +56,7 @@ export default {
},
methods: {
fetchDeptData() {
listDeptSelectDataSource().then(data => {
listMetadata().then(data => {
this.deptOptions = data
}).catch(error => {
console.error('获取部门数据失败:', error)
@@ -17,7 +17,7 @@
<script>
import { listDeptSelectProDataSource } from '@/api/system/component'
import { listMetadata } from '@/api/application/cute-product-line-select-pro'
import CsMessage from '@/utils/elementui/CsMessage'
export default {
@@ -62,7 +62,7 @@ export default {
})
},
fetchDeptData() {
listDeptSelectProDataSource().then(data => {
listMetadata().then(data => {
this.deptOptions = this.cleanEmptyChildren(data)
// console.error('deptOptions', this.deptOptions)
}).catch(error => {
@@ -28,7 +28,7 @@
<script>
import UserService from '@/api/system/user'
import CuteUserSelectApi from '@/api/application/cute-user-select'
export default {
name: 'CuteSingleUserSelect',
@@ -41,7 +41,7 @@ export default {
},
data() {
return {
user: this.value,
user: [],
loading: false,
options: []
}
@@ -51,21 +51,28 @@ export default {
this.user = newVal
}
},
async mounted() {
const that = this
if (that.value && that.value.length > 0) {
that.options = await CuteUserSelectApi.listMetadataByUsernames(that.value)
that.users = that.value
}
},
methods: {
remoteMethod(query) {
if (query !== '') {
this.loading = true
setTimeout(() => {
this.loading = false
this.queryUserMetadataOptions(query)
this.listMetadata(query)
}, 200)
} else {
this.options = []
}
},
queryUserMetadataOptions(query, options) {
listMetadata(query, options) {
const that = this
UserService.queryUserMetadataOptions(query).then(res => {
CuteUserSelectApi.listMetadata(query).then(res => {
that.options = res
})
},
@@ -28,7 +28,7 @@
<script>
import UserService from '@/api/system/user'
import CuteUserSelectApi from '@/api/application/cute-user-select'
export default {
name: 'CuteUserSelect',
@@ -37,16 +37,11 @@ export default {
type: Array,
required: false,
default: null
},
dataSource: {
type: Array,
required: false,
default: null
}
},
data() {
return {
users: this.value,
users: [],
loading: false,
options: []
}
@@ -56,9 +51,11 @@ export default {
this.users = newVal
}
},
mounted() {
if (this.dataSource && this.dataSource.length > 0) {
this.options = this.dataSource
async mounted() {
const that = this
if (that.value && that.value.length > 0) {
that.options = await CuteUserSelectApi.listMetadataByUsernames(that.value)
that.users = that.value
}
},
methods: {
@@ -67,15 +64,15 @@ export default {
this.loading = true
setTimeout(() => {
this.loading = false
this.queryUserMetadataOptions(query)
this.listMetadata(query)
}, 200)
} else {
this.options = []
}
},
queryUserMetadataOptions(query, options) {
listMetadata(query, options) {
const that = this
UserService.queryUserMetadataOptions(query).then(res => {
CuteUserSelectApi.listMetadata(query).then(res => {
that.options = res
})
},
@@ -65,7 +65,7 @@ export default {
data() {
return {
form: {
user: null,
user: [],
dept: null,
productLine: null,
productLinePro: null
@@ -11,7 +11,7 @@
</el-select>
</el-form-item>
<el-form-item label="文件上传" prop="fileUrl">
<cute-file-drag-upload v-model="form" />
<cute-file-drag-upload v-model="form" mode="local" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('form')">提 交</el-button>
@@ -11,7 +11,7 @@
</el-select>
</el-form-item>
<el-form-item label="文件上传" prop="fileUrl">
<cute-file-upload v-model="form" />
<cute-file-upload v-model="form" mode="local" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('form')">提 交</el-button>
@@ -72,7 +72,7 @@
</template>
<script>
import crudDictDetail from '@/api/system/dictDetail'
import crudDictDetail from '@/api/system/dict-detail'
import CRUD, { form, header, presenter } from '@crud/crud'
import pagination from '@crud/Pagination'
import udOperation from '@crud/UD.operation'
@@ -167,7 +167,7 @@
</template>
<script>
import crudJob from '@/api/system/quartzJob'
import crudJob from '@/api/system/quartz-job'
import Log from './log'
import CRUD, { crud, form, header, presenter } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
@@ -125,7 +125,7 @@
<script>
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import crudFile from '@/api/system/localStorage'
import crudFile from '@/api/system/local-storage'
import CRUD, { crud, form, header, presenter } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
@@ -94,7 +94,7 @@
<script>
import { mapGetters } from 'vuex'
import { getToken } from '@/utils/auth'
import crudFile from '@/api/system/ossStorage'
import crudFile from '@/api/system/oss-storage'
import CRUD, { crud, form, header, presenter } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-framework</artifactId>
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-module-system</artifactId>
@@ -13,7 +13,7 @@
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>cutejava-framework</artifactId>
<version>1.5.0</version>
<version>1.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.minio/minio -->
<dependency>
@@ -0,0 +1,31 @@
package cn.odboy.system.application;
import cn.odboy.system.application.model.CuteDeptTreeVo;
import cn.odboy.system.application.service.CuteDeptTreeService;
import cn.odboy.system.dal.model.request.SystemQueryDeptArgs;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
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;
import java.util.List;
@RestController
@Api(tags = "系统组件:CuteDeptTree")
@RequestMapping("/api/component/CuteDeptTree")
public class CuteDeptTreeApi {
@Autowired
private CuteDeptTreeService cuteDeptTreeService;
@ApiOperation("查询部门")
@PostMapping(value = "/listMetadata")
public ResponseEntity<List<CuteDeptTreeVo>> listMetadata(@Validated @RequestBody SystemQueryDeptArgs args) throws Exception {
List<CuteDeptTreeVo> depts = cuteDeptTreeService.listMetadata(args);
return ResponseEntity.ok(depts);
}
}
@@ -0,0 +1,44 @@
package cn.odboy.system.application;
import cn.odboy.system.application.service.CuteFileUploadService;
import cn.odboy.system.framework.operalog.OperationLog;
import cn.odboy.system.service.SystemOssStorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@Api(tags = "系统组件:CuteFileUpload")
@RequestMapping("/api/component/CuteFileUpload")
public class CuteFileUploadApi {
@Autowired
private CuteFileUploadService cuteFileUploadService;
@Autowired
private SystemOssStorageService systemOssStorageService;
@OperationLog
@ApiOperation("上传文件到服务器本地")
@PostMapping(value = "/uploadLocal")
@PreAuthorize("@el.check()")
public ResponseEntity<String> uploadLocal(@RequestParam("file") MultipartFile file) {
String fileUrl = cuteFileUploadService.uploadLocal(file);
return ResponseEntity.ok(fileUrl);
}
@OperationLog
@ApiOperation("上传文件到OSS")
@PostMapping(value = "/uploadOSS")
@PreAuthorize("@el.check()")
public ResponseEntity<String> uploadOSS(@RequestParam("file") MultipartFile file) {
String fileUrl = systemOssStorageService.uploadFile(file);
return ResponseEntity.ok(fileUrl);
}
}
@@ -0,0 +1,27 @@
package cn.odboy.system.application;
import cn.odboy.system.application.service.CuteProductLineSelectService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统组件:CuteProductLineSelect")
@RequestMapping("/api/component/CuteProductLineSelect")
public class CuteProductLineSelectApi {
@Autowired
private CuteProductLineSelectService cuteProductLineSelectService;
@ApiOperation("查询部门下拉选择数据源")
@PostMapping(value = "/listMetadata")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listMetadata() {
return ResponseEntity.ok(cuteProductLineSelectService.listMetadata());
}
}
@@ -0,0 +1,27 @@
package cn.odboy.system.application;
import cn.odboy.system.application.service.CuteProductLineSelectProService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统组件:CuteProductLineSelectPro")
@RequestMapping("/api/component/CuteProductLineSelectPro")
public class CuteProductLineSelectProApi {
@Autowired
private CuteProductLineSelectProService cuteProductLineSelectProService;
@ApiOperation("查询部门下拉选择Pro数据源")
@PostMapping(value = "/listMetadata")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listMetadata() {
return ResponseEntity.ok(cuteProductLineSelectProService.listMetadata());
}
}
@@ -0,0 +1,41 @@
package cn.odboy.system.application;
import cn.odboy.system.application.model.CuteUserSelectVo;
import cn.odboy.system.application.service.CuteUserSelectService;
import cn.odboy.system.dal.model.request.SystemQueryUserArgs;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
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;
import java.util.List;
@RestController
@Api(tags = "系统组件:CuteUserSelect")
@RequestMapping("/api/component/CuteUserSelect")
public class CuteUserSelectApi {
@Autowired
private CuteUserSelectService cuteUserSelectService;
@ApiOperation("查询用户基础数据")
@PostMapping(value = "/listMetadata")
@PreAuthorize("@el.check()")
public ResponseEntity<List<CuteUserSelectVo>> listMetadata(@Validated @RequestBody SystemQueryUserArgs args) {
List<CuteUserSelectVo> collect = cuteUserSelectService.listMetadata(args);
return ResponseEntity.ok(collect);
}
@ApiOperation("根据用户名称集合查询用户基础数据")
@PostMapping(value = "/listMetadataByUsernames")
@PreAuthorize("@el.check()")
public ResponseEntity<List<CuteUserSelectVo>> listMetadataByUsernames(@RequestBody List<String> usernameList) {
List<CuteUserSelectVo> collect = cuteUserSelectService.listMetadataByUsernames(usernameList);
return ResponseEntity.ok(collect);
}
}
@@ -0,0 +1,48 @@
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CuteDeptTreeVo extends KitObject {
/**
* 部门ID
*/
private String id;
/**
* 部门名称
*/
private String name;
/**
* 上级部门ID
*/
private String pid;
/**
* 子节点数目
*/
private Integer subCount = 0;
/**
* 是否有子节点
*/
public Boolean getHasChildren() {
return subCount > 0;
}
/**
* 是否为叶子
*/
public Boolean getLeaf() {
return subCount <= 0;
}
/**
* 标签名称
*/
public String getLabel() {
return name;
}
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.dal.model.response;
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
@@ -22,9 +22,14 @@ import java.util.List;
@Getter
@Setter
public class SystemProductLineTreeVo extends KitObject {
public class CuteProductLineSelectProVo extends KitObject {
/**
* 部门ID(select的value)
*/
private String value;
/**
* 产品线,如"研发部/华南分部/devops组"
*/
private String label;
private List<SystemProductLineTreeVo> children;
private List<CuteProductLineSelectProVo> children;
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.dal.model.response;
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
@@ -21,12 +21,12 @@ import lombok.Setter;
@Getter
@Setter
public class SystemProductLineVo extends KitObject {
public class CuteProductLineSelectVo extends KitObject {
/**
* 部门ID(select的value)
*/
private Long value;
private String value;
/**
* 产品线,如"研发部/华南分部/devops组"
*/
@@ -0,0 +1,31 @@
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CuteUserSelectVo extends KitObject {
/**
* username
*/
private String value;
/**
* nickname
*/
private String label;
/**
* 部门ID
*/
private String deptId;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String phone;
}
@@ -0,0 +1,24 @@
package cn.odboy.system.application.service;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.mysql.SystemDeptMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
public class CuteBaseService {
@Autowired
private SystemDeptMapper systemDeptMapper;
/**
* 查询启用的所有部门集合
*
* @return /
*/
public List<SystemDeptTb> listEnabledDept() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemDeptTb::getEnabled, 1);
return systemDeptMapper.selectList(wrapper);
}
}
@@ -0,0 +1,65 @@
package cn.odboy.system.application.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.system.application.model.CuteDeptTreeVo;
import cn.odboy.system.constant.SystemDataScopeEnum;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.model.request.SystemQueryDeptArgs;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.system.service.SystemDeptService;
import cn.odboy.util.KitClassUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CuteDeptTreeService {
@Autowired
private SystemDeptService systemDeptService;
public List<CuteDeptTreeVo> listMetadata(SystemQueryDeptArgs args) throws Exception {
String dataScopeType = KitSecurityHelper.getDataScopeType();
if (dataScopeType.equals(SystemDataScopeEnum.ALL.getValue())) {
args.setPidIsNull(true);
}
List<Field> fields = KitClassUtil.getAllFields(args.getClass(), new ArrayList<>());
List<String> fieldNames = new ArrayList<>() {{
add("pidIsNull");
add("enabled");
}};
for (Field field : fields) {
// 设置对象的访问权限, 保证对private的属性的访问
field.setAccessible(true);
Object val = field.get(args);
if (fieldNames.contains(field.getName())) {
continue;
}
if (ObjectUtil.isNotNull(val)) {
args.setPidIsNull(null);
break;
}
}
// 数据权限
args.setIds(KitSecurityHelper.getCurrentUserDataScope());
List<SystemDeptTb> list = systemDeptService.queryDeptByArgs(args);
// 如果为空, 就代表为自定义权限或者本级权限, 就需要去重, 不理解可以注释掉,看查询结果
if (StrUtil.isBlank(dataScopeType)) {
return systemDeptService.filterRootDeptList(list).stream().map(this::convertToVo).collect(Collectors.toList());
}
return list.stream().map(this::convertToVo).collect(Collectors.toList());
}
private CuteDeptTreeVo convertToVo(SystemDeptTb record) {
CuteDeptTreeVo treeVo = new CuteDeptTreeVo();
treeVo.setId(Long.toString(record.getId()));
treeVo.setName(record.getName());
treeVo.setPid(record.getPid() == null ? null : Long.toString(record.getPid()));
treeVo.setSubCount(record.getSubCount());
return treeVo;
}
}
@@ -0,0 +1,67 @@
package cn.odboy.system.application.service;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.odboy.framework.context.KitRequestHolder;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.server.core.KitFileLocalUploadHelper;
import cn.odboy.system.dal.dataobject.SystemLocalStorageTb;
import cn.odboy.system.dal.mysql.SystemLocalStorageMapper;
import cn.odboy.util.KitFileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Date;
@Slf4j
@Service
public class CuteFileUploadService {
@Autowired
private SystemLocalStorageMapper systemLocalStorageMapper;
@Autowired
private KitFileLocalUploadHelper fileUploadPathHelper;
@Autowired
private AppProperties properties;
@Transactional(rollbackFor = Exception.class)
public String uploadLocal(MultipartFile multipartFile) {
long size = multipartFile.getSize();
KitFileUtil.checkSize(properties.getOss().getMaxSize(), size);
String suffix = KitFileUtil.getSuffix(multipartFile.getOriginalFilename());
String type = KitFileUtil.getFileType(suffix);
String uploadDateStr = DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);
File file = KitFileUtil.upload(multipartFile, fileUploadPathHelper.getPath() + uploadDateStr + File.separator);
if (file == null) {
throw new BadRequestException("上传失败");
}
try {
String formatSize = KitFileUtil.getSize(size);
String prefixName = KitFileUtil.getPrefix(multipartFile.getOriginalFilename(), null);
SystemLocalStorageTb localStorage = new SystemLocalStorageTb();
localStorage.setRealName(file.getName());
localStorage.setName(prefixName);
localStorage.setSuffix(suffix);
localStorage.setPath(file.getPath());
localStorage.setType(type);
localStorage.setSize(formatSize);
localStorage.setDateGroup(uploadDateStr);
systemLocalStorageMapper.insert(localStorage);
// 构建上传路径 /file/20260117/odboycn-20260117055246428.png
HttpServletRequest httpServletRequest = KitRequestHolder.getHttpServletRequest();
StringBuffer requestURL = httpServletRequest.getRequestURL();
String[] splits = requestURL.toString().split("/api/component/CuteFileUpload");
String requestAddress = splits[0];
return String.format("%s/file/%s/%s", requestAddress, uploadDateStr, localStorage.getRealName());
} catch (Exception e) {
log.error("上传文件失败", e);
KitFileUtil.del(file);
throw e;
}
}
}
@@ -0,0 +1,69 @@
package cn.odboy.system.application.service;
import cn.odboy.system.application.model.CuteProductLineSelectProVo;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class CuteProductLineSelectProService extends CuteBaseService {
/**
* 产品线选择组件Pro版 数据源
*
* @return /
*/
public List<CuteProductLineSelectProVo> listMetadata() {
List<SystemDeptTb> depts = this.listEnabledDept();
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<CuteProductLineSelectProVo> options = new ArrayList<>();
// 构建树形结构
for (SystemDeptTb dept : depts) {
// 只处理顶级部门(pid为null或0的部门)
if (dept.getPid() == null || dept.getPid() == 0) {
CuteProductLineSelectProVo vo = this.buildDeptTreePro(dept, deptMap);
options.add(vo);
}
}
// 按排序字段排序
options.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
return options;
}
/**
* 递归构建部门树
*
* @param dept 当前部门
* @param deptMap 部门映射
* @return CuteProductLineSelectProVo 树节点
*/
private CuteProductLineSelectProVo buildDeptTreePro(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
CuteProductLineSelectProVo vo = new CuteProductLineSelectProVo();
vo.setValue(String.valueOf(dept.getId()));
vo.setLabel(dept.getName());
// 查找子部门
List<CuteProductLineSelectProVo> children = new ArrayList<>();
for (SystemDeptTb childDept : deptMap.values()) {
if (dept.getId().equals(childDept.getPid())) {
children.add(this.buildDeptTreePro(childDept, deptMap));
}
}
// 子部门按排序字段排序
children.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
vo.setChildren(children);
return vo;
}
}
@@ -0,0 +1,70 @@
package cn.odboy.system.application.service;
import cn.odboy.system.application.model.CuteProductLineSelectVo;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class CuteProductLineSelectService extends CuteBaseService {
/**
* 产品线选择组件 数据源
*
* @return /
*/
public List<CuteProductLineSelectVo> listMetadata() {
List<SystemDeptTb> depts = this.listEnabledDept();
return this.buildDeptMetadata(depts);
}
private List<CuteProductLineSelectVo> buildDeptMetadata(List<SystemDeptTb> depts) {
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<CuteProductLineSelectVo> options = new ArrayList<>();
for (SystemDeptTb dept : depts) {
// 构建部门ID路径
List<Long> pathIds = new ArrayList<>();
this.buildDeptIdPath(dept, deptMap, pathIds);
// 反转路径,从顶级部门到当前部门
Collections.reverse(pathIds);
CuteProductLineSelectVo dto = new CuteProductLineSelectVo();
dto.setValue(Long.toString(dept.getId()));
dto.setIdPath(pathIds.stream().map(String::valueOf).collect(Collectors.joining("-")));
// 保留名称路径用于显示
dto.setLabel(this.buildNamePath(dept, deptMap));
options.add(dto);
}
// 按部门名称路径排序
options.sort(Comparator.comparing(CuteProductLineSelectVo::getLabel));
return options;
}
private void buildDeptIdPath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<Long> pathIds) {
pathIds.add(dept.getId());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptIdPath(deptMap.get(dept.getPid()), deptMap, pathIds);
}
}
private String buildNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
List<String> pathNames = new ArrayList<>();
this.buildDeptNamePath(dept, deptMap, pathNames);
Collections.reverse(pathNames);
return String.join(" / ", pathNames);
}
private void buildDeptNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<String> pathNames) {
pathNames.add(dept.getName());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptNamePath(deptMap.get(dept.getPid()), deptMap, pathNames);
}
}
}
@@ -0,0 +1,68 @@
package cn.odboy.system.application.service;
import cn.hutool.core.collection.CollUtil;
import cn.odboy.system.application.model.CuteUserSelectVo;
import cn.odboy.system.dal.dataobject.SystemUserTb;
import cn.odboy.system.dal.model.request.SystemQueryUserArgs;
import cn.odboy.system.dal.mysql.SystemUserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CuteUserSelectService {
@Autowired
private SystemUserMapper systemUserMapper;
/**
* 模糊查询用户基础信息,限制返回的条数
*
* @param args 查询参数
* @return /
*/
public List<CuteUserSelectVo> listMetadata(SystemQueryUserArgs args) {
LambdaQueryWrapper<SystemUserTb> wrapper = new LambdaQueryWrapper<>();
wrapper.select(SystemUserTb::getUsername, SystemUserTb::getNickName, SystemUserTb::getDeptId, SystemUserTb::getEmail, SystemUserTb::getPhone);
wrapper.and(c -> {
c.eq(SystemUserTb::getPhone, args.getBlurry());
c.or();
c.eq(SystemUserTb::getEmail, args.getBlurry());
c.or();
c.like(SystemUserTb::getUsername, args.getBlurry());
c.or();
c.like(SystemUserTb::getNickName, args.getBlurry());
});
return systemUserMapper.selectPage(new Page<>(1, 50), wrapper).convert(m -> {
CuteUserSelectVo selectVo = new CuteUserSelectVo();
selectVo.setValue(m.getUsername());
selectVo.setLabel(m.getNickName());
selectVo.setDeptId(Long.toString(m.getDeptId()));
selectVo.setEmail(m.getEmail());
selectVo.setPhone(m.getPhone());
return selectVo;
}).getRecords();
}
public List<CuteUserSelectVo> listMetadataByUsernames(List<String> usernameList) {
if (CollUtil.isEmpty(usernameList)) {
return new ArrayList<>();
}
LambdaQueryWrapper<SystemUserTb> wrapper = new LambdaQueryWrapper<>();
wrapper.select(SystemUserTb::getUsername, SystemUserTb::getNickName, SystemUserTb::getDeptId, SystemUserTb::getEmail, SystemUserTb::getPhone);
wrapper.in(SystemUserTb::getUsername, usernameList);
return systemUserMapper.selectList(wrapper).stream().map(m -> {
CuteUserSelectVo selectVo = new CuteUserSelectVo();
selectVo.setValue(m.getUsername());
selectVo.setLabel(m.getNickName());
selectVo.setDeptId(Long.toString(m.getDeptId()));
selectVo.setEmail(m.getEmail());
selectVo.setPhone(m.getPhone());
return selectVo;
}).collect(Collectors.toList());
}
}
@@ -28,4 +28,8 @@ public interface SystemCacheKey {
* 登录验证码
*/
String CAPTCHA_LOGIN = "captcha::login:";
/**
* 用户信息
*/
String USER_INFO = "user::info:";
}
@@ -21,7 +21,6 @@ import cn.odboy.system.dal.model.response.SystemAuthVo;
import cn.odboy.system.service.SystemAuthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
@@ -29,6 +28,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletRequest;
/**
* 授权、根据token获取用户详细信息
@@ -1,49 +0,0 @@
/*
* Copyright 2021-2026 Odboy
*
* 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.
*/
package cn.odboy.system.controller;
import cn.odboy.system.service.SystemDeptService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统:组件数据源")
@RequestMapping("/api/component")
public class SystemComponentController {
@Autowired
private SystemDeptService systemDeptService;
@ApiOperation("查询部门下拉选择数据源")
@PostMapping(value = "/listDeptSelectDataSource")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listDeptSelectDataSource() {
return ResponseEntity.ok(systemDeptService.listDeptSelectDataSource());
}
@ApiOperation("查询部门下拉选择Pro数据源")
@PostMapping(value = "/listDeptSelectProDataSource")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listDeptSelectProDataSource() {
return ResponseEntity.ok(systemDeptService.listDeptSelectProDataSource());
}
}
@@ -17,7 +17,6 @@ package cn.odboy.system.controller;
import cn.odboy.base.KitPageArgs;
import cn.odboy.base.KitPageResult;
import cn.odboy.base.KitSelectOptionVo;
import cn.odboy.system.dal.dataobject.SystemUserTb;
import cn.odboy.system.dal.model.request.SystemQueryUserArgs;
import cn.odboy.system.dal.model.request.SystemUpdateUserPasswordArgs;
@@ -43,7 +42,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Set;
@Api(tags = "系统:用户管理")
@@ -141,13 +139,6 @@ public class SystemUserController {
return ResponseEntity.ok(null);
}
@ApiOperation("查询用户基础数据")
@PostMapping(value = "/queryUserMetadataOptions")
@PreAuthorize("@el.check('user:list')")
public ResponseEntity<List<KitSelectOptionVo>> queryUserMetadataOptions(@Validated @RequestBody KitPageArgs<SystemQueryUserArgs> args) {
List<KitSelectOptionVo> collect = systemUserService.queryUserMetadataOptions(args);
return ResponseEntity.ok(collect);
}
@ApiOperation("获取用户信息")
@PostMapping(value = "/getCurrentUserInfo")
@@ -20,10 +20,10 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.util.Objects;
@Getter
@@ -16,6 +16,7 @@
package cn.odboy.system.dal.model.response;
import cn.odboy.base.KitBaseUserTimeTb;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.dataobject.SystemJobTb;
import cn.odboy.system.dal.dataobject.SystemRoleTb;
import io.swagger.annotations.ApiModelProperty;
@@ -60,7 +61,7 @@ public class SystemUserVo extends KitBaseUserTimeTb {
* 扩展字段
*/
@ApiModelProperty(value = "用户部门")
private SystemDeptVo dept;
private SystemDeptTb dept;
@ApiModelProperty(value = "用户角色")
private Set<SystemRoleTb> roles;
@ApiModelProperty(value = "用户岗位")
@@ -43,7 +43,7 @@ public class SystemUserInfoDAO {
if (StrUtil.isNotEmpty(userName)) {
// 添加数据, 避免数据同时过期(2小时左右)
long time = 7200 + RandomUtil.randomInt(900, 1800);
redisHelper.set(SystemCacheKey.ONLINE_USER + userName, user, time);
redisHelper.set(SystemCacheKey.USER_INFO + userName, user, time);
}
}
@@ -56,7 +56,7 @@ public class SystemUserInfoDAO {
public void deleteUserLoginInfoByUserName(String userName) {
if (StrUtil.isNotEmpty(userName)) {
// 清除数据
redisHelper.del(SystemCacheKey.ONLINE_USER + userName);
redisHelper.del(SystemCacheKey.USER_INFO + userName);
}
}
@@ -69,7 +69,7 @@ public class SystemUserInfoDAO {
public SystemUserJwtVo getUserLoginInfoByUserName(String username) {
if (StrUtil.isNotEmpty(username)) {
// 获取数据
return redisHelper.get(SystemCacheKey.ONLINE_USER + username, SystemUserJwtVo.class);
return redisHelper.get(SystemCacheKey.USER_INFO + username, SystemUserJwtVo.class);
}
return null;
}
@@ -27,8 +27,6 @@ import cn.odboy.system.dal.model.export.SystemDeptExportRowVo;
import cn.odboy.system.dal.model.request.SystemCreateDeptArgs;
import cn.odboy.system.dal.model.request.SystemQueryDeptArgs;
import cn.odboy.system.dal.model.response.SystemDeptVo;
import cn.odboy.system.dal.model.response.SystemProductLineTreeVo;
import cn.odboy.system.dal.model.response.SystemProductLineVo;
import cn.odboy.system.dal.mysql.SystemDeptMapper;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.util.KitBeanUtil;
@@ -42,14 +40,11 @@ import org.springframework.transaction.annotation.Transactional;
import jakarta.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@@ -107,10 +102,10 @@ public class SystemDeptService {
@Transactional(rollbackFor = Exception.class)
public void deleteDeptByIds(Set<Long> ids) {
// 查询部门, 和其所有子部门
Set<SystemDeptVo> depts = this.traverseDeptByIdWithPids(ids);
Set<SystemDeptTb> depts = this.traverseDeptByIdWithPids(ids);
// 验证是否被角色或用户关联
this.verifyBindRelationByIds(depts);
for (SystemDeptVo dept : depts) {
for (SystemDeptTb dept : depts) {
systemDeptMapper.deleteById(dept.getId());
this.updateDeptSubCnt(dept.getPid());
}
@@ -171,16 +166,6 @@ public class SystemDeptService {
return list;
}
/**
* 根据ID查询
*
* @param id /
* @return /
*/
public SystemDeptVo getDeptVoById(Long id) {
return KitBeanUtil.copyToClass(systemDeptMapper.selectById(id), SystemDeptVo.class);
}
/**
* 根据部门id遍历所有部门和子部门id集合
*
@@ -207,14 +192,15 @@ public class SystemDeptService {
* @return /
*/
public KitPageResult<SystemDeptVo> searchDeptTree(List<Long> ids, Boolean exclude) {
Set<SystemDeptVo> deptSet1 = new LinkedHashSet<>();
Map<Long, SystemDeptTb> allDeptMap = this.getAllDeptMap();
Set<SystemDeptTb> deptSet1 = new LinkedHashSet<>();
for (Long id : ids) {
// 同级数据
SystemDeptVo dept = this.getDeptVoById(id);
SystemDeptTb dept = allDeptMap.get(id);
// 上级数据
List<SystemDeptVo> depts = this.querySuperiorDeptByPid(dept, new ArrayList<>());
List<SystemDeptTb> depts = this.querySuperiorDeptByPid(dept, new ArrayList<>(), allDeptMap);
if (exclude) {
for (SystemDeptVo data : depts) {
for (SystemDeptTb data : depts) {
if (data.getId().equals(dept.getPid())) {
data.setSubCount(data.getSubCount() - 1);
}
@@ -224,18 +210,20 @@ public class SystemDeptService {
}
deptSet1.addAll(depts);
}
List<SystemDeptVo> deptList = new ArrayList<>(deptSet1);
List<SystemDeptTb> deptList = new ArrayList<>(deptSet1);
// 构建部门树
Set<SystemDeptVo> trees = new LinkedHashSet<>();
Set<SystemDeptVo> deptSet = new LinkedHashSet<>();
List<String> deptNames = deptList.stream().map(SystemDeptVo::getName).collect(Collectors.toList());
List<String> deptNames = deptList.stream().map(SystemDeptTb::getName).collect(Collectors.toList());
boolean isChild;
for (SystemDeptVo dept : deptList) {
List<SystemDeptVo> systemDeptVos = KitBeanUtil.copyToList(deptList, SystemDeptVo.class);
for (SystemDeptVo dept : systemDeptVos) {
isChild = false;
if (dept.getPid() == null) {
trees.add(dept);
}
for (SystemDeptVo it : deptList) {
for (SystemDeptVo it : systemDeptVos) {
if (it.getPid() != null && dept.getId().equals(it.getPid())) {
isChild = true;
if (dept.getChildren() == null) {
@@ -246,7 +234,7 @@ public class SystemDeptService {
}
if (isChild) {
deptSet.add(dept);
} else if (dept.getPid() != null && !deptNames.contains(this.getDeptVoById(dept.getPid()).getName())) {
} else if (dept.getPid() != null && !deptNames.contains(allDeptMap.get(dept.getPid()).getName())) {
deptSet.add(dept);
}
}
@@ -259,13 +247,18 @@ public class SystemDeptService {
return baseResult;
}
private Map<Long, SystemDeptTb> getAllDeptMap() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
return systemDeptMapper.selectList(wrapper).stream().collect(Collectors.toMap(SystemDeptTb::getId, i -> i, (m, n) -> m));
}
/**
* 验证是否被角色或用户关联
*
* @param deptSet /
*/
public void verifyBindRelationByIds(Set<SystemDeptVo> deptSet) {
Set<Long> deptIds = deptSet.stream().map(SystemDeptVo::getId).collect(Collectors.toSet());
public void verifyBindRelationByIds(Set<SystemDeptTb> deptSet) {
Set<Long> deptIds = deptSet.stream().map(SystemDeptTb::getId).collect(Collectors.toSet());
if (systemUserDeptService.countUserByDeptIds(deptIds) > 0) {
throw new BadRequestException("所选部门存在用户关联,请解除后再试!");
}
@@ -279,13 +272,13 @@ public class SystemDeptService {
*
* @param ids 部门id集合
*/
public Set<SystemDeptVo> traverseDeptByIdWithPids(Set<Long> ids) {
Set<SystemDeptVo> depts = new HashSet<>();
public Set<SystemDeptTb> traverseDeptByIdWithPids(Set<Long> ids) {
Set<SystemDeptTb> depts = new HashSet<>();
for (Long id : ids) {
// 根部门
depts.add(this.getDeptVoById(id));
depts.add(systemDeptMapper.selectById(id));
// 子部门
List<SystemDeptVo> deptList = this.listDeptVoByPid(id);
List<SystemDeptTb> deptList = this.listDeptByPid(id);
if (CollUtil.isNotEmpty(deptList)) {
this.queryRelationDeptByArgs(deptList, depts);
}
@@ -293,43 +286,6 @@ public class SystemDeptService {
return depts;
}
/**
* 产品线选择组件 数据源
*
* @return /
*/
public List<SystemProductLineVo> listDeptSelectDataSource() {
List<SystemDeptTb> depts = this.listEnabledDepts();
return this.buildDeptSelectOptions(depts);
}
/**
* 产品线选择组件Pro版 数据源
*
* @return /
*/
public List<SystemProductLineTreeVo> listDeptSelectProDataSource() {
List<SystemDeptTb> depts = this.listEnabledDepts();
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<SystemProductLineTreeVo> options = new ArrayList<>();
// 构建树形结构
for (SystemDeptTb dept : depts) {
// 只处理顶级部门(pid为null或0的部门)
if (dept.getPid() == null || dept.getPid() == 0) {
SystemProductLineTreeVo vo = this.buildDeptTreePro(dept, deptMap);
options.add(vo);
}
}
// 按排序字段排序
options.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
return options;
}
/**
* 根据父部门id查询部门集合
*
@@ -373,137 +329,37 @@ public class SystemDeptService {
return systemDeptMapper.selectList(wrapper);
}
/**
* 递归构建部门树
*
* @param dept 当前部门
* @param deptMap 部门映射
* @return SystemProductLineTreeVo 树节点
*/
private SystemProductLineTreeVo buildDeptTreePro(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
SystemProductLineTreeVo vo = new SystemProductLineTreeVo();
vo.setValue(String.valueOf(dept.getId()));
vo.setLabel(dept.getName());
// 查找子部门
List<SystemProductLineTreeVo> children = new ArrayList<>();
for (SystemDeptTb childDept : deptMap.values()) {
if (dept.getId().equals(childDept.getPid())) {
children.add(this.buildDeptTreePro(childDept, deptMap));
}
}
// 子部门按排序字段排序
children.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
vo.setChildren(children);
return vo;
}
/**
* 产品线选择组件使用
*
* @param depts 部门集合
* @return /
*/
private List<SystemProductLineVo> buildDeptSelectOptions(List<SystemDeptTb> depts) {
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<SystemProductLineVo> options = new ArrayList<>();
for (SystemDeptTb dept : depts) {
// 构建部门ID路径
List<Long> pathIds = new ArrayList<>();
this.buildDeptIdPath(dept, deptMap, pathIds);
// 反转路径,从顶级部门到当前部门
Collections.reverse(pathIds);
SystemProductLineVo dto = new SystemProductLineVo();
dto.setValue(dept.getId());
dto.setIdPath(pathIds.stream().map(String::valueOf).collect(Collectors.joining("-")));
// 保留名称路径用于显示
dto.setLabel(this.buildNamePath(dept, deptMap));
options.add(dto);
}
// 按部门名称路径排序
options.sort(Comparator.comparing(SystemProductLineVo::getLabel));
return options;
}
/**
* 产品线选择组件使用
*/
private void buildDeptIdPath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<Long> pathIds) {
pathIds.add(dept.getId());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptIdPath(deptMap.get(dept.getPid()), deptMap, pathIds);
}
}
/**
* 产品线选择组件使用
*/
private String buildNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
List<String> pathNames = new ArrayList<>();
this.buildDeptNamePath(dept, deptMap, pathNames);
Collections.reverse(pathNames);
return String.join(" / ", pathNames);
}
/**
* 产品线选择组件使用
*/
private void buildDeptNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<String> pathNames) {
pathNames.add(dept.getName());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptNamePath(deptMap.get(dept.getPid()), deptMap, pathNames);
}
}
/**
* 查询启用的所有部门集合
*
* @return /
*/
private List<SystemDeptTb> listEnabledDepts() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemDeptTb::getEnabled, 1);
return systemDeptMapper.selectList(wrapper);
}
/**
* 查询部门下所有关联的部门
*
* @param deptTbList /
* @param depts /
*/
private void queryRelationDeptByArgs(List<SystemDeptVo> deptTbList, Set<SystemDeptVo> depts) {
for (SystemDeptVo dept : deptTbList) {
private void queryRelationDeptByArgs(List<SystemDeptTb> deptTbList, Set<SystemDeptTb> depts) {
for (SystemDeptTb dept : deptTbList) {
depts.add(dept);
List<SystemDeptVo> deptList = this.listDeptVoByPid(dept.getId());
List<SystemDeptTb> deptList = this.listDeptByPid(dept.getId());
if (CollUtil.isNotEmpty(deptList)) {
this.queryRelationDeptByArgs(deptList, depts);
}
}
}
private List<SystemDeptVo> listDeptVoByPid(Long pid) {
return KitBeanUtil.copyToList(this.listDeptByPid(pid), SystemDeptVo.class);
}
/**
* 根据ID查询同级与上级数据
*
* @param dept /
* @param deptList /
* @param allDeptMap
* @return /
*/
private List<SystemDeptVo> querySuperiorDeptByPid(SystemDeptVo dept, List<SystemDeptVo> deptList) {
private List<SystemDeptTb> querySuperiorDeptByPid(SystemDeptTb dept, List<SystemDeptTb> deptList, Map<Long, SystemDeptTb> allDeptMap) {
if (dept.getPid() == null) {
deptList.addAll(this.listRootDept());
return deptList;
}
deptList.addAll(this.listDeptVoByPid(dept.getPid()));
return querySuperiorDeptByPid(this.getDeptVoById(dept.getPid()), deptList);
deptList.addAll(this.listDeptByPid(dept.getPid()));
return querySuperiorDeptByPid(allDeptMap.get(dept.getPid()), deptList, allDeptMap);
}
/**
@@ -511,10 +367,10 @@ public class SystemDeptService {
*
* @return /
*/
private List<SystemDeptVo> listRootDept() {
private List<SystemDeptTb> listRootDept() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
wrapper.isNull(SystemDeptTb::getPid);
return KitBeanUtil.copyToList(systemDeptMapper.selectList(wrapper), SystemDeptVo.class);
return systemDeptMapper.selectList(wrapper);
}
/**
@@ -523,7 +379,7 @@ public class SystemDeptService {
* @param id 部门id
* @return /
*/
private SystemDeptTb getDeptById(Long id) {
public SystemDeptTb getDeptById(Long id) {
return systemDeptMapper.selectById(id);
}
@@ -542,7 +398,7 @@ public class SystemDeptService {
/**
* 筛选出 list 中没有父部门(即 pid 不在其他部门 id 列表中的部门)的部门列表
*/
private List<SystemDeptTb> filterRootDeptList(List<SystemDeptTb> list) {
public List<SystemDeptTb> filterRootDeptList(List<SystemDeptTb> list) {
List<SystemDeptTb> deptList = new ArrayList<>();
// 使用 Set 存储所有部门的 id
Set<Long> idSet = list.stream().map(SystemDeptTb::getId).collect(Collectors.toSet());
@@ -561,7 +417,7 @@ public class SystemDeptService {
* @param args /
* @return /
*/
private List<SystemDeptTb> queryDeptByArgs(SystemQueryDeptArgs args) {
public List<SystemDeptTb> queryDeptByArgs(SystemQueryDeptArgs args) {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
if (args != null) {
wrapper.in(CollUtil.isNotEmpty(args.getIds()), SystemDeptTb::getId, args.getIds());
@@ -17,9 +17,7 @@ package cn.odboy.system.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.base.KitPageArgs;
import cn.odboy.base.KitPageResult;
import cn.odboy.base.KitSelectOptionVo;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.server.core.KitFileLocalUploadHelper;
@@ -333,36 +331,6 @@ public class SystemUserService {
return systemUserMapper.selectCount(wrapper);
}
/**
* 模糊查询用户基础信息,限制返回的条数
*
* @param pageArgs 分页参数
* @return /
*/
public List<KitSelectOptionVo> queryUserMetadataOptions(KitPageArgs<SystemQueryUserArgs> pageArgs) {
SystemQueryUserArgs args = pageArgs.getArgs();
LambdaQueryWrapper<SystemUserTb> wrapper = new LambdaQueryWrapper<>();
wrapper.select(
SystemUserTb::getId, SystemUserTb::getUsername, SystemUserTb::getNickName, SystemUserTb::getDeptId, SystemUserTb::getEmail, SystemUserTb::getPhone);
wrapper.and(c -> {
c.eq(SystemUserTb::getPhone, args.getBlurry());
c.or();
c.eq(SystemUserTb::getEmail, args.getBlurry());
c.or();
c.like(SystemUserTb::getUsername, args.getBlurry());
c.or();
c.like(SystemUserTb::getNickName, args.getBlurry());
});
return systemUserMapper.selectPage(new Page<>(pageArgs.getPage(), 50), wrapper).getRecords().stream().map(m -> {
Map<String, Object> ext = new HashMap<>(1);
ext.put("id", m.getId());
ext.put("deptId", m.getDeptId());
ext.put("email", m.getEmail());
ext.put("phone", m.getPhone());
return KitSelectOptionVo.builder().label(m.getNickName()).value(String.valueOf(m.getId())).ext(ext).build();
}).collect(Collectors.toList());
}
/**
* 根据用户名查询启用的用户信息
*
@@ -399,10 +367,7 @@ public class SystemUserService {
/**
* 聚合查询 -> TestPassed
*/
public KitPageResult<SystemUserVo> aggregationSearchUserByArgs(
Page<SystemUserTb> page, SystemQueryUserArgs args,
String currentUsername
) {
public KitPageResult<SystemUserVo> aggregationSearchUserByArgs(Page<SystemUserTb> page, SystemQueryUserArgs args, String currentUsername) {
if (!ObjectUtils.isEmpty(args.getDeptId())) {
args.getDeptIds().add(args.getDeptId());
// 先查找是否存在子节点
@@ -584,7 +549,7 @@ public class SystemUserService {
SystemUserVo userVo = KitBeanUtil.copyToClass(user, SystemUserVo.class);
// 查询关联的部门信息
if (user.getDeptId() != null) {
userVo.setDept(systemDeptService.getDeptVoById(user.getDeptId()));
userVo.setDept(systemDeptService.getDeptById(user.getDeptId()));
}
// 查询关联的岗位信息
userVo.setJobs(systemUserJobService.listUserJobByUserId(user.getId()));
@@ -592,4 +557,5 @@ public class SystemUserService {
userVo.setRoles(systemUserRoleService.listUserRoleByUserId(user.getId()));
return userVo;
}
}
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -15,7 +15,7 @@
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>cutejava-module-system</artifactId>
<version>1.5.0</version>
<version>1.5.2</version>
</dependency>
</dependencies>
@@ -5,4 +5,4 @@
| |___ | |_| | | | | |___ | |_| | / / | | | |/ / / / | |
\_____| \_____/ |_| |_____| \_____/ /_/ |_| |___/ /_/ |_|
Spring Boot Version: (${spring-boot.version}),CuteJava Version: (1.5.0)
Spring Boot Version: (${spring-boot.version}),CuteJava Version: (1.5.2)
+1 -1
View File
@@ -5,7 +5,7 @@
<groupId>cn.odboy</groupId>
<artifactId>cutejava</artifactId>
<packaging>pom</packaging>
<version>1.5.0</version>
<version>1.5.2</version>
<modules>
<!-- 基础设施 -->
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-framework</artifactId>
@@ -111,7 +111,7 @@ public class SwaggerConfig {
private ApiInfo apiInfo() {
return new ApiInfoBuilder().description("一个简单且易上手的自动化运维平台").title("CuteJava 接口文档")
.version("1.5.0").build();
.version("1.5.2").build();
}
private List<SecurityScheme> securitySchemes() {
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-module-system</artifactId>
@@ -13,7 +13,7 @@
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>cutejava-framework</artifactId>
<version>1.5.0</version>
<version>1.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.minio/minio -->
<dependency>
@@ -0,0 +1,32 @@
package cn.odboy.system.application;
import cn.odboy.system.application.model.CuteDeptTreeVo;
import cn.odboy.system.application.service.CuteDeptTreeService;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.model.request.SystemQueryDeptArgs;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
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;
import java.util.List;
@RestController
@Api(tags = "系统组件:CuteDeptTree")
@RequestMapping("/api/component/CuteDeptTree")
public class CuteDeptTreeApi {
@Autowired
private CuteDeptTreeService cuteDeptTreeService;
@ApiOperation("查询部门")
@PostMapping(value = "/listMetadata")
public ResponseEntity<List<CuteDeptTreeVo>> listMetadata(@Validated @RequestBody SystemQueryDeptArgs args) throws Exception {
List<CuteDeptTreeVo> depts = cuteDeptTreeService.listMetadata(args);
return ResponseEntity.ok(depts);
}
}
@@ -0,0 +1,45 @@
package cn.odboy.system.application;
import cn.odboy.system.application.service.CuteFileUploadService;
import cn.odboy.system.framework.operalog.OperationLog;
import cn.odboy.system.service.SystemLocalStorageService;
import cn.odboy.system.service.SystemOssStorageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@Api(tags = "系统组件:CuteFileUpload")
@RequestMapping("/api/component/CuteFileUpload")
public class CuteFileUploadApi {
@Autowired
private CuteFileUploadService cuteFileUploadService;
@Autowired
private SystemOssStorageService systemOssStorageService;
@OperationLog
@ApiOperation("上传文件到服务器本地")
@PostMapping(value = "/uploadLocal")
@PreAuthorize("@el.check()")
public ResponseEntity<String> uploadLocal(@RequestParam("file") MultipartFile file) {
String fileUrl = cuteFileUploadService.uploadLocal(file);
return ResponseEntity.ok(fileUrl);
}
@OperationLog
@ApiOperation("上传文件到OSS")
@PostMapping(value = "/uploadOSS")
@PreAuthorize("@el.check()")
public ResponseEntity<String> uploadOSS(@RequestParam("file") MultipartFile file) {
String fileUrl = systemOssStorageService.uploadFile(file);
return ResponseEntity.ok(fileUrl);
}
}
@@ -0,0 +1,27 @@
package cn.odboy.system.application;
import cn.odboy.system.application.service.CuteProductLineSelectService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统组件:CuteProductLineSelect")
@RequestMapping("/api/component/CuteProductLineSelect")
public class CuteProductLineSelectApi {
@Autowired
private CuteProductLineSelectService cuteProductLineSelectService;
@ApiOperation("查询部门下拉选择数据源")
@PostMapping(value = "/listMetadata")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listMetadata() {
return ResponseEntity.ok(cuteProductLineSelectService.listMetadata());
}
}
@@ -0,0 +1,27 @@
package cn.odboy.system.application;
import cn.odboy.system.application.service.CuteProductLineSelectProService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统组件:CuteProductLineSelectPro")
@RequestMapping("/api/component/CuteProductLineSelectPro")
public class CuteProductLineSelectProApi {
@Autowired
private CuteProductLineSelectProService cuteProductLineSelectProService;
@ApiOperation("查询部门下拉选择Pro数据源")
@PostMapping(value = "/listMetadata")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listMetadata() {
return ResponseEntity.ok(cuteProductLineSelectProService.listMetadata());
}
}
@@ -0,0 +1,41 @@
package cn.odboy.system.application;
import cn.odboy.system.application.model.CuteUserSelectVo;
import cn.odboy.system.application.service.CuteUserSelectService;
import cn.odboy.system.dal.model.request.SystemQueryUserArgs;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
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;
import java.util.List;
@RestController
@Api(tags = "系统组件:CuteUserSelect")
@RequestMapping("/api/component/CuteUserSelect")
public class CuteUserSelectApi {
@Autowired
private CuteUserSelectService cuteUserSelectService;
@ApiOperation("查询用户基础数据")
@PostMapping(value = "/listMetadata")
@PreAuthorize("@el.check()")
public ResponseEntity<List<CuteUserSelectVo>> listMetadata(@Validated @RequestBody SystemQueryUserArgs args) {
List<CuteUserSelectVo> collect = cuteUserSelectService.listMetadata(args);
return ResponseEntity.ok(collect);
}
@ApiOperation("根据用户名称集合查询用户基础数据")
@PostMapping(value = "/listMetadataByUsernames")
@PreAuthorize("@el.check()")
public ResponseEntity<List<CuteUserSelectVo>> listMetadataByUsernames(@RequestBody List<String> usernameList) {
List<CuteUserSelectVo> collect = cuteUserSelectService.listMetadataByUsernames(usernameList);
return ResponseEntity.ok(collect);
}
}
@@ -0,0 +1,48 @@
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CuteDeptTreeVo extends KitObject {
/**
* 部门ID
*/
private String id;
/**
* 部门名称
*/
private String name;
/**
* 上级部门ID
*/
private String pid;
/**
* 子节点数目
*/
private Integer subCount = 0;
/**
* 是否有子节点
*/
public Boolean getHasChildren() {
return subCount > 0;
}
/**
* 是否为叶子
*/
public Boolean getLeaf() {
return subCount <= 0;
}
/**
* 标签名称
*/
public String getLabel() {
return name;
}
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.dal.model.response;
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import java.util.List;
@@ -22,9 +22,14 @@ import lombok.Setter;
@Getter
@Setter
public class SystemProductLineTreeVo extends KitObject {
public class CuteProductLineSelectProVo extends KitObject {
/**
* 部门ID(select的value)
*/
private String value;
/**
* 产品线,如"研发部/华南分部/devops组"
*/
private String label;
private List<SystemProductLineTreeVo> children;
private List<CuteProductLineSelectProVo> children;
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.dal.model.response;
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
@@ -21,12 +21,12 @@ import lombok.Setter;
@Getter
@Setter
public class SystemProductLineVo extends KitObject {
public class CuteProductLineSelectVo extends KitObject {
/**
* 部门ID(select的value)
*/
private Long value;
private String value;
/**
* 产品线,如"研发部/华南分部/devops组"
*/
@@ -0,0 +1,31 @@
package cn.odboy.system.application.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class CuteUserSelectVo extends KitObject {
/**
* username
*/
private String value;
/**
* nickname
*/
private String label;
/**
* 部门ID
*/
private String deptId;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String phone;
}
@@ -0,0 +1,24 @@
package cn.odboy.system.application.service;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.mysql.SystemDeptMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
public class CuteBaseService {
@Autowired
private SystemDeptMapper systemDeptMapper;
/**
* 查询启用的所有部门集合
*
* @return /
*/
public List<SystemDeptTb> listEnabledDept() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemDeptTb::getEnabled, 1);
return systemDeptMapper.selectList(wrapper);
}
}
@@ -0,0 +1,65 @@
package cn.odboy.system.application.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.system.application.model.CuteDeptTreeVo;
import cn.odboy.system.constant.SystemDataScopeEnum;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.model.request.SystemQueryDeptArgs;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.system.service.SystemDeptService;
import cn.odboy.util.KitClassUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CuteDeptTreeService {
@Autowired
private SystemDeptService systemDeptService;
public List<CuteDeptTreeVo> listMetadata(SystemQueryDeptArgs args) throws Exception {
String dataScopeType = KitSecurityHelper.getDataScopeType();
if (dataScopeType.equals(SystemDataScopeEnum.ALL.getValue())) {
args.setPidIsNull(true);
}
List<Field> fields = KitClassUtil.getAllFields(args.getClass(), new ArrayList<>());
List<String> fieldNames = new ArrayList<>() {{
add("pidIsNull");
add("enabled");
}};
for (Field field : fields) {
// 设置对象的访问权限, 保证对private的属性的访问
field.setAccessible(true);
Object val = field.get(args);
if (fieldNames.contains(field.getName())) {
continue;
}
if (ObjectUtil.isNotNull(val)) {
args.setPidIsNull(null);
break;
}
}
// 数据权限
args.setIds(KitSecurityHelper.getCurrentUserDataScope());
List<SystemDeptTb> list = systemDeptService.queryDeptByArgs(args);
// 如果为空, 就代表为自定义权限或者本级权限, 就需要去重, 不理解可以注释掉,看查询结果
if (StrUtil.isBlank(dataScopeType)) {
return systemDeptService.filterRootDeptList(list).stream().map(this::convertToVo).collect(Collectors.toList());
}
return list.stream().map(this::convertToVo).collect(Collectors.toList());
}
private CuteDeptTreeVo convertToVo(SystemDeptTb record) {
CuteDeptTreeVo treeVo = new CuteDeptTreeVo();
treeVo.setId(Long.toString(record.getId()));
treeVo.setName(record.getName());
treeVo.setPid(record.getPid() == null ? null : Long.toString(record.getPid()));
treeVo.setSubCount(record.getSubCount());
return treeVo;
}
}
@@ -0,0 +1,67 @@
package cn.odboy.system.application.service;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.odboy.framework.context.KitRequestHolder;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.server.core.KitFileLocalUploadHelper;
import cn.odboy.system.dal.dataobject.SystemLocalStorageTb;
import cn.odboy.system.dal.mysql.SystemLocalStorageMapper;
import cn.odboy.util.KitFileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Date;
@Slf4j
@Service
public class CuteFileUploadService {
@Autowired
private SystemLocalStorageMapper systemLocalStorageMapper;
@Autowired
private KitFileLocalUploadHelper fileUploadPathHelper;
@Autowired
private AppProperties properties;
@Transactional(rollbackFor = Exception.class)
public String uploadLocal(MultipartFile multipartFile) {
long size = multipartFile.getSize();
KitFileUtil.checkSize(properties.getOss().getMaxSize(), size);
String suffix = KitFileUtil.getSuffix(multipartFile.getOriginalFilename());
String type = KitFileUtil.getFileType(suffix);
String uploadDateStr = DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);
File file = KitFileUtil.upload(multipartFile, fileUploadPathHelper.getPath() + uploadDateStr + File.separator);
if (file == null) {
throw new BadRequestException("上传失败");
}
try {
String formatSize = KitFileUtil.getSize(size);
String prefixName = KitFileUtil.getPrefix(multipartFile.getOriginalFilename(), null);
SystemLocalStorageTb localStorage = new SystemLocalStorageTb();
localStorage.setRealName(file.getName());
localStorage.setName(prefixName);
localStorage.setSuffix(suffix);
localStorage.setPath(file.getPath());
localStorage.setType(type);
localStorage.setSize(formatSize);
localStorage.setDateGroup(uploadDateStr);
systemLocalStorageMapper.insert(localStorage);
// 构建上传路径 /file/20260117/odboycn-20260117055246428.png
HttpServletRequest httpServletRequest = KitRequestHolder.getHttpServletRequest();
StringBuffer requestURL = httpServletRequest.getRequestURL();
String[] splits = requestURL.toString().split("/api/component/CuteFileUpload");
String requestAddress = splits[0];
return String.format("%s/file/%s/%s", requestAddress, uploadDateStr, localStorage.getRealName());
} catch (Exception e) {
log.error("上传文件失败", e);
KitFileUtil.del(file);
throw e;
}
}
}
@@ -0,0 +1,69 @@
package cn.odboy.system.application.service;
import cn.odboy.system.application.model.CuteProductLineSelectProVo;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class CuteProductLineSelectProService extends CuteBaseService {
/**
* 产品线选择组件Pro版 数据源
*
* @return /
*/
public List<CuteProductLineSelectProVo> listMetadata() {
List<SystemDeptTb> depts = this.listEnabledDept();
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<CuteProductLineSelectProVo> options = new ArrayList<>();
// 构建树形结构
for (SystemDeptTb dept : depts) {
// 只处理顶级部门(pid为null或0的部门)
if (dept.getPid() == null || dept.getPid() == 0) {
CuteProductLineSelectProVo vo = this.buildDeptTreePro(dept, deptMap);
options.add(vo);
}
}
// 按排序字段排序
options.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
return options;
}
/**
* 递归构建部门树
*
* @param dept 当前部门
* @param deptMap 部门映射
* @return CuteProductLineSelectProVo 树节点
*/
private CuteProductLineSelectProVo buildDeptTreePro(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
CuteProductLineSelectProVo vo = new CuteProductLineSelectProVo();
vo.setValue(String.valueOf(dept.getId()));
vo.setLabel(dept.getName());
// 查找子部门
List<CuteProductLineSelectProVo> children = new ArrayList<>();
for (SystemDeptTb childDept : deptMap.values()) {
if (dept.getId().equals(childDept.getPid())) {
children.add(this.buildDeptTreePro(childDept, deptMap));
}
}
// 子部门按排序字段排序
children.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
vo.setChildren(children);
return vo;
}
}
@@ -0,0 +1,70 @@
package cn.odboy.system.application.service;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.application.model.CuteProductLineSelectVo;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
public class CuteProductLineSelectService extends CuteBaseService {
/**
* 产品线选择组件 数据源
*
* @return /
*/
public List<CuteProductLineSelectVo> listMetadata() {
List<SystemDeptTb> depts = this.listEnabledDept();
return this.buildDeptMetadata(depts);
}
private List<CuteProductLineSelectVo> buildDeptMetadata(List<SystemDeptTb> depts) {
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<CuteProductLineSelectVo> options = new ArrayList<>();
for (SystemDeptTb dept : depts) {
// 构建部门ID路径
List<Long> pathIds = new ArrayList<>();
this.buildDeptIdPath(dept, deptMap, pathIds);
// 反转路径,从顶级部门到当前部门
Collections.reverse(pathIds);
CuteProductLineSelectVo dto = new CuteProductLineSelectVo();
dto.setValue(Long.toString(dept.getId()));
dto.setIdPath(pathIds.stream().map(String::valueOf).collect(Collectors.joining("-")));
// 保留名称路径用于显示
dto.setLabel(this.buildNamePath(dept, deptMap));
options.add(dto);
}
// 按部门名称路径排序
options.sort(Comparator.comparing(CuteProductLineSelectVo::getLabel));
return options;
}
private void buildDeptIdPath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<Long> pathIds) {
pathIds.add(dept.getId());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptIdPath(deptMap.get(dept.getPid()), deptMap, pathIds);
}
}
private String buildNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
List<String> pathNames = new ArrayList<>();
this.buildDeptNamePath(dept, deptMap, pathNames);
Collections.reverse(pathNames);
return String.join(" / ", pathNames);
}
private void buildDeptNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<String> pathNames) {
pathNames.add(dept.getName());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptNamePath(deptMap.get(dept.getPid()), deptMap, pathNames);
}
}
}
@@ -0,0 +1,68 @@
package cn.odboy.system.application.service;
import cn.hutool.core.collection.CollUtil;
import cn.odboy.system.application.model.CuteUserSelectVo;
import cn.odboy.system.dal.dataobject.SystemUserTb;
import cn.odboy.system.dal.model.request.SystemQueryUserArgs;
import cn.odboy.system.dal.mysql.SystemUserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CuteUserSelectService {
@Autowired
private SystemUserMapper systemUserMapper;
/**
* 模糊查询用户基础信息,限制返回的条数
*
* @param args 查询参数
* @return /
*/
public List<CuteUserSelectVo> listMetadata(SystemQueryUserArgs args) {
LambdaQueryWrapper<SystemUserTb> wrapper = new LambdaQueryWrapper<>();
wrapper.select(SystemUserTb::getUsername, SystemUserTb::getNickName, SystemUserTb::getDeptId, SystemUserTb::getEmail, SystemUserTb::getPhone);
wrapper.and(c -> {
c.eq(SystemUserTb::getPhone, args.getBlurry());
c.or();
c.eq(SystemUserTb::getEmail, args.getBlurry());
c.or();
c.like(SystemUserTb::getUsername, args.getBlurry());
c.or();
c.like(SystemUserTb::getNickName, args.getBlurry());
});
return systemUserMapper.selectPage(new Page<>(1, 50), wrapper).convert(m -> {
CuteUserSelectVo selectVo = new CuteUserSelectVo();
selectVo.setValue(m.getUsername());
selectVo.setLabel(m.getNickName());
selectVo.setDeptId(Long.toString(m.getDeptId()));
selectVo.setEmail(m.getEmail());
selectVo.setPhone(m.getPhone());
return selectVo;
}).getRecords();
}
public List<CuteUserSelectVo> listMetadataByUsernames(List<String> usernameList) {
if (CollUtil.isEmpty(usernameList)) {
return new ArrayList<>();
}
LambdaQueryWrapper<SystemUserTb> wrapper = new LambdaQueryWrapper<>();
wrapper.select(SystemUserTb::getUsername, SystemUserTb::getNickName, SystemUserTb::getDeptId, SystemUserTb::getEmail, SystemUserTb::getPhone);
wrapper.in(SystemUserTb::getUsername, usernameList);
return systemUserMapper.selectList(wrapper).stream().map(m -> {
CuteUserSelectVo selectVo = new CuteUserSelectVo();
selectVo.setValue(m.getUsername());
selectVo.setLabel(m.getNickName());
selectVo.setDeptId(Long.toString(m.getDeptId()));
selectVo.setEmail(m.getEmail());
selectVo.setPhone(m.getPhone());
return selectVo;
}).collect(Collectors.toList());
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2021-2026 Odboy
*
* 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.
*/
package cn.odboy.system.controller;
import cn.odboy.system.service.SystemDeptService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统:组件数据源")
@RequestMapping("/api/component")
public class SystemComponentController {
@Autowired
private SystemDeptService systemDeptService;
@ApiOperation("查询部门下拉选择数据源")
@PostMapping(value = "/listDeptSelectDataSource")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listDeptSelectDataSource() {
return ResponseEntity.ok(systemDeptService.listDeptSelectDataSource());
}
@ApiOperation("查询部门下拉选择Pro数据源")
@PostMapping(value = "/listDeptSelectProDataSource")
@PreAuthorize("@el.check()")
public ResponseEntity<?> listDeptSelectProDataSource() {
return ResponseEntity.ok(systemDeptService.listDeptSelectProDataSource());
}
}
@@ -141,13 +141,6 @@ public class SystemUserController {
return ResponseEntity.ok(null);
}
@ApiOperation("查询用户基础数据")
@PostMapping(value = "/queryUserMetadataOptions")
@PreAuthorize("@el.check('user:list')")
public ResponseEntity<List<KitSelectOptionVo>> queryUserMetadataOptions(@Validated @RequestBody KitPageArgs<SystemQueryUserArgs> args) {
List<KitSelectOptionVo> collect = systemUserService.queryUserMetadataOptions(args);
return ResponseEntity.ok(collect);
}
@ApiOperation("获取用户信息")
@PostMapping(value = "/getCurrentUserInfo")
@@ -16,14 +16,15 @@
package cn.odboy.system.dal.model.response;
import cn.odboy.base.KitBaseUserTimeTb;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.dataobject.SystemJobTb;
import cn.odboy.system.dal.dataobject.SystemRoleTb;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import java.util.Objects;
import java.util.Set;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@@ -60,7 +61,7 @@ public class SystemUserVo extends KitBaseUserTimeTb {
* 扩展字段
*/
@ApiModelProperty(value = "用户部门")
private SystemDeptVo dept;
private SystemDeptTb dept;
@ApiModelProperty(value = "用户角色")
private Set<SystemRoleTb> roles;
@ApiModelProperty(value = "用户岗位")
@@ -27,8 +27,6 @@ import cn.odboy.system.dal.model.export.SystemDeptExportRowVo;
import cn.odboy.system.dal.model.request.SystemCreateDeptArgs;
import cn.odboy.system.dal.model.request.SystemQueryDeptArgs;
import cn.odboy.system.dal.model.response.SystemDeptVo;
import cn.odboy.system.dal.model.response.SystemProductLineTreeVo;
import cn.odboy.system.dal.model.response.SystemProductLineVo;
import cn.odboy.system.dal.mysql.SystemDeptMapper;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.util.KitBeanUtil;
@@ -42,14 +40,11 @@ import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@@ -107,10 +102,10 @@ public class SystemDeptService {
@Transactional(rollbackFor = Exception.class)
public void deleteDeptByIds(Set<Long> ids) {
// 查询部门, 和其所有子部门
Set<SystemDeptVo> depts = this.traverseDeptByIdWithPids(ids);
Set<SystemDeptTb> depts = this.traverseDeptByIdWithPids(ids);
// 验证是否被角色或用户关联
this.verifyBindRelationByIds(depts);
for (SystemDeptVo dept : depts) {
for (SystemDeptTb dept : depts) {
systemDeptMapper.deleteById(dept.getId());
this.updateDeptSubCnt(dept.getPid());
}
@@ -171,16 +166,6 @@ public class SystemDeptService {
return list;
}
/**
* 根据ID查询
*
* @param id /
* @return /
*/
public SystemDeptVo getDeptVoById(Long id) {
return KitBeanUtil.copyToClass(systemDeptMapper.selectById(id), SystemDeptVo.class);
}
/**
* 根据部门id遍历所有部门和子部门id集合
*
@@ -207,14 +192,15 @@ public class SystemDeptService {
* @return /
*/
public KitPageResult<SystemDeptVo> searchDeptTree(List<Long> ids, Boolean exclude) {
Set<SystemDeptVo> deptSet1 = new LinkedHashSet<>();
Map<Long, SystemDeptTb> allDeptMap = this.getAllDeptMap();
Set<SystemDeptTb> deptSet1 = new LinkedHashSet<>();
for (Long id : ids) {
// 同级数据
SystemDeptVo dept = this.getDeptVoById(id);
SystemDeptTb dept = allDeptMap.get(id);
// 上级数据
List<SystemDeptVo> depts = this.querySuperiorDeptByPid(dept, new ArrayList<>());
List<SystemDeptTb> depts = this.querySuperiorDeptByPid(dept, new ArrayList<>(), allDeptMap);
if (exclude) {
for (SystemDeptVo data : depts) {
for (SystemDeptTb data : depts) {
if (data.getId().equals(dept.getPid())) {
data.setSubCount(data.getSubCount() - 1);
}
@@ -224,18 +210,20 @@ public class SystemDeptService {
}
deptSet1.addAll(depts);
}
List<SystemDeptVo> deptList = new ArrayList<>(deptSet1);
List<SystemDeptTb> deptList = new ArrayList<>(deptSet1);
// 构建部门树
Set<SystemDeptVo> trees = new LinkedHashSet<>();
Set<SystemDeptVo> deptSet = new LinkedHashSet<>();
List<String> deptNames = deptList.stream().map(SystemDeptVo::getName).collect(Collectors.toList());
List<String> deptNames = deptList.stream().map(SystemDeptTb::getName).collect(Collectors.toList());
boolean isChild;
for (SystemDeptVo dept : deptList) {
List<SystemDeptVo> systemDeptVos = KitBeanUtil.copyToList(deptList, SystemDeptVo.class);
for (SystemDeptVo dept : systemDeptVos) {
isChild = false;
if (dept.getPid() == null) {
trees.add(dept);
}
for (SystemDeptVo it : deptList) {
for (SystemDeptVo it : systemDeptVos) {
if (it.getPid() != null && dept.getId().equals(it.getPid())) {
isChild = true;
if (dept.getChildren() == null) {
@@ -246,7 +234,7 @@ public class SystemDeptService {
}
if (isChild) {
deptSet.add(dept);
} else if (dept.getPid() != null && !deptNames.contains(this.getDeptVoById(dept.getPid()).getName())) {
} else if (dept.getPid() != null && !deptNames.contains(allDeptMap.get(dept.getPid()).getName())) {
deptSet.add(dept);
}
}
@@ -259,13 +247,18 @@ public class SystemDeptService {
return baseResult;
}
private Map<Long, SystemDeptTb> getAllDeptMap() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
return systemDeptMapper.selectList(wrapper).stream().collect(Collectors.toMap(SystemDeptTb::getId, i -> i, (m, n) -> m));
}
/**
* 验证是否被角色或用户关联
*
* @param deptSet /
*/
public void verifyBindRelationByIds(Set<SystemDeptVo> deptSet) {
Set<Long> deptIds = deptSet.stream().map(SystemDeptVo::getId).collect(Collectors.toSet());
public void verifyBindRelationByIds(Set<SystemDeptTb> deptSet) {
Set<Long> deptIds = deptSet.stream().map(SystemDeptTb::getId).collect(Collectors.toSet());
if (systemUserDeptService.countUserByDeptIds(deptIds) > 0) {
throw new BadRequestException("所选部门存在用户关联,请解除后再试!");
}
@@ -279,13 +272,13 @@ public class SystemDeptService {
*
* @param ids 部门id集合
*/
public Set<SystemDeptVo> traverseDeptByIdWithPids(Set<Long> ids) {
Set<SystemDeptVo> depts = new HashSet<>();
public Set<SystemDeptTb> traverseDeptByIdWithPids(Set<Long> ids) {
Set<SystemDeptTb> depts = new HashSet<>();
for (Long id : ids) {
// 根部门
depts.add(this.getDeptVoById(id));
depts.add(systemDeptMapper.selectById(id));
// 子部门
List<SystemDeptVo> deptList = this.listDeptVoByPid(id);
List<SystemDeptTb> deptList = this.listDeptByPid(id);
if (CollUtil.isNotEmpty(deptList)) {
this.queryRelationDeptByArgs(deptList, depts);
}
@@ -293,43 +286,6 @@ public class SystemDeptService {
return depts;
}
/**
* 产品线选择组件 数据源
*
* @return /
*/
public List<SystemProductLineVo> listDeptSelectDataSource() {
List<SystemDeptTb> depts = this.listEnabledDepts();
return this.buildDeptSelectOptions(depts);
}
/**
* 产品线选择组件Pro版 数据源
*
* @return /
*/
public List<SystemProductLineTreeVo> listDeptSelectProDataSource() {
List<SystemDeptTb> depts = this.listEnabledDepts();
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<SystemProductLineTreeVo> options = new ArrayList<>();
// 构建树形结构
for (SystemDeptTb dept : depts) {
// 只处理顶级部门(pid为null或0的部门)
if (dept.getPid() == null || dept.getPid() == 0) {
SystemProductLineTreeVo vo = this.buildDeptTreePro(dept, deptMap);
options.add(vo);
}
}
// 按排序字段排序
options.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
return options;
}
/**
* 根据父部门id查询部门集合
*
@@ -373,137 +329,37 @@ public class SystemDeptService {
return systemDeptMapper.selectList(wrapper);
}
/**
* 递归构建部门树
*
* @param dept 当前部门
* @param deptMap 部门映射
* @return SystemProductLineTreeVo 树节点
*/
private SystemProductLineTreeVo buildDeptTreePro(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
SystemProductLineTreeVo vo = new SystemProductLineTreeVo();
vo.setValue(String.valueOf(dept.getId()));
vo.setLabel(dept.getName());
// 查找子部门
List<SystemProductLineTreeVo> children = new ArrayList<>();
for (SystemDeptTb childDept : deptMap.values()) {
if (dept.getId().equals(childDept.getPid())) {
children.add(this.buildDeptTreePro(childDept, deptMap));
}
}
// 子部门按排序字段排序
children.sort(Comparator.comparingInt(o -> {
Long id = Long.valueOf(o.getValue());
return deptMap.get(id) != null ? deptMap.get(id).getDeptSort() : 0;
}));
vo.setChildren(children);
return vo;
}
/**
* 产品线选择组件使用
*
* @param depts 部门集合
* @return /
*/
private List<SystemProductLineVo> buildDeptSelectOptions(List<SystemDeptTb> depts) {
// 查询所有部门并按父子关系组织
Map<Long, SystemDeptTb> deptMap =
depts.stream().collect(Collectors.toMap(SystemDeptTb::getId, Function.identity()));
List<SystemProductLineVo> options = new ArrayList<>();
for (SystemDeptTb dept : depts) {
// 构建部门ID路径
List<Long> pathIds = new ArrayList<>();
this.buildDeptIdPath(dept, deptMap, pathIds);
// 反转路径,从顶级部门到当前部门
Collections.reverse(pathIds);
SystemProductLineVo dto = new SystemProductLineVo();
dto.setValue(dept.getId());
dto.setIdPath(pathIds.stream().map(String::valueOf).collect(Collectors.joining("-")));
// 保留名称路径用于显示
dto.setLabel(this.buildNamePath(dept, deptMap));
options.add(dto);
}
// 按部门名称路径排序
options.sort(Comparator.comparing(SystemProductLineVo::getLabel));
return options;
}
/**
* 产品线选择组件使用
*/
private void buildDeptIdPath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<Long> pathIds) {
pathIds.add(dept.getId());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptIdPath(deptMap.get(dept.getPid()), deptMap, pathIds);
}
}
/**
* 产品线选择组件使用
*/
private String buildNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap) {
List<String> pathNames = new ArrayList<>();
this.buildDeptNamePath(dept, deptMap, pathNames);
Collections.reverse(pathNames);
return String.join(" / ", pathNames);
}
/**
* 产品线选择组件使用
*/
private void buildDeptNamePath(SystemDeptTb dept, Map<Long, SystemDeptTb> deptMap, List<String> pathNames) {
pathNames.add(dept.getName());
if (dept.getPid() != null && dept.getPid() != 0 && deptMap.containsKey(dept.getPid())) {
this.buildDeptNamePath(deptMap.get(dept.getPid()), deptMap, pathNames);
}
}
/**
* 查询启用的所有部门集合
*
* @return /
*/
private List<SystemDeptTb> listEnabledDepts() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemDeptTb::getEnabled, 1);
return systemDeptMapper.selectList(wrapper);
}
/**
* 查询部门下所有关联的部门
*
* @param deptTbList /
* @param depts /
*/
private void queryRelationDeptByArgs(List<SystemDeptVo> deptTbList, Set<SystemDeptVo> depts) {
for (SystemDeptVo dept : deptTbList) {
private void queryRelationDeptByArgs(List<SystemDeptTb> deptTbList, Set<SystemDeptTb> depts) {
for (SystemDeptTb dept : deptTbList) {
depts.add(dept);
List<SystemDeptVo> deptList = this.listDeptVoByPid(dept.getId());
List<SystemDeptTb> deptList = this.listDeptByPid(dept.getId());
if (CollUtil.isNotEmpty(deptList)) {
this.queryRelationDeptByArgs(deptList, depts);
}
}
}
private List<SystemDeptVo> listDeptVoByPid(Long pid) {
return KitBeanUtil.copyToList(this.listDeptByPid(pid), SystemDeptVo.class);
}
/**
* 根据ID查询同级与上级数据
*
* @param dept /
* @param deptList /
* @param allDeptMap
* @return /
*/
private List<SystemDeptVo> querySuperiorDeptByPid(SystemDeptVo dept, List<SystemDeptVo> deptList) {
private List<SystemDeptTb> querySuperiorDeptByPid(SystemDeptTb dept, List<SystemDeptTb> deptList, Map<Long, SystemDeptTb> allDeptMap) {
if (dept.getPid() == null) {
deptList.addAll(this.listRootDept());
return deptList;
}
deptList.addAll(this.listDeptVoByPid(dept.getPid()));
return querySuperiorDeptByPid(this.getDeptVoById(dept.getPid()), deptList);
deptList.addAll(this.listDeptByPid(dept.getPid()));
return querySuperiorDeptByPid(allDeptMap.get(dept.getPid()), deptList, allDeptMap);
}
/**
@@ -511,10 +367,10 @@ public class SystemDeptService {
*
* @return /
*/
private List<SystemDeptVo> listRootDept() {
private List<SystemDeptTb> listRootDept() {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
wrapper.isNull(SystemDeptTb::getPid);
return KitBeanUtil.copyToList(systemDeptMapper.selectList(wrapper), SystemDeptVo.class);
return systemDeptMapper.selectList(wrapper);
}
/**
@@ -523,7 +379,7 @@ public class SystemDeptService {
* @param id 部门id
* @return /
*/
private SystemDeptTb getDeptById(Long id) {
public SystemDeptTb getDeptById(Long id) {
return systemDeptMapper.selectById(id);
}
@@ -542,7 +398,7 @@ public class SystemDeptService {
/**
* 筛选出 list 中没有父部门(即 pid 不在其他部门 id 列表中的部门)的部门列表
*/
private List<SystemDeptTb> filterRootDeptList(List<SystemDeptTb> list) {
public List<SystemDeptTb> filterRootDeptList(List<SystemDeptTb> list) {
List<SystemDeptTb> deptList = new ArrayList<>();
// 使用 Set 存储所有部门的 id
Set<Long> idSet = list.stream().map(SystemDeptTb::getId).collect(Collectors.toSet());
@@ -561,7 +417,7 @@ public class SystemDeptService {
* @param args /
* @return /
*/
private List<SystemDeptTb> queryDeptByArgs(SystemQueryDeptArgs args) {
public List<SystemDeptTb> queryDeptByArgs(SystemQueryDeptArgs args) {
LambdaQueryWrapper<SystemDeptTb> wrapper = new LambdaQueryWrapper<>();
if (args != null) {
wrapper.in(CollUtil.isNotEmpty(args.getIds()), SystemDeptTb::getId, args.getIds());
@@ -22,6 +22,7 @@ import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.StrUtil;
import cn.odboy.base.KitPageResult;
import cn.odboy.constant.FileTypeEnum;
import cn.odboy.framework.context.KitRequestHolder;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.server.core.KitFileLocalUploadHelper;
@@ -41,6 +42,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.Date;
@@ -17,9 +17,7 @@ package cn.odboy.system.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.base.KitPageArgs;
import cn.odboy.base.KitPageResult;
import cn.odboy.base.KitSelectOptionVo;
import cn.odboy.framework.exception.BadRequestException;
import cn.odboy.framework.properties.AppProperties;
import cn.odboy.framework.server.core.KitFileLocalUploadHelper;
@@ -333,36 +331,6 @@ public class SystemUserService {
return systemUserMapper.selectCount(wrapper);
}
/**
* 模糊查询用户基础信息,限制返回的条数
*
* @param pageArgs 分页参数
* @return /
*/
public List<KitSelectOptionVo> queryUserMetadataOptions(KitPageArgs<SystemQueryUserArgs> pageArgs) {
SystemQueryUserArgs args = pageArgs.getArgs();
LambdaQueryWrapper<SystemUserTb> wrapper = new LambdaQueryWrapper<>();
wrapper.select(
SystemUserTb::getId, SystemUserTb::getUsername, SystemUserTb::getNickName, SystemUserTb::getDeptId, SystemUserTb::getEmail, SystemUserTb::getPhone);
wrapper.and(c -> {
c.eq(SystemUserTb::getPhone, args.getBlurry());
c.or();
c.eq(SystemUserTb::getEmail, args.getBlurry());
c.or();
c.like(SystemUserTb::getUsername, args.getBlurry());
c.or();
c.like(SystemUserTb::getNickName, args.getBlurry());
});
return systemUserMapper.selectPage(new Page<>(pageArgs.getPage(), 50), wrapper).getRecords().stream().map(m -> {
Map<String, Object> ext = new HashMap<>(1);
ext.put("id", m.getId());
ext.put("deptId", m.getDeptId());
ext.put("email", m.getEmail());
ext.put("phone", m.getPhone());
return KitSelectOptionVo.builder().label(m.getNickName()).value(String.valueOf(m.getId())).ext(ext).build();
}).collect(Collectors.toList());
}
/**
* 根据用户名查询启用的用户信息
*
@@ -399,10 +367,7 @@ public class SystemUserService {
/**
* 聚合查询 -> TestPassed
*/
public KitPageResult<SystemUserVo> aggregationSearchUserByArgs(
Page<SystemUserTb> page, SystemQueryUserArgs args,
String currentUsername
) {
public KitPageResult<SystemUserVo> aggregationSearchUserByArgs(Page<SystemUserTb> page, SystemQueryUserArgs args, String currentUsername) {
if (!ObjectUtils.isEmpty(args.getDeptId())) {
args.getDeptIds().add(args.getDeptId());
// 先查找是否存在子节点
@@ -584,7 +549,7 @@ public class SystemUserService {
SystemUserVo userVo = KitBeanUtil.copyToClass(user, SystemUserVo.class);
// 查询关联的部门信息
if (user.getDeptId() != null) {
userVo.setDept(systemDeptService.getDeptVoById(user.getDeptId()));
userVo.setDept(systemDeptService.getDeptById(user.getDeptId()));
}
// 查询关联的岗位信息
userVo.setJobs(systemUserJobService.listUserJobByUserId(user.getId()));
@@ -592,4 +557,5 @@ public class SystemUserService {
userVo.setRoles(systemUserRoleService.listUserRoleByUserId(user.getId()));
return userVo;
}
}
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-module-task-v1</artifactId>
@@ -13,7 +13,7 @@
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>cutejava-module-system</artifactId>
<version>1.5.0</version>
<version>1.5.2</version>
</dependency>
</dependencies>
</project>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-module-task-v2</artifactId>
@@ -13,7 +13,7 @@
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>cutejava-module-system</artifactId>
<version>1.5.0</version>
<version>1.5.2</version>
</dependency>
</dependencies>
</project>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>cutejava</artifactId>
<groupId>cn.odboy</groupId>
<version>1.5.0</version>
<version>1.5.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cutejava-starter</artifactId>
@@ -13,7 +13,7 @@
<dependency>
<groupId>cn.odboy</groupId>
<artifactId>cutejava-module-task-v1</artifactId>
<version>1.5.0</version>
<version>1.5.2</version>
</dependency>
</dependencies>
<!-- 打包 -->
@@ -5,4 +5,4 @@
| |___ | |_| | | | | |___ | |_| | / / | | | |/ / / / | |
\_____| \_____/ |_| |_____| \_____/ /_/ |_| |___/ /_/ |_|
Spring Boot Version: (${spring-boot.version}),CuteJava Version: (1.5.0)
Spring Boot Version: (${spring-boot.version}),CuteJava Version: (1.5.2)
@@ -16,6 +16,7 @@
package cn.odboy;
import cn.hutool.core.collection.CollUtil;
import cn.odboy.system.dal.dataobject.SystemDeptTb;
import cn.odboy.system.dal.dataobject.SystemJobTb;
import cn.odboy.system.dal.dataobject.SystemRoleTb;
import cn.odboy.system.dal.model.response.SystemDeptVo;
@@ -40,7 +41,7 @@ public class SystemApplicationTests {
@Test
public void contextLoads() {
SystemDeptVo systemDept = new SystemDeptVo();
SystemDeptTb systemDept = new SystemDeptTb();
systemDept.setId(2L);
SystemJobTb systemJob = new SystemJobTb();
systemJob.setId(11L);
+1 -1
View File
@@ -5,7 +5,7 @@
<groupId>cn.odboy</groupId>
<artifactId>cutejava</artifactId>
<packaging>pom</packaging>
<version>1.5.0</version>
<version>1.5.2</version>
<modules>
<!-- 基础设施 -->