package com.pomelotea.hoperun.sign.api import com.alibaba.fastjson.JSON import com.alibaba.fastjson.JSONObject import com.alibaba.fastjson.TypeReference import com.pomelotea.hoperun.sign.config.HoperunUserConfig import com.pomelotea.hoperun.sign.config.UserConfig import okhttp3.FormBody import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable 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.text.SimpleDateFormat import java.time.Duration import java.time.LocalDate import java.util.* import kotlin.collections.ArrayList import kotlin.collections.HashMap /** * * @version 0.0.1 * @author jimlee * date 2022-07-15 11:01 * hoperun打卡服务接口 **/ @RestController @RequestMapping("/api/daka") class HoperunSignController( private val hoperunUserConfig: HoperunUserConfig ) { companion object { const val DAKA_URL = "http://pom.hoperun.com:8187/attm/attence/recordAttendance" const val MONTH_ATT_URL = "http://pom.hoperun.com:8187/attm/calendar/monthAtt" const val LOGIN_URL = "http://pom.hoperun.com:8187/attm/login/login" val client = OkHttpClient() .newBuilder() .connectTimeout(Duration.ofSeconds(10)) .callTimeout(Duration.ofSeconds(10)) // .addInterceptor(LogInterceptor()) .build() val sessionMap: MutableMap = HashMap() val expireMap: MutableMap = HashMap() fun getNowDateyyyy_MM(): String { val localDate = LocalDate.now() return "${localDate.year}-${pad(localDate.monthValue)}" } fun getLastDateyyyy_MM(): String { val localDate = LocalDate.now().minusMonths(1) return "${localDate.year}-${pad(localDate.monthValue)}" } fun getNowDateyyyy_MM_dd(): String { val localDate = LocalDate.now() return "${localDate.year}-${pad(localDate.monthValue)}-${pad(localDate.dayOfMonth)}" } private fun pad(num: Int): String { return if (num < 10) "0$num" else "$num" } } @GetMapping("/username/{employeeNo}") fun getUsername(@PathVariable employeeNo: String): WebResult { val userConfig = getUserConfig(employeeNo) if (userConfig == null) { return WebResult.getFailed("登陆失败") } return WebResult.getSuccess( LoginResponse( userConfig.username, userConfig.device, userConfig.project_id, userConfig.projectname, "杭州市" ) ) } @GetMapping("/last/{employeeNo}") fun getLast5DaysRecord(@PathVariable employeeNo: String): WebResult { val jsessionId = getJsessionIdAutoLogin(employeeNo) ?: return WebResult.getFailed("登陆失败") return WebResult.getSuccess(monthAtt(employeeNo, jsessionId)) } @PostMapping("/endTime") fun endTime(@RequestBody request: DakaRequest): WebResult { val userConfig = hoperunUserConfig.userConfigMap.get(request.employeeNo) if (userConfig?.device == null) { return WebResult.getFailed("用户没有配置的deviceUA") } val jsessionId = getJsessionIdAutoLogin(request.employeeNo) if (jsessionId == null) { return WebResult.getFailed("登陆失败") } val date = if (request.date == "今天") SimpleDateFormat("yyyy-MM-dd").format(Date()) else request.date val dakaRequest = Request.Builder() .url(DAKA_URL) .post( JSON.toJSONString( endTimeHoperunDakaRequest( request.employeeNo, date, request.time ) ).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull()) ) .addHeader("Cookie", "JSESSIONID=$jsessionId") .build() val result: String? = client.newCall(dakaRequest).execute().body?.string() return WebResult.getSuccess(JSONObject.parseObject(result, DakaResponse::class.java)) } @PostMapping("/beginTime") fun beginTime(@RequestBody request: DakaRequest): WebResult { val userConfig = hoperunUserConfig.userConfigMap.get(request.employeeNo) if (userConfig?.device == null) { return WebResult.getFailed("用户没有配置的deviceUA") } val jsessionId = getJsessionIdAutoLogin(request.employeeNo) if (jsessionId == null) { return WebResult.getFailed("登陆失败") } val date = if (request.date == "今天") SimpleDateFormat("yyyy-MM-dd").format(Date()) else request.date val dakaRequest = Request.Builder() .url(DAKA_URL) .post( JSON.toJSONString( beginTimeHoperunDakaRequest( request.employeeNo, date, request.time ) ).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull()) ) .addHeader("Cookie", "JSESSIONID=$jsessionId") .build() val result: String? = client.newCall(dakaRequest).execute().body?.string() return WebResult.getSuccess(JSONObject.parseObject(result, DakaResponse::class.java)) } private fun getJsessionIdAutoLogin(employeeNo: String): String? { if (sessionMap.get(employeeNo) == null || expireMap.get(employeeNo) == null || expireMap.get(employeeNo)!! < System.currentTimeMillis()) { login(employeeNo) } return sessionMap.get(employeeNo) } private fun getUserConfig(employeeNo: String): UserConfig? { val userConfig = hoperunUserConfig.userConfigMap.get(employeeNo) if (userConfig?.username == null) { login(employeeNo) } return hoperunUserConfig.userConfigMap.get(employeeNo) } /** * 查询近两个月的 */ private fun monthAtt(employeeNo: String, jsessionId: String): List { val monthAttResult: MutableList = ArrayList() val monthAttList: List = queryMonthAttData(employeeNo, jsessionId, getNowDateyyyy_MM() + "-01") // 如果dateType = 1的结果小于3条,查询上月 val monthAttLogs = monthAttList.sortedByDescending { it.yearmonth }.filter { it.dateType == "1" } .filter { it.yearmonth!!.compareTo(getNowDateyyyy_MM_dd()) <= 0 } monthAttResult.addAll(monthAttLogs) val lastMonthAttList: List = queryMonthAttData(employeeNo, jsessionId, getLastDateyyyy_MM() + "-01") val lastMonthAttLogs = lastMonthAttList.sortedByDescending { it.yearmonth }.filter { it.dateType == "1" } monthAttResult.addAll(lastMonthAttLogs) return monthAttResult } private fun queryMonthAttData(employeeNo: String, jsessionId: String, yearmonth: String): List { val monthAttRequest = Request.Builder() .url(MONTH_ATT_URL) .post( FormBody.Builder() .add("staff_code", padEmployeeNumber(employeeNo)) .add("yearmonth", yearmonth) .build() ) .addHeader("Cookie", "JSESSIONID=$jsessionId") .build() val result: String? = client.newCall(monthAttRequest).execute().body?.string() return JSONObject.parseObject( JSONObject.parseObject(result).getString("data"), object : TypeReference?>() {}) } private fun login(employeeNo: String) { val jsessionId: String? val loginRequest = Request.Builder() .url(LOGIN_URL) .post( FormBody.Builder() .add("login_id", padEmployeeNumber(employeeNo)) .add("password", "123456") .build() ) .build() val response = client.newCall(loginRequest).execute() jsessionId = response.request.url.pathSegments[2].substring(19) sessionMap.put(employeeNo, jsessionId) expireMap.put(employeeNo, System.currentTimeMillis() + 300000) // 读取员工姓名 if (hoperunUserConfig.userConfigMap[employeeNo]?.username == null) { setUserConfig(employeeNo) } } private fun setUserConfig(employeeNo: String) { // 获取deviceua val loginRequest = Request.Builder() .url("http://pom.hoperun.com:8187/attp/login/login.do") .post( JSON.toJSONString( mapOf( "login_id" to padEmployeeNumber(employeeNo), "password" to "123456", "roleType" to "0" ) ).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull()) ) .build() val response = client.newCall(loginRequest).execute() val jsessionId = response.headers("Set-Cookie")[0].substring(11, 43) val attendancesDetailRequest = Request.Builder() .url("http://pom.hoperun.com:8187/attp/attendances/queryAttendancesDetail") .post( JSON.toJSONString( mapOf( "beginDate" to getLastDateyyyy_MM() + "-21", "endDate" to getNowDateyyyy_MM_dd(), "staffCode" to padEmployeeNumber(employeeNo) ) ).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull()) ) .addHeader("Cookie", "JSESSIONID=$jsessionId") .build() val attendancesDetailResponse = client.newCall(attendancesDetailRequest).execute() val bodyString = attendancesDetailResponse.body?.string() val dakaJsonArray = JSONObject.parseArray(bodyString) val dakaInfo = dakaJsonArray.getJSONObject(dakaJsonArray.size - 1) val dakaList = dakaInfo.getJSONArray("list") var lastDakaInfo = dakaList.getJSONObject(dakaList.size - 1) val userConfig: UserConfig = hoperunUserConfig.userConfigMap.get(employeeNo) ?: UserConfig() if (lastDakaInfo.getString("begin_time") == null) { for (i in dakaList.size - 1 downTo 0) { lastDakaInfo = dakaList.getJSONObject(i) if (lastDakaInfo.getString("actual_area_end") != null) { break } } } val username: String = lastDakaInfo.getString("staff_name") userConfig.username = username if (userConfig.device == null) { if (lastDakaInfo.getString("actual_area_end") != null) { val area: String = lastDakaInfo.getString("actual_area_end") userConfig.device = area.substring(area.lastIndexOf("Qing") + 13) } else { userConfig.device = null } } if (userConfig.projectcode == null) { userConfig.projectcode = dakaInfo.getString("pro_id") } if (userConfig.projectname == null) { userConfig.projectname = dakaInfo.getString("pro_name") } if (userConfig.project_id == null) { userConfig.project_id = dakaInfo.getString("pro_id") } hoperunUserConfig.addUserConfig( employeeNo, userConfig ) } private fun beginTimeHoperunDakaRequest( employeeNo: String, yearmonth: String, begin_time: String? ): HoperunDakaRequest { val ua = hoperunUserConfig.getUA(employeeNo) val userConfig: UserConfig = getUserConfig(employeeNo)!! val hoperunDakaRequest = HoperunDakaRequest( staff_code = padEmployeeNumber(employeeNo), yearmonth = yearmonth, userConfig.project_id!!, userConfig.projectname!!, userConfig.projectcode!!, actualArea = ua ) hoperunDakaRequest.begin_time = begin_time return hoperunDakaRequest } private fun endTimeHoperunDakaRequest( employeeNo: String, yearmonth: String, end_time: String? ): HoperunDakaRequest { val ua = hoperunUserConfig.getUA(employeeNo) val userConfig: UserConfig = getUserConfig(employeeNo)!! val hoperunDakaRequest = HoperunDakaRequest( staff_code = padEmployeeNumber(employeeNo), yearmonth = yearmonth, userConfig.project_id!!, userConfig.projectname!!, userConfig.projectcode!!, actualArea = ua ) hoperunDakaRequest.end_time = end_time return hoperunDakaRequest } fun padEmployeeNumber(employeeNumber: String): String { return when (employeeNumber.length) { 5 -> "0000" + employeeNumber 4 -> "00000" + employeeNumber else -> employeeNumber } } } data class DakaRequest( val employeeNo: String, val date: String, val time: String ) data class DakaResponse( var result: String? = null, var comment: String? = null, var data: String? = null ) class WebResult protected constructor() : java.io.Serializable { var data: T? = null var code: Int? = null var success = false var message: String? = null @Suppress("UNUSED") var timestamp = System.currentTimeMillis() companion object { fun getSuccess(data: T): WebResult { return getWebResult(true, data, "success", 0) } fun getFailed(message: String = "failed"): WebResult { return getWebResult(false, null, message, -1) } fun getWebResult(success: Boolean, data: T, message: String?, code: Int?): WebResult { val webResult = WebResult() webResult.success = success webResult.data = data webResult.code = code webResult.message = message return webResult } } } data class MonthAttLog( var area_id: String? = null, var area_id_begin: String? = null, var area_id_end: String? = null, var attState: String? = null, var att_type: String? = null, var begin_time: String? = null, var dateType: String? = null, var departmentcode: String? = null, var end_time: String? = null, var project_id: String? = null, var projectcode: String? = null, var staff_code: String? = null, var yearmonth: String? = null ) data class HoperunDakaRequest( val staff_code: String, val yearmonth: String, var project_id: String = "U2103S000078", var projectname: String = "JRKF-银河资产对接合作平台贷项目", var projectcode: String = "U2103S000078", val area_id: String = "杭州市", val actualArea: String, var begin_time: String? = null, var end_time: String? = null ) data class LoginResponse( var username: String? = null, var device: String? = null, var project_id: String? = null, var projectname: String? = null, var area: String? = null )