Files
hoperun-custom-sign/src/main/kotlin/com/pomelotea/hoperun/sign/api/HoperunDakaController.kt
2025-11-04 17:19:28 +08:00

433 lines
18 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.notify.ServerChan3NotifyHelper
import com.pomelotea.hoperun.sign.service.NotificationService
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.beans.factory.annotation.Autowired
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(
@field:Autowired private val notificationService: NotificationService
) {
init {
AutoDakaScheduler(notificationService)
// 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<LoginResponse?> {
/*
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<Any?> {
val userConfig = getUserConfig(employeeNo) ?: return WebResult.getFailed("需要重新登录")
userConfig.autoDaka = checked
return WebResult.getSuccess(checked)
}
@GetMapping("/last/{employeeNo}")
fun getLast5DaysRecord(@PathVariable employeeNo: String): WebResult<Any?> {
val jsessionId = sessionMap.get(employeeNo) ?: return WebResult.getFailed("登陆失败")
return WebResult.getSuccess(monthAtt(employeeNo, jsessionId))
}
@PostMapping("/endTime")
fun endTime(@RequestBody request: DakaRequest): WebResult<Any?> {
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<Any?> {
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<MonthAttLog> {
val monthAttResult: MutableList<MonthAttLog> = ArrayList()
val monthAttList: List<MonthAttLog> = 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<MonthAttLog> =
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<MonthAttLog> {
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<List<MonthAttLog>?>() {})
}
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<AttendancesDetail> =
JSONObject.parseObject(attendancesDetailResponse.data, object : TypeReference<List<AttendancesDetail>>() {})
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<T> 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 <T> getSuccess(data: T): WebResult<T> {
return getWebResult(true, data, "success", 0)
}
fun <T> getFailed(message: String = "failed"): WebResult<T?> {
return getWebResult(false, null, message, -1)
}
fun <T> getWebResult(success: Boolean, data: T, message: String?, code: Int?): WebResult<T> {
val webResult = WebResult<T>()
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
)