浏览代码

增加用户和部门相关接口

Feick 4 年之前
父节点
当前提交
937e6a7808
共有 22 个文件被更改,包括 726 次插入49 次删除
  1. 14 13
      src/main/kotlin/com/yaoxiang/planning/action/AnnualAction.kt
  2. 52 6
      src/main/kotlin/com/yaoxiang/planning/action/DepartmentAction.kt
  3. 1 1
      src/main/kotlin/com/yaoxiang/planning/action/QuarterlyAction.kt
  4. 54 3
      src/main/kotlin/com/yaoxiang/planning/action/UserAction.kt
  5. 30 10
      src/main/kotlin/com/yaoxiang/planning/action/WeeklyAction.kt
  6. 7 0
      src/main/kotlin/com/yaoxiang/planning/config/PlanningConstants.kt
  7. 12 0
      src/main/kotlin/com/yaoxiang/planning/config/PlanningProperties.kt
  8. 22 8
      src/main/kotlin/com/yaoxiang/planning/domain/Department.kt
  9. 23 0
      src/main/kotlin/com/yaoxiang/planning/domain/DepartmentLeader.kt
  10. 8 0
      src/main/kotlin/com/yaoxiang/planning/domain/UserInfo.kt
  11. 6 1
      src/main/kotlin/com/yaoxiang/planning/repository/DepartmentRepo.kt
  12. 4 0
      src/main/kotlin/com/yaoxiang/planning/repository/UserInfoRepo.kt
  13. 1 0
      src/main/kotlin/com/yaoxiang/planning/repository/WeeklyPlanRepo.kt
  14. 7 0
      src/main/kotlin/com/yaoxiang/planning/service/AnnualPlanService.kt
  15. 131 0
      src/main/kotlin/com/yaoxiang/planning/service/DepartmentService.kt
  16. 169 0
      src/main/kotlin/com/yaoxiang/planning/service/UserService.kt
  17. 32 1
      src/main/kotlin/com/yaoxiang/planning/service/WeeklyPlanService.kt
  18. 17 4
      src/main/kotlin/com/yaoxiang/planning/utils/DateUtil.java
  19. 65 0
      src/main/kotlin/com/yaoxiang/planning/utils/TreeUtil.kt
  20. 6 2
      src/main/resources/application.properties
  21. 14 0
      src/test/kotlin/com/yaoxiang/planning/utils/DateUtilTest.kt
  22. 51 0
      src/test/kotlin/com/yaoxiang/planning/utils/TreeUtilTest.kt

+ 14 - 13
src/main/kotlin/com/yaoxiang/planning/action/AnnualAction.kt

@@ -8,10 +8,7 @@ import io.swagger.annotations.ApiImplicitParam
 import io.swagger.annotations.ApiImplicitParams
 import io.swagger.annotations.ApiOperation
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.PostMapping
-import org.springframework.web.bind.annotation.RequestMapping
-import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.bind.annotation.*
 import org.thymeleaf.util.DateUtils
 import java.util.*
 
@@ -24,20 +21,24 @@ class AnnualAction {
     private lateinit var annualPlanService: AnnualPlanService
 
     @ApiOperation("添加年度计划")
-    @ApiImplicitParams(ApiImplicitParam(name = "name", value = "名称", paramType = "query"),
-            ApiImplicitParam(name = "content", value = "计划内容", paramType = "query"),
-            ApiImplicitParam(name = "year", value = "年份", paramType = "query"))
+    @ApiImplicitParams(
+        ApiImplicitParam(name = "name", value = "名称", paramType = "query"),
+        ApiImplicitParam(name = "content", value = "计划内容", paramType = "query"),
+        ApiImplicitParam(name = "year", value = "年份", paramType = "query")
+    )
     @PostMapping("add")
     fun add(name: String, content: String, year: Int): Reply<Any> {
         val result = annualPlanService.add(name, content, year)
-        return Reply(result)
+        return if (result) Reply.ok() else Reply.fail("当年年度计划已存在")
     }
 
     @ApiOperation("更新年度计划")
-    @ApiImplicitParams(ApiImplicitParam(name = "id", value = "年度计划id", paramType = "query"),
-            ApiImplicitParam(name = "name", value = "名称", paramType = "query"),
-            ApiImplicitParam(name = "content", value = "计划内容", paramType = "query"),
-            ApiImplicitParam(name = "year", value = "年份", paramType = "query"))
+    @ApiImplicitParams(
+        ApiImplicitParam(name = "id", value = "年度计划id", paramType = "query"),
+        ApiImplicitParam(name = "name", value = "名称", paramType = "query"),
+        ApiImplicitParam(name = "content", value = "计划内容", paramType = "query"),
+        ApiImplicitParam(name = "year", value = "年份", paramType = "query")
+    )
     @PostMapping("update")
     fun update(id: Long, name: String, content: String, year: Int, status: Int): Reply<Any> {
         val result = annualPlanService.update(id, name, content, year, status)
@@ -51,7 +52,7 @@ class AnnualAction {
     }
 
     @GetMapping("current")
-    fun get(year: Int? = null): Reply<AnnualPlan?> {
+    fun current(@RequestParam(required = false) year: Int? = null): Reply<AnnualPlan> {
         val y: Int = year ?: DateUtils.year(Date())
         val optional = annualPlanService.findByYear(y)
         return Reply(optional.isPresent, "", optional.orElse(null))

+ 52 - 6
src/main/kotlin/com/yaoxiang/planning/action/DepartmentAction.kt

@@ -1,12 +1,14 @@
 package com.yaoxiang.planning.action
 
+import com.yaoxiang.planning.domain.Department
 import com.yaoxiang.planning.model.Reply
 import com.yaoxiang.planning.service.DepartmentService
 import io.swagger.annotations.Api
+import io.swagger.annotations.ApiImplicitParam
+import io.swagger.annotations.ApiImplicitParams
+import io.swagger.annotations.ApiOperation
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.RequestMapping
-import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.bind.annotation.*
 
 @Api(tags = ["部门"])
 @RestController
@@ -16,8 +18,52 @@ class DepartmentAction {
     @Autowired
     private lateinit var departmentService: DepartmentService
 
-    @GetMapping("hello")
-    fun hello(): Reply<Any> {
-        return Reply.ok()
+    @PostMapping("add")
+    @ApiOperation("新增部门")
+    @ApiImplicitParams(
+        ApiImplicitParam(name = "name", value = "部门名称", paramType = "query"),
+        ApiImplicitParam(name = "duty", value = "职责", paramType = "query"),
+        ApiImplicitParam(name = "remark", value = "备注", paramType = "query"),
+        ApiImplicitParam(name = "parentId", value = "上级部门Id", paramType = "query")
+    )
+    fun add(name: String, @RequestParam(required = false) duty: String?,
+            @RequestParam(required = false) remark: String?, parentId: Long): Reply<Any> {
+        val result = departmentService.add(name, duty, remark, parentId)
+        return if (result) Reply.ok() else Reply.fail("部门名称重复或未找到上级部门")
+    }
+
+    @ApiOperation("获取部门树")
+    @GetMapping("getTree")
+    fun getTree(): Reply<Department> {
+        val root = departmentService.findRoot()
+        if (!root.isPresent) {
+            return Reply.fail("未找到部门列表")
+        }
+        val tree = departmentService.getTree(root.get().id!!)
+        return Reply.ok(tree.orElse(null))
+    }
+
+    @ApiOperation("更新部门信息")
+    @PostMapping("update")
+    @ApiImplicitParams(
+        ApiImplicitParam(name = "id", value = "部门id", paramType = "query"),
+        ApiImplicitParam(name = "name", value = "部门名称", paramType = "query"),
+        ApiImplicitParam(name = "duty", value = "职责", paramType = "query"),
+        ApiImplicitParam(name = "remark", value = "备注", paramType = "query"),
+        ApiImplicitParam(name = "parentId", value = "上级部门Id", paramType = "query")
+    )
+    fun update(id: Long, name: String, @RequestParam(required = false) duty: String?,
+               @RequestParam(required = false) remark: String?,
+               @RequestParam(required = false) parentId: Long?): Reply<Any> {
+        val result = departmentService.update(id, name, duty, remark, parentId)
+        return if (result) Reply.ok() else Reply.fail("更新失败")
+    }
+
+    @ApiOperation("删除部门及其子部门")
+    @PostMapping("delete")
+    @ApiImplicitParam(name = "id",value = "部门id",paramType = "query")
+    fun delete(id: Long): Reply<Any> {
+        val result = departmentService.delete(id)
+        return if (result) Reply.ok() else Reply.fail("删除失败")
     }
 }

+ 1 - 1
src/main/kotlin/com/yaoxiang/planning/action/QuarterlyAction.kt

@@ -46,7 +46,7 @@ class QuarterlyAction {
     }
 
     @ApiOperation("获取季度计划")
-    @ApiImplicitParam(name = "yar", value = "year", paramType = "query")
+    @ApiImplicitParam(name = "year", value = "year", paramType = "query")
     @GetMapping("list")
     fun list(@RequestParam(required = false) year: Int? = null): Reply<List<QuarterlyPlan>> {
         val y: Int = year ?: DateUtils.year(Date())

+ 54 - 3
src/main/kotlin/com/yaoxiang/planning/action/UserAction.kt

@@ -2,13 +2,14 @@ package com.yaoxiang.planning.action
 
 import com.yaoxiang.planning.domain.UserInfo
 import com.yaoxiang.planning.model.Reply
+import com.yaoxiang.planning.service.DepartmentService
 import com.yaoxiang.planning.service.UserService
 import io.swagger.annotations.Api
+import io.swagger.annotations.ApiImplicitParam
+import io.swagger.annotations.ApiImplicitParams
 import io.swagger.annotations.ApiOperation
 import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.RequestMapping
-import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.bind.annotation.*
 
 @Api(tags = ["用户"])
 @RestController
@@ -25,6 +26,43 @@ class UserAction {
         return Reply.ok(result)
     }
 
+    @ApiOperation("新增用户")
+    @PostMapping("add")
+    fun add(username: String, name: String, password: String,
+            @RequestParam(required = false) departmentId: Long?): Reply<Any> {
+        val result = userService.add(username, name, password, departmentId)
+        return if (result) Reply.ok() else Reply.fail("新增失败")
+    }
+
+    @ApiOperation("更新用户信息")
+    @ApiImplicitParams(
+        ApiImplicitParam(name = "name", value = "昵称", paramType = "query"),
+        ApiImplicitParam(name = "age", value = "职责", paramType = "query"),
+        ApiImplicitParam(name = "gender", value = "备注", paramType = "query"),
+        ApiImplicitParam(name = "email", value = "上级部门Id", paramType = "query")
+    )
+    @PostMapping("updateInfo")
+    fun updateInfo(id: Long, name: String, @RequestParam(required = false) age: Int?,
+        @RequestParam(required = false) gender: Int?,
+        @RequestParam(required = false) email: String?): Reply<Any> {
+        val result = userService.updateInfo(id, name, age, gender, email)
+        return if (result) Reply.ok() else Reply.fail("更新失败")
+    }
+
+    @ApiOperation("更新密码")
+    @PostMapping("updatePassword")
+    fun updatePassword(id: Long, oldPassword: String, newPassword: String): Reply<Any> {
+        val result = userService.updatePassword(id, oldPassword, newPassword)
+        return if (result) Reply.ok() else Reply.fail("更新密码失败")
+    }
+
+    @ApiOperation("重置密码")
+    @PostMapping("resetPassword")
+    fun resetPassword(id: Long, secret: String?): Reply<Any> {
+        val result = userService.resetPassword(id, secret)
+        return if (result) Reply.ok() else Reply.fail("重置密码失败")
+    }
+
     @ApiOperation("当前用户")
     @GetMapping("cur")
     fun currentUser(): Reply<UserInfo> {
@@ -36,5 +74,18 @@ class UserAction {
         return Reply.ok(result)
     }
 
+    @ApiOperation("更新用户部门")
+    @PostMapping("updateDepartment")
+    fun updateDepartment(id: Long, departmentId: Long): Reply<Any> {
+        val result = userService.updateDepartment(id, departmentId)
+        return if (result) Reply.ok() else Reply.fail("更新失败")
+    }
+
+    @ApiOperation("删除用户")
+    @PostMapping("delete")
+    fun delete(id: Long): Reply<Any> {
+        val result = userService.delete(id)
+        return if (result) Reply.ok() else Reply.fail("删除失败")
+    }
 
 }

+ 30 - 10
src/main/kotlin/com/yaoxiang/planning/action/WeeklyAction.kt

@@ -21,14 +21,18 @@ class WeeklyAction {
     private lateinit var weeklyPlanService: WeeklyPlanService
 
     @ApiOperation("添加季度计划")
-    @ApiImplicitParams(ApiImplicitParam(name = "name", value = "名称", paramType = "query"),
-            ApiImplicitParam(name = "content", value = "计划内容", paramType = "query"),
-            ApiImplicitParam(name = "startTime", value = "计划时间", paramType = "query"),
-            ApiImplicitParam(name = "year", value = "年份", paramType = "query"))
+    @ApiImplicitParams(
+        ApiImplicitParam(name = "name", value = "名称", paramType = "query"),
+        ApiImplicitParam(name = "content", value = "计划内容", paramType = "query"),
+        ApiImplicitParam(name = "startTime", value = "计划时间", paramType = "query"),
+        ApiImplicitParam(name = "year", value = "年份", paramType = "query")
+    )
     @PostMapping("add")
-    fun add(name: String, content: String,
-            @RequestParam(required = false) userId: Long?,
-            @RequestParam(required = false) startTime: Long? = null): Reply<Any> {
+    fun add(
+        name: String, content: String,
+        @RequestParam(required = false) userId: Long?,
+        @RequestParam(required = false) startTime: Long? = null
+    ): Reply<Any> {
         val start = startTime ?: System.currentTimeMillis()
         val year = DateUtils.year(Date(start))
         weeklyPlanService.add(name, content, userId, start, year)
@@ -50,10 +54,26 @@ class WeeklyAction {
         return Reply(result)
     }
 
-    @GetMapping("list")
-    fun list(startTime: Long?): Reply<List<WeeklyPlan>> {
+    @ApiOperation("获取个人的周计划列表")
+    @GetMapping("listCurrentWeek")
+    fun listCurrentWeek(@RequestParam(required = false) startTime: Long?): Reply<Map<String,List<WeeklyPlan>>> {
         val start = startTime ?: System.currentTimeMillis()
-        val result = weeklyPlanService.findByStartTime(start)
+        val result = weeklyPlanService.mapCurrentWeek(start)
+        return Reply.ok(result)
+    }
+
+
+    fun listCurrentMonth(@RequestParam(required = false) startTime: Long?):Reply<Map<String,List<WeeklyPlan>>>{
+        val start = startTime ?: System.currentTimeMillis()
+        val result = weeklyPlanService.mapCurrentMonth(start)
+        return Reply.ok(result)
+    }
+
+    @ApiOperation("获取所有人的周计划列表")
+    @GetMapping("listAllOfCurrentWeek")
+    fun listAllOfCurrentWeek(@RequestParam(required = false) startTime: Long?): Reply<Map<String,List<WeeklyPlan>>> {
+        val start = startTime ?: System.currentTimeMillis()
+        val result = weeklyPlanService.mapCurrentWeek(start,false)
         return Reply.ok(result)
     }
 }

+ 7 - 0
src/main/kotlin/com/yaoxiang/planning/config/PlanningConstants.kt

@@ -0,0 +1,7 @@
+package com.yaoxiang.planning.config
+
+class PlanningConstants {
+    companion object{
+        const val ADMIN_USER = "admin"
+    }
+}

+ 12 - 0
src/main/kotlin/com/yaoxiang/planning/config/PlanningProperties.kt

@@ -0,0 +1,12 @@
+package com.yaoxiang.planning.config
+
+import org.springframework.boot.context.properties.ConfigurationProperties
+import org.springframework.stereotype.Component
+
+@Component
+@ConfigurationProperties(prefix = "planning")
+class PlanningProperties {
+    var departmentName: String = "root"
+    var secret: String = "YaoXiang@1234"
+    var defaultPassword: String = "Admin123"
+}

+ 22 - 8
src/main/kotlin/com/yaoxiang/planning/domain/Department.kt

@@ -1,5 +1,6 @@
 package com.yaoxiang.planning.domain
 
+import com.yaoxiang.planning.utils.ToTree
 import io.swagger.annotations.ApiModel
 import io.swagger.annotations.ApiModelProperty
 import javax.persistence.Column
@@ -10,7 +11,7 @@ import javax.persistence.Table
 @Entity
 @ApiModel("部门信息")
 @Table(indexes = [Index(name = "nameIndex", columnList = "name", unique = true)])
-class Department() : BaseLongEntity() {
+class Department() : BaseLongEntity(), ToTree {
 
     @ApiModelProperty("部门名称")
     @Column(columnDefinition = "varchar(64) COMMENT '用户名/手机号码'")
@@ -20,16 +21,29 @@ class Department() : BaseLongEntity() {
     @Column(columnDefinition = "mediumtext COMMENT '部门'")
     var duty: String? = null
 
-    @ApiModelProperty("职责")
+    @ApiModelProperty("备注")
     @Column(columnDefinition = "varchar(255) COMMENT '备注'")
     var remark: String? = null
 
-    @ApiModelProperty("部门层级")
-    @Column(columnDefinition = "int(11) COMMENT '部门层级'")
-    var level: Int? = null
+    @ApiModelProperty("上级部门Id")
+    @Column(columnDefinition = "int(20) COMMENT '上级部门Id'")
+    var parentId: Long? = null
+
+    @Transient
+    @ApiModelProperty("子树")
+    var children: List<Department>? = null
+
+    override fun id(): Long {
+        return id!!
+    }
+
+    override fun parentId(): Long? {
+        return parentId
+    }
+
+    override fun setChild(children: MutableList<ToTree>) {
+        this.children = children as MutableList<Department>
+    }
 
-    @ApiModelProperty("部门负责人Id")
-    @Column(columnDefinition = "int(20) COMMENT '部门负责人Id'")
-    var leader: Long? = null
 
 }

+ 23 - 0
src/main/kotlin/com/yaoxiang/planning/domain/DepartmentLeader.kt

@@ -0,0 +1,23 @@
+package com.yaoxiang.planning.domain
+
+import io.swagger.annotations.ApiModel
+import io.swagger.annotations.ApiModelProperty
+import javax.persistence.Column
+import javax.persistence.Entity
+import javax.persistence.Index
+import javax.persistence.Table
+
+@Entity
+@ApiModel("部门信息")
+@Table(indexes = [Index(name = "departmentUser", columnList = "departmentId,userId", unique = true)])
+class DepartmentLeader : BaseLongEntity() {
+
+    @ApiModelProperty("部门Id")
+    @Column(columnDefinition = "int(20) COMMENT '部门Id'")
+    val departmentId: Long? = null
+
+    @ApiModelProperty("用户Id")
+    @Column(columnDefinition = "int(20) COMMENT '用户Id'")
+    val userId: Long? = null
+
+}

+ 8 - 0
src/main/kotlin/com/yaoxiang/planning/domain/UserInfo.kt

@@ -37,6 +37,14 @@ class UserInfo() : BaseLongEntity() {
     @Column(columnDefinition = "int(11) COMMENT '年龄'")
     var age: Int? = null
 
+    @ApiModelProperty("邮箱")
+    @Column(columnDefinition = "varchar(255) COMMENT '邮箱'")
+    var email: String? = null
+
+    @ApiModelProperty("微信openId")
+    @Column(columnDefinition = "varchar(255) COMMENT '微信openId'")
+    var openId: String? = null
+
     @ApiModelProperty("手机号码")
     @Column(columnDefinition = "varchar(255) COMMENT '手机号码'")
     var phone: String? = null

+ 6 - 1
src/main/kotlin/com/yaoxiang/planning/repository/DepartmentRepo.kt

@@ -3,6 +3,11 @@ package com.yaoxiang.planning.repository
 import com.yaoxiang.planning.domain.Department
 import org.springframework.data.jpa.repository.JpaRepository
 import org.springframework.stereotype.Repository
+import java.util.*
 
 @Repository
-interface DepartmentRepo : JpaRepository<Department, Long>
+interface DepartmentRepo : JpaRepository<Department, Long> {
+    fun findFirstByParentIdIsNull(): Optional<Department>
+
+    fun existsByName(name: String): Boolean
+}

+ 4 - 0
src/main/kotlin/com/yaoxiang/planning/repository/UserInfoRepo.kt

@@ -9,4 +9,8 @@ import java.util.*
 interface UserInfoRepo : JpaRepository<UserInfo, Long> {
 
     fun findByUsername(username: String): Optional<UserInfo>
+
+    fun existsByUsername(username: String):Boolean
+
+    fun findAllByDepartmentIdIn(ids: List<Long>): List<UserInfo>
 }

+ 1 - 0
src/main/kotlin/com/yaoxiang/planning/repository/WeeklyPlanRepo.kt

@@ -8,4 +8,5 @@ import java.util.*
 @Repository
 interface WeeklyPlanRepo : JpaRepository<WeeklyPlan, Long> {
     fun findAllByUserIdAndStartTimeBetween(userId:Long,start: Date, end: Date): List<WeeklyPlan>
+    fun findAllByStartTimeBetween(start: Date, end: Date): List<WeeklyPlan>
 }

+ 7 - 0
src/main/kotlin/com/yaoxiang/planning/service/AnnualPlanService.kt

@@ -5,6 +5,7 @@ import com.yaoxiang.planning.model.PlanType
 import com.yaoxiang.planning.repository.AnnualPlanRepo
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
 import java.util.*
 
 @Service
@@ -19,6 +20,7 @@ class AnnualPlanService {
     @Autowired
     private lateinit var planningItemService: PlanningItemService
 
+    @Transactional
     fun add(name: String, content: String, year: Int): Boolean {
         if (exists(year)) {
             return false
@@ -29,6 +31,7 @@ class AnnualPlanService {
         return true
     }
 
+    @Transactional(readOnly = true)
     fun exists(year: Int): Boolean {
         val optional = annualPlanRepo.findFirstByYear(year)
         return optional.isPresent
@@ -44,6 +47,7 @@ class AnnualPlanService {
         return optional
     }
 
+    @Transactional(readOnly = true)
     fun findByYear(year: Int): Optional<AnnualPlan> {
         return annualPlanRepo.findFirstByYear(year)
     }
@@ -52,6 +56,7 @@ class AnnualPlanService {
         return annualPlanRepo.findById(id)
     }
 
+    @Transactional
     fun update(id: Long, name: String, content: String, year: Int, status: Int): Boolean {
         val optional = get(id)
         if (!optional.isPresent) {
@@ -66,6 +71,7 @@ class AnnualPlanService {
         return true
     }
 
+    @Transactional
     fun delete(id: Long): Boolean {
         val optional = get(id)
         if (!optional.isPresent) {
@@ -75,6 +81,7 @@ class AnnualPlanService {
         return true
     }
 
+    @Transactional(readOnly = true)
     fun list(): List<AnnualPlan> {
         return annualPlanRepo.findAll()
     }

+ 131 - 0
src/main/kotlin/com/yaoxiang/planning/service/DepartmentService.kt

@@ -1,12 +1,143 @@
 package com.yaoxiang.planning.service
 
+import com.yaoxiang.planning.config.PlanningProperties
+import com.yaoxiang.planning.domain.Department
 import com.yaoxiang.planning.repository.DepartmentRepo
+import com.yaoxiang.planning.utils.TreeUtil
+import mu.KotlinLogging
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import java.util.*
+import javax.annotation.PostConstruct
+
+private val logger = KotlinLogging.logger { }
 
 @Service
 class DepartmentService {
 
     @Autowired
     private lateinit var departmentRepo: DepartmentRepo
+
+    @Autowired
+    private lateinit var userService: UserService
+
+    @Autowired
+    private lateinit var planningProperties: PlanningProperties
+
+    @PostConstruct
+    fun init() {
+        val list = list()
+        if (list.isEmpty()) {
+            add(planningProperties.departmentName, null, null, null)
+            logger.info { "init root department." }
+        }
+    }
+
+    fun list(): List<Department> {
+        return departmentRepo.findAll()
+    }
+
+    fun listAllChildren(rootId: Long): List<Department> {
+        val optional = get(rootId)
+        if (!optional.isPresent) {
+            return arrayListOf()
+        }
+        val list = list()
+//        val map = list.associateBy { it.id!! }
+        TreeUtil.listAllChildren(optional.get(), list.toMutableList())
+        return list
+    }
+
+    @Transactional
+    fun add(name: String, duty: String?, remark: String?, parentId: Long?): Boolean {
+        if (existsByName(name)) {
+            return false
+        }
+        if (parentId == null && findRoot().isPresent) {
+            return false
+        }
+        if (parentId != null && !exists(parentId)) {
+            return false
+        }
+        val department = Department()
+        department.name = name
+        department.duty = duty
+        department.remark = remark
+        department.parentId = parentId
+        departmentRepo.save(department)
+        logger.info { "添加部门成功,name=${name},duty=${duty},remark=${remark},parentId=${parentId}" }
+        return true
+    }
+
+    @Transactional
+    fun update(id: Long, name: String, duty: String?, remark: String?, parentId: Long?): Boolean {
+        val optional = get(id)
+        if (!optional.isPresent) {
+            return false
+        }
+        val department = optional.get()
+        if (parentId == null && department.parentId != null) {
+            logger.error { "不允许设置非root部门的上级部门为null,departmentName==${department.name}" }
+            return false
+        }
+        if (parentId != null && department.parentId == null) {
+            logger.error { "不允许设置root部门的parentId,departmentName=${department.name},parentId=${parentId}" }
+            return false
+        }
+
+        department.name = name
+        department.duty = duty
+        department.remark = remark
+        department.parentId = parentId
+        departmentRepo.save(department)
+        logger.info { "更新部门成功,department=${department}" }
+        return true
+    }
+
+    @Transactional
+    fun delete(id: Long): Boolean {
+        val optional = get(id)
+        if (!optional.isPresent) {
+            return false
+        }
+        val department = optional.get()
+        if (department.parentId == null) {
+            logger.error { "不允许删除root部门,id=${id}" }
+            return false
+        }
+        val list = list()
+        val children = TreeUtil.listChildren(department, list.toMutableList()) as List<Department>
+        departmentRepo.deleteAll(children)
+        userService.clearDepartment(children.map { it.id!! })
+        logger.info { "删除部门成功,id=${id},departmentName=${department.name},size=${children.size}" }
+        return true
+    }
+
+    fun exists(id: Long): Boolean {
+        return departmentRepo.existsById(id)
+    }
+
+    private fun existsByName(name: String): Boolean {
+        return departmentRepo.existsByName(name)
+    }
+
+    fun get(id: Long): Optional<Department> {
+        return departmentRepo.findById(id)
+    }
+
+    fun findRoot(): Optional<Department> {
+        return departmentRepo.findFirstByParentIdIsNull()
+    }
+
+    @Transactional(readOnly = true)
+    fun getTree(id: Long): Optional<Department> {
+        val list = listAllChildren(id)
+        if (list.isEmpty()) {
+            return Optional.empty()
+        }
+//        val map = list.associateBy { it.id!! }
+        return Optional.ofNullable(list.firstOrNull { id == it.id!! })
+    }
+
 }

+ 169 - 0
src/main/kotlin/com/yaoxiang/planning/service/UserService.kt

@@ -1,19 +1,37 @@
 package com.yaoxiang.planning.service
 
+import com.yaoxiang.planning.config.PlanningConstants
+import com.yaoxiang.planning.config.PlanningProperties
+import com.yaoxiang.planning.domain.Department
 import com.yaoxiang.planning.domain.UserInfo
 import com.yaoxiang.planning.model.AuthUser
+import com.yaoxiang.planning.repository.DepartmentRepo
 import com.yaoxiang.planning.repository.UserInfoRepo
+import mu.KotlinLogging
+import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.security.core.context.SecurityContextHolder
 import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import org.springframework.util.DigestUtils
+import org.springframework.util.StringUtils
 import java.util.*
 import javax.annotation.Resource
 
+private val logger = KotlinLogging.logger { }
+
 @Service
 class UserService {
 
     @Resource
     private lateinit var userInfoRepo: UserInfoRepo
 
+    @Autowired
+    private lateinit var departmentRepo: DepartmentRepo
+
+    @Autowired
+    private lateinit var planningProperties: PlanningProperties
+
+    @Transactional(readOnly = true)
     fun findByUsername(username: String): Optional<UserInfo> {
         return userInfoRepo.findByUsername(username)
     }
@@ -31,4 +49,155 @@ class UserService {
         }
         return null
     }
+
+    @Transactional(readOnly = true)
+    fun existsByUsername(username: String): Boolean {
+        return userInfoRepo.existsByUsername(username)
+    }
+
+    @Transactional(readOnly = true)
+    fun get(id: Long): Optional<UserInfo> {
+        return userInfoRepo.findById(id)
+    }
+
+    @Transactional
+    fun add(username: String, name: String, password: String, departmentId: Long?): Boolean {
+        if (existsByUsername(username)) {
+            logger.error { "用户名已存在,username=${username}" }
+            return false
+        }
+        var department: Department? = null
+        if (departmentId != null) {
+            val optional = departmentRepo.findById(departmentId)
+            if (!optional.isPresent) {
+                logger.error { "未找到指定部门,departmentId=${departmentId}" }
+                return false
+            }
+            department = optional.get()
+        }
+        val userInfo = UserInfo()
+        userInfo.enabled = true
+        userInfo.username = username
+        userInfo.name = name
+        userInfo.password = DigestUtils.md5DigestAsHex(password.toByteArray()).toUpperCase()
+        userInfo.departmentId = departmentId
+        userInfo.departmentName = department?.name
+        userInfoRepo.save(userInfo)
+        logger.info { "新增用户,user=${userInfo}" }
+        return true
+    }
+
+    @Transactional
+    fun updateInfo(id: Long, name: String, age: Int?, gender: Int?, email: String?): Boolean {
+        val optional = get(id)
+        if (!optional.isPresent) {
+            return false
+        }
+        val user = optional.get()
+        user.name = name
+        user.age = age
+        user.gender = gender
+        user.email = email
+        val result = update(user)
+        logger.info { "更新用户信息,user=${user}" }
+        return result
+    }
+
+    @Transactional
+    fun updatePassword(id: Long, oldPassword: String, newPassword: String): Boolean {
+        val optional = get(id)
+        if (!optional.isPresent) {
+            return false
+        }
+        val user = optional.get()
+        if (user.password != DigestUtils.md5DigestAsHex(oldPassword.toByteArray()).toUpperCase()) {
+            logger.error { "密码不匹配,username=${user.username},oldPassword=${oldPassword},newPassword=${newPassword}" }
+            return false
+        }
+        user.password = DigestUtils.md5DigestAsHex(newPassword.toByteArray()).toUpperCase()
+        val result = update(user)
+        logger.info { "更新用户密码,id=${id},result=${result}" }
+        return result
+    }
+
+    @Transactional
+    fun resetPassword(id: Long, secret: String?): Boolean {
+        val optional = get(id)
+        if (!optional.isPresent) {
+            return false
+        }
+        val cur = currentUser()
+        val hasText = StringUtils.hasText(secret)
+        if (!hasText && (cur == null || cur.username != PlanningConstants.ADMIN_USER)) {
+            logger.error { "未提供secret且用户不是admin,currentUserId=${cur?.id}" }
+            return false
+        }
+        if (hasText && secret != planningProperties.secret) {
+            logger.error { "secret不匹配,currentUserId=${cur?.id}" }
+            return false
+        }
+        val user = optional.get()
+        user.password = DigestUtils.md5DigestAsHex(planningProperties.defaultPassword.toByteArray()).toUpperCase()
+        val result = update(user)
+        logger.info { "重置密码,id=${id},result=${result}" }
+        return result
+    }
+
+    @Transactional
+    fun delete(id: Long): Boolean {
+        val optional = get(id)
+        if (!optional.isPresent) {
+            return false
+        }
+        val user = optional.get()
+        if (user.username == PlanningConstants.ADMIN_USER) {
+            logger.error { "不允许删除admin,currentUserId=${currentUserId()}" }
+            return false
+        }
+        val result = delete(user)
+        logger.info { "删除用户,id=${id},result=${result}" }
+        return result
+    }
+
+    private fun delete(userInfo: UserInfo): Boolean {
+        userInfoRepo.delete(userInfo)
+        return true
+    }
+
+    @Transactional
+    fun clearDepartment(departmentIds: List<Long>): Boolean {
+        val users = userInfoRepo.findAllByDepartmentIdIn(departmentIds)
+        users.forEach {
+            it.departmentId = null
+            it.departmentName = null
+            update(it)
+        }
+        logger.info { "清除部门信息,departmentIds=${departmentIds}" }
+        return true
+    }
+
+    @Transactional
+    fun updateDepartment(id: Long, departmentId: Long): Boolean {
+        val optional = get(id)
+        if (!optional.isPresent) {
+            logger.error { "未找到用户,更新部门失败,id=${id},departmentId=${departmentId}" }
+            return false
+        }
+        val optional1 = departmentRepo.findById(departmentId)
+        if (!optional1.isPresent) {
+            logger.error { "未找到部门,更新部门失败,id=${id},departmentId=${departmentId}" }
+        }
+        val user = optional.get()
+        user.departmentId = departmentId
+        user.departmentName = optional1.get().name
+        val result = update(user)
+        logger.info { "更新部门,id=${id},departmentId=${departmentId},result=${result}" }
+        return result
+    }
+
+    @Transactional
+    private fun update(userInfo: UserInfo): Boolean {
+        userInfoRepo.save(userInfo)
+        return true
+    }
 }

+ 32 - 1
src/main/kotlin/com/yaoxiang/planning/service/WeeklyPlanService.kt

@@ -6,7 +6,9 @@ import com.yaoxiang.planning.repository.WeeklyPlanRepo
 import com.yaoxiang.planning.utils.DateUtil
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
 import java.util.*
+import kotlin.collections.LinkedHashMap
 
 @Service
 class WeeklyPlanService {
@@ -57,11 +59,40 @@ class WeeklyPlanService {
         return true
     }
 
-    fun findByStartTime(start: Long): List<WeeklyPlan> {
+    fun mapCurrentWeek(start: Long, self: Boolean = true): Map<String, List<WeeklyPlan>> {
+        val list = findCurrentWeek(start, self)
+        list.sortedBy { it.startTime!! }
+        val result = LinkedHashMap<String,List<WeeklyPlan>>()
+        return result
+    }
+
+    fun mapCurrentMonth(start: Long, self: Boolean = true):Map<String,List<WeeklyPlan>>{
+        val result = LinkedHashMap<String,List<WeeklyPlan>>()
+        return result
+    }
+
+    @Transactional(readOnly = true)
+    fun findCurrentWeek(start: Long, self: Boolean): List<WeeklyPlan> {
         val time = Date(start)
         val first = DateUtil.getFirstDayOfWeek(time)
         val last = DateUtil.getLastDayOfWeek(time)
+        if (!self) {
+            return weeklyPlanRepo.findAllByStartTimeBetween(first, last)
+        }
+        val userId = userService.currentUserId()
+        return weeklyPlanRepo.findAllByUserIdAndStartTimeBetween(userId!!, first, last)
+    }
+
+    @Transactional(readOnly = true)
+    fun findCurrentMoon(start: Long, self: Boolean = true): List<WeeklyPlan> {
+        val time = Date(start)
+        val first = DateUtil.getFirstDayOfMonth(time)
+        val last = DateUtil.getLastDayOfMonth(time)
+        if (!self) {
+            return weeklyPlanRepo.findAllByStartTimeBetween(first, last)
+        }
         val userId = userService.currentUserId()
         return weeklyPlanRepo.findAllByUserIdAndStartTimeBetween(userId!!, first, last)
     }
+
 }

+ 17 - 4
src/main/kotlin/com/yaoxiang/planning/utils/DateUtil.java

@@ -182,8 +182,8 @@ public class DateUtil {
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(date);
         calendar.setFirstDayOfWeek(Calendar.SUNDAY);
-        int dayofweek = calendar.get(Calendar.DAY_OF_WEEK);
-        calendar.add(Calendar.DATE, 1 - dayofweek);
+        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
+        calendar.add(Calendar.DATE, 1 - dayOfWeek);
         calendar.set(Calendar.HOUR_OF_DAY, 0);
         calendar.set(Calendar.MINUTE, 0);
         calendar.set(Calendar.SECOND, 1);
@@ -194,12 +194,25 @@ public class DateUtil {
         Calendar calendar = Calendar.getInstance();
         calendar.setTime(date);
         calendar.setFirstDayOfWeek(Calendar.SUNDAY);
-        int dayofweek = calendar.get(Calendar.DAY_OF_WEEK);
-        calendar.add(Calendar.DATE, 7 - dayofweek);
+        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
+        calendar.add(Calendar.DATE, 7 - dayOfWeek);
         calendar.set(Calendar.HOUR_OF_DAY, 23);
         calendar.set(Calendar.MINUTE, 59);
         calendar.set(Calendar.SECOND, 59);
         return calendar.getTime();
     }
+
+    public static int getMonthDay(Date date) {
+
+        Calendar a = Calendar.getInstance();
+        a.setTime(date);
+
+        a.set(Calendar.DATE, 1);
+
+        a.roll(Calendar.DATE, -1);
+
+        return a.get(Calendar.DATE);
+
+    }
 }
 

+ 65 - 0
src/main/kotlin/com/yaoxiang/planning/utils/TreeUtil.kt

@@ -0,0 +1,65 @@
+package com.yaoxiang.planning.utils
+
+import java.util.*
+
+
+class TreeUtil {
+    companion object {
+
+        fun listAllChildren(root: ToTree, allList: MutableList<ToTree>) {
+            val childList = getListChildren(root.id(), allList)
+            root.setChild(childList)
+            for (r in childList) {
+                listAllChildren(r, allList)
+            }
+        }
+
+        fun listChildren(root: ToTree, allList: MutableList<ToTree>): List<ToTree> {
+            val result = arrayListOf<ToTree>()
+            val queue = LinkedList<ToTree>()
+            result.add(root)
+            queue.offer(root)
+            while (!queue.isEmpty()) {
+                val r = queue.poll()
+                val it = allList.iterator()
+                while (it.hasNext()) {
+                    val rr = it.next()
+                    val parentId = rr.parentId()
+                    if (parentId != null && parentId == r.id()) {
+                        result.add(rr)
+                        queue.offer(rr)
+                        it.remove()
+                    }
+                }
+            }
+            return result
+        }
+
+        private fun getListChildren(id: Long, allList: MutableList<ToTree>): MutableList<ToTree> {
+            val list: MutableList<ToTree> = arrayListOf()
+            var i = 0
+            var j = allList.size
+            while (i < j) {
+                val parentId = allList[i].parentId()
+                if (parentId != null && id == parentId) {
+                    list.add(allList.removeAt(i--))
+                    j--
+                }
+                i++
+            }
+            return list
+        }
+
+
+    }
+
+}
+
+interface ToTree {
+
+    fun id(): Long
+
+    fun parentId(): Long?
+
+    fun setChild(children: MutableList<ToTree>)
+}

+ 6 - 2
src/main/resources/application.properties

@@ -14,7 +14,11 @@ spring.data.redis.repositories.enabled=false
 
 
 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
-spring.datasource.validaionQuery=select 1
+spring.datasource.validationQuery=select 1
 spring.datasource.testWhileIdle=true
 spring.datasource.testOnBorrow=false
-spring.datasource.testOnReturn=false
+spring.datasource.testOnReturn=false
+
+planning.department_name=سÏó
+planning.secret=YaoXiang@1234
+planning.default_password=Admin123

+ 14 - 0
src/test/kotlin/com/yaoxiang/planning/utils/DateUtilTest.kt

@@ -0,0 +1,14 @@
+package com.yaoxiang.planning.utils
+
+import org.junit.jupiter.api.Test
+import java.util.*
+
+class DateUtilTest {
+
+    @Test
+    fun test(){
+        val firstDayOfNextMonth = DateUtil.getFirstDayOfNextMonth(Date())
+        val a = DateUtil.getMonthDay(firstDayOfNextMonth)
+        println(a)
+    }
+}

+ 51 - 0
src/test/kotlin/com/yaoxiang/planning/utils/TreeUtilTest.kt

@@ -0,0 +1,51 @@
+package com.yaoxiang.planning.utils
+
+import com.yaoxiang.planning.domain.Department
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.Test
+
+internal class TreeUtilTest {
+
+    @BeforeEach
+    fun setUp() {
+    }
+
+    @AfterEach
+    fun tearDown() {
+    }
+
+    @Test
+    fun test() {
+        val root = Department()
+        root.id = 1
+        root.name = "root"
+
+        val child1 = Department()
+        child1.id = 2
+        child1.name = "a"
+        child1.parentId = 1
+
+        val child2 = Department()
+        child2.id = 3
+        child2.name = "b"
+        child2.parentId = 1
+
+        val child3 = Department()
+        child3.id = 4
+        child3.name = "c"
+        child3.parentId = 2
+
+        val child4 = Department()
+        child4.id = 5
+        child4.name = "d"
+        child4.parentId = 4
+
+        val list = mutableListOf<ToTree>(root, child1, child2, child3, child4)
+        TreeUtil.listAllChildren(root,list)
+
+        println(root)
+    }
+}