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.common.* import com.pomelotea.hoperun.sign.config.HoperunUserConfig.deviceMap import com.pomelotea.hoperun.sign.config.HoperunUserConfig.getUserConfig import com.pomelotea.hoperun.sign.config.HoperunUserConfig.userConfigMap import com.pomelotea.hoperun.sign.config.UserConfig import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.dakaQueue import okhttp3.FormBody import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import org.springframework.web.bind.annotation.* import java.text.SimpleDateFormat import java.util.* /** * * @version 0.0.1 * @author jimlee * date 2022-07-15 11:01 * update: 2023/3/22 * hoperun打卡服务接口 **/ @RestController @RequestMapping("/api/daka") class HoperunSignController { init { AutoDakaScheduler() // AutoRenewSessionScheduler() val yxl = UserConfig( project_id = "U2103S000112", projectcode = "U2103S000112", projectname = "JRKF-浙江网商-技术服务外包", device = "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android" ) userConfigMap["16638"] = yxl } // @GetMapping("/username/{employeeNo}/{checked}/{jsessionId}") @GetMapping("/username/{employeeNo}/{checked}") fun getUsername( @PathVariable employeeNo: String, @PathVariable checked: Boolean ): WebResult { /* if (jsessionId != null) { getJsessionIdAutoLogin(employeeNo, jsessionId) }*/ val userConfig = getUserConfig(employeeNo).let { defaultLogin(employeeNo) getUserConfig(employeeNo) } userConfig ?: return WebResult.getFailed("登陆失败") userConfig.autoDaka = checked userConfig.device = deviceMap[employeeNo] return WebResult.getSuccess( LoginResponse( userConfig.username, userConfig.device, userConfig.project_id, userConfig.projectname, "杭州市" ) ) } @GetMapping("/auto/{employeeNo}/{checked}") fun autoDaka(@PathVariable employeeNo: String, @PathVariable checked: Boolean): WebResult { val userConfig = getUserConfig(employeeNo) ?: return WebResult.getFailed("需要重新登录") userConfig.autoDaka = checked return WebResult.getSuccess(checked) } @GetMapping("/last/{employeeNo}") fun getLast5DaysRecord(@PathVariable employeeNo: String): WebResult { val jsessionId = sessionMap.get(employeeNo) ?: return WebResult.getFailed("登陆失败") return WebResult.getSuccess(monthAtt(employeeNo, jsessionId)) } @PostMapping("/endTime") fun endTime(@RequestBody request: DakaRequest): WebResult { val userConfig = userConfigMap.get(request.employeeNo) if (userConfig?.device == null) { return WebResult.getFailed("用户没有配置的deviceUA") } val jsessionId = sessionMap.get(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 = userConfigMap.get(request.employeeNo) if (userConfig?.device == null) { return WebResult.getFailed("用户没有配置的deviceUA") } val jsessionId = sessionMap.get(request.employeeNo) 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 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) val monthAttLog = monthAttResult.find { it.yearmonth == getNowDateyyyy_MM_dd() } val autoDaka = dakaQueue.filter { it.dakaDate == getNowDateyyyy_MM_dd() }.findLast { it.employeeNo == employeeNo } if (autoDaka != null && monthAttLog != null) { monthAttLog.autoDakaBeginTime = autoDaka.beginTime monthAttLog.autoDakaEndTime = autoDaka.endTime } monthAttResult.forEach { it.actual_area_begin = if (!it.actual_area_begin.isNullOrBlank()) { if (it.actual_area_begin == "buqianka") "补签卡" else area_regex.find(it.actual_area_begin!!)?.groups?.get(0)?.value } else null it.actual_area_end = if (!it.actual_area_end.isNullOrBlank()) { if (it.actual_area_end == "buqianka") "补签卡" else area_regex.find(it.actual_area_end!!)?.groups?.get(0)?.value } else null } 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 defaultLogin(employeeNo: String) { resetJSessionId(employeeNo) setUserConfig(employeeNo) } /* private fun setUserConfig(employeeNo: String, jsessionId: String) { val attendancesDetailRequest = Request.Builder() .url("http://pom.hoperun.com:8187/attm/calendar/monthAtt?staff_code=${padEmployeeNumber(employeeNo)}&yearmonth=${getNowDateyyyy_MM()}-01") .get() .addHeader("Cookie", "JSESSIONID=$jsessionId") .addHeader( "User-Agent", "Qing/0.9.113;iOS 16.4.1;Apple;iPhone13,2;deviceId:a8baf66f-fdeb-4f4d-b1e5-9fafcd5045b6;deviceName:iOS;clientId:10200;os:iOS 16.3.1;brand:Apple;model:iPhone13,2;lang:zh-CN;fontNum:0;fontScale:1.0;ver:10.7.14;Mozilla/5.0 (iPhone; CPU iPhone OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" ) .addHeader("accept", "*") .addHeader("Origin", "http://pom.hoperun.com:8187") .addHeader("Referer", "http://pom.hoperun.com:8187/attm/attence/getInfo") .addHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8") .build() val attendancesDetailResp = client.newCall(attendancesDetailRequest).execute() val bodyString = attendancesDetailResp.body?.string() val attendancesDetailResponse = JSONObject.parseObject(bodyString, AttendancesDetailResponse::class.java) val dataList: List = JSONObject.parseObject(attendancesDetailResponse.data, object : TypeReference>() {}) val userConfig: UserConfig = userConfigMap.get(employeeNo) ?: UserConfig() if (dataList.isNotEmpty()) { val lastDakaInfo: AttendancesDetail = dataList.sortedByDescending { it.yearmonth } .filter { it.project_id != "-1" } .filter { it.begin_time != null } .firstOrNull()!! if (userConfig.projectcode == null) { userConfig.projectcode = lastDakaInfo.projectcode } if (userConfig.projectname == null) { userConfig.projectname = lastDakaInfo.projectname } if (userConfig.project_id == null) { userConfig.project_id = lastDakaInfo.project_id } } // username 要从主页的html元素中获取 val indexRequest = Request.Builder() .url("http://pom.hoperun.com:8187/attm/attence/getInfo") .get() .addHeader("Cookie", "JSESSIONID=$jsessionId") .addHeader( "User-Agent", "Qing/0.9.113;iOS 16.3.1;Apple;iPhone13,2;deviceId:a8baf66f-fdeb-4f4d-b1e5-9fafcd5045b6;deviceName:iOS;clientId:10200;os:iOS 16.3.1;brand:Apple;model:iPhone13,2;lang:zh-CN;fontNum:0;fontScale:1.0;ver:10.7.14;Mozilla/5.0 (iPhone; CPU iPhone OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" ) .addHeader("accept", "*") .addHeader("Origin", "http://pom.hoperun.com:8187") .addHeader("Referer", "http://pom.hoperun.com:8187/attm/attence/getInfo") .addHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8") .build() val indexResp = client.newCall(indexRequest).execute() val indexHtml = indexResp.body?.string() val doc = Jsoup.parse(indexHtml!!) userConfig.username = doc.select("#attendance-detail-content > div.container.none-padding > div > div:nth-child(1) > div:nth-child(4)") .text() userConfig.employeeNo = employeeNo HoperunUserConfig.addUserConfig( employeeNo, userConfig ) }*/ private fun setUserConfig(employeeNo: String) { if (userConfigMap[employeeNo] != null && userConfigMap[employeeNo]!!.timeout > System.currentTimeMillis()) return // 获取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 = userConfigMap.get(employeeNo) ?: UserConfig() userConfig.employeeNo = employeeNo 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 && lastDakaInfo.getString("actual_area_end") != "buqianka") { val area: String = lastDakaInfo.getString("actual_area_end") userConfig.device = area.substring(area.lastIndexOf("Qing") + 13) } else if (lastDakaInfo.getString("actual_area_begin") != null) { val area: String = lastDakaInfo.getString("actual_area_begin") 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") } userConfigMap[employeeNo] = userConfig } } 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 ) { override fun toString(): String { return "DakaResponse(result=$result, comment=$comment, data=$data)" } } 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 } } } val area_regex = Regex(".*[\\u4e00-\\u9fa5]|[0-9][\\u4e00-\\u9fa5]") 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, var autoDakaBeginTime: String? = null, var autoDakaEndTime: String? = null, var actual_area_begin: String? = null, var actual_area_end: 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 )