dev-2025 #1

Merged
luobei merged 14 commits from dev-2025 into main 2025-03-21 15:26:29 +08:00
6 changed files with 192 additions and 13 deletions
Showing only changes of commit 9fabaa9bee - Show all commits

View File

@@ -13,6 +13,7 @@ import com.pomelotea.hoperun.sign.config.HoperunUserConfig.userConfigMap
import com.pomelotea.hoperun.sign.config.UserConfig import com.pomelotea.hoperun.sign.config.UserConfig
import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler
import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.dakaQueue import com.pomelotea.hoperun.sign.scheduler.AutoDakaScheduler.Companion.dakaQueue
import com.pomelotea.hoperun.sign.scheduler.AutoRenewSessionScheduler
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.Request import okhttp3.Request
@@ -35,8 +36,11 @@ import java.util.*
@RequestMapping("/api/daka") @RequestMapping("/api/daka")
class HoperunSignController { class HoperunSignController {
val LOGIN_URL = "http://pom.hoperun.com:8187/attm/login/login"
init { init {
AutoDakaScheduler() AutoDakaScheduler()
AutoRenewSessionScheduler()
val yxl = UserConfig( val yxl = UserConfig(
project_id = "U2103S000112", project_id = "U2103S000112",
projectcode = "U2103S000112", projectcode = "U2103S000112",
@@ -46,14 +50,22 @@ class HoperunSignController {
userConfigMap["16638"] = yxl userConfigMap["16638"] = yxl
} }
@GetMapping("/username/{employeeNo}/{jsessionId}/{checked}") // @GetMapping("/username/{employeeNo}/{checked}/{jsessionId}")
@GetMapping("/username/{employeeNo}/{checked}")
fun getUsername( fun getUsername(
@PathVariable employeeNo: String, @PathVariable employeeNo: String,
@PathVariable jsessionId: String,
@PathVariable checked: Boolean @PathVariable checked: Boolean
): WebResult<LoginResponse?> { ): WebResult<LoginResponse?> {
getJsessionIdAutoLogin(employeeNo, jsessionId) /*
val userConfig = getUserConfig(employeeNo) ?: return WebResult.getFailed("登陆失败") if (jsessionId != null) {
getJsessionIdAutoLogin(employeeNo, jsessionId)
}*/
val userConfig = getUserConfig(employeeNo).let {
oldLogin(employeeNo)
getUserConfig(employeeNo)
}
userConfig ?: return WebResult.getFailed("登陆失败")
userConfig.autoDaka = checked userConfig.autoDaka = checked
userConfig.device = deviceMap[employeeNo] userConfig.device = deviceMap[employeeNo]
return WebResult.getSuccess( return WebResult.getSuccess(
@@ -138,6 +150,7 @@ class HoperunSignController {
if (sessionMap.get(employeeNo) == null) { if (sessionMap.get(employeeNo) == null) {
login(employeeNo, jsessionId) login(employeeNo, jsessionId)
} }
sessionMap[employeeNo] = jsessionId
return sessionMap.get(employeeNo) return sessionMap.get(employeeNo)
} }
@@ -186,10 +199,26 @@ class HoperunSignController {
// 读取员工姓名 // 读取员工姓名
if (userConfigMap[employeeNo]?.username == null) { if (userConfigMap[employeeNo]?.username == null) {
setUserConfig(employeeNo, jsessionId) setUserConfig(employeeNo, jsessionId)
sessionMap.put(employeeNo, jsessionId)
} }
} }
private fun oldLogin(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)
setUserConfigOld(employeeNo)
}
private fun setUserConfig(employeeNo: String, jsessionId: String) { private fun setUserConfig(employeeNo: String, jsessionId: String) {
val attendancesDetailRequest = Request.Builder() val attendancesDetailRequest = Request.Builder()
.url("http://pom.hoperun.com:8187/attm/calendar/monthAtt?staff_code=${padEmployeeNumber(employeeNo)}&yearmonth=${getNowDateyyyy_MM()}-01") .url("http://pom.hoperun.com:8187/attm/calendar/monthAtt?staff_code=${padEmployeeNumber(employeeNo)}&yearmonth=${getNowDateyyyy_MM()}-01")
@@ -252,6 +281,77 @@ class HoperunSignController {
) )
} }
private fun setUserConfigOld(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 = 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 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
}
} }

View File

@@ -11,7 +11,7 @@ object HoperunUserConfig {
val deviceMap = mapOf<String, String>( val deviceMap = mapOf<String, String>(
"16638" to "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android", "16638" to "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android",
"9119" to "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" "9119" to "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"
) )
val userConfigMap: MutableMap<String, UserConfig> = HashMap() val userConfigMap: MutableMap<String, UserConfig> = HashMap()

View File

@@ -0,0 +1,79 @@
package com.pomelotea.hoperun.sign.scheduler
import com.pomelotea.hoperun.sign.common.client
import com.pomelotea.hoperun.sign.common.sessionMap
import okhttp3.Request
import org.jsoup.Jsoup
import java.io.BufferedWriter
import java.io.File
import java.io.OutputStreamWriter
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
/**
*
* @version 0.0.1
* @author jimlee
* date 2023-03-23 08:54
*
**/
class AutoRenewSessionScheduler {
val outFile = File("./renewsession.log")
val bw: BufferedWriter = BufferedWriter(OutputStreamWriter(outFile.outputStream()))
val schedulerThreadPool: ScheduledExecutorService = Executors.newScheduledThreadPool(1)
init {
schedulerThreadPool.schedule({renewSession()}, 2, TimeUnit.MINUTES)
}
private fun renewSession() {
val iterator = sessionMap.iterator()
while (iterator.hasNext()) {
val item = iterator.next()
item.value?.let {
val result = index(it)
if (result != null) {
bw.write("[RENEW-SESSION]:SUCCESS:USER:$result")
bw.newLine()
bw.flush()
} else {
bw.write("[REMOVE-SESSION]:USER:$result")
bw.newLine()
bw.flush()
iterator.remove()
}
}
}
schedulerThreadPool.schedule({renewSession()}, (30 + Random().nextInt(30)).toLong(), TimeUnit.MINUTES)
}
private fun index(jsessionId: String): String? {
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 username = try {
Jsoup.parse(indexHtml!!).select("#attendance-detail-content > div.container.none-padding > div > div:nth-child(1) > div:nth-child(4)")
.text()
} catch (e: Exception) {
null
}
return username
}
}

View File

@@ -37,9 +37,9 @@
<div> <div>
<input class="login-input" id="employee-number" type="text" placeholder="输入工号"> <input class="login-input" id="employee-number" type="text" placeholder="输入工号">
</div> </div>
<div> <!--<div>
<input class="login-input" style="width: 280px" id="jsessionId" type="text" placeholder="输入SESSIONID"> <input class="login-input" style="width: 280px" id="jsessionId" type="text" placeholder="输入SESSIONID">
</div> </div>-->
<div> <div>
<div id="autodaka">自动打卡开关</div> <div id="autodaka">自动打卡开关</div>
</div> </div>

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>打卡</title><link rel="stylesheet"href="./normalize.min.css"><link rel="stylesheet"href="./style.css"></head><body class="dark-mode"><!--partial:index.partial.html--><div class="job"><div class="header"><div class="logo"><svg xmlns="http://www.w3.org/2000/svg"viewBox="0 0 512 512"><path xmlns="http://www.w3.org/2000/svg"d="M512 503.5H381.7a48 48 0 01-45.3-32.1L265 268.1l-9-25.5 2.7-124.6L338.2 8.5l23.5 67.1L512 503.5z"fill="#0473ff"data-original="#28b446"/><path xmlns="http://www.w3.org/2000/svg"fill="#0473ff"data-original="#219b38"d="M361.7 75.6L265 268.1l-9-25.5 2.7-124.6L338.2 8.5z"/><path xmlns="http://www.w3.org/2000/svg"d="M338.2 8.5l-82.2 234-80.4 228.9a48 48 0 01-45.3 32.1H0l173.8-495h164.4z"fill="#0473ff"data-original="#518ef8"/></svg>打卡</div><div class="user-settings"><div class="dark-light"><svg viewBox="0 0 24 24"stroke="currentColor"stroke-width="1.5"fill="none"stroke-linecap="round"stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"></path></svg></div><img class="user-profile"id="user-head"src="img/tx.png"alt=""><div id="user-div"><div id="username">未登陆</div><span id="login-span"><div class="alert-inline"><div><input class="login-input"id="employee-number"type="text"placeholder="输入工号"></div><div><input class="login-input"style="width: 280px"id="jsessionId"type="text"placeholder="输入SESSIONID"></div><div><div id="autodaka">自动打卡开关</div></div><div><div class="toggle toggle--switch"><input type="checkbox"id="toggle--switch"class="toggle--checkbox"><label class="toggle--btn"for="toggle--switch"><span class="toggle--feature"data-label-on="on"data-label-off="off"></span></label></div></div><div><button class="random-buttons"id="login">登陆</button></div></div></span><div id="logout-div"style="display: none"><button class="random-buttons"id="logout">登出</button></div></div></div></div><div class="dialog"style="display: none"><div class="alert"><div class="job-card-title"id="sign-date"><span style="font-size: 24px"></span></div><div class="alert-inline"><div><input id="sign-begin-time"type="text"placeholder="输入上班时间"></div><div><button class="random-buttons"id="sign-begin-random">随机</button></div></div><div class="alert-inline"><div><input id="sign-end-time"type="text"placeholder="输入下班时间"></div><div><button class="random-buttons"id="sign-end-random">随机</button></div></div><button class="search-buttons card-buttons begin-buttons"id="save-sign">保存</button></div></div><div class="userinfo_dialog"style="display: none"><div class="alert"><div class="job-card-title"><span style="font-size: 24px">打卡信息</span></div><div class="alert-inline"><div><label for="_user_input">用户名:</label><input id="_user_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_project_id_input">项目I D:</label><input id="_project_id_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_project_name_input">项目名称:</label><input id="_project_name_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_area_input">打卡地区:</label><input id="_area_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_device_input">设备信息:</label><input id="_device_input"readonly="readonly"type="text"></div></div></div></div><div class="wrapper"><div class="main-container"><div class="searched-jobs"><div class="searched-bar"><div class="searched-show">打卡记录</div><!--<button class="search-button">餐补<span class="canbu-span"></span></button>--></div><div class="job-cards"></div></div></div></div><script src="./coco-message.js"></script><script src="./jquery.min.js"></script><script src="./script.js"></script></div></body></html> <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>打卡</title><link rel="stylesheet"href="./normalize.min.css"><link rel="stylesheet"href="./style.css"></head><body class="dark-mode"><!--partial:index.partial.html--><div class="job"><div class="header"><div class="logo"><svg xmlns="http://www.w3.org/2000/svg"viewBox="0 0 512 512"><path xmlns="http://www.w3.org/2000/svg"d="M512 503.5H381.7a48 48 0 01-45.3-32.1L265 268.1l-9-25.5 2.7-124.6L338.2 8.5l23.5 67.1L512 503.5z"fill="#0473ff"data-original="#28b446"/><path xmlns="http://www.w3.org/2000/svg"fill="#0473ff"data-original="#219b38"d="M361.7 75.6L265 268.1l-9-25.5 2.7-124.6L338.2 8.5z"/><path xmlns="http://www.w3.org/2000/svg"d="M338.2 8.5l-82.2 234-80.4 228.9a48 48 0 01-45.3 32.1H0l173.8-495h164.4z"fill="#0473ff"data-original="#518ef8"/></svg>打卡</div><div class="user-settings"><div class="dark-light"><svg viewBox="0 0 24 24"stroke="currentColor"stroke-width="1.5"fill="none"stroke-linecap="round"stroke-linejoin="round"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"></path></svg></div><img class="user-profile"id="user-head"src="img/tx.png"alt=""><div id="user-div"><div id="username">未登陆</div><span id="login-span"><div class="alert-inline"><div><input class="login-input"id="employee-number"type="text"placeholder="输入工号"></div><!--<div><input class="login-input"style="width: 280px"id="jsessionId"type="text"placeholder="输入SESSIONID"></div>--><div><div id="autodaka">自动打卡开关</div></div><div><div class="toggle toggle--switch"><input type="checkbox"id="toggle--switch"class="toggle--checkbox"><label class="toggle--btn"for="toggle--switch"><span class="toggle--feature"data-label-on="on"data-label-off="off"></span></label></div></div><div><button class="random-buttons"id="login">登陆</button></div></div></span><div id="logout-div"style="display: none"><button class="random-buttons"id="logout">登出</button></div></div></div></div><div class="dialog"style="display: none"><div class="alert"><div class="job-card-title"id="sign-date"><span style="font-size: 24px"></span></div><div class="alert-inline"><div><input id="sign-begin-time"type="text"placeholder="输入上班时间"></div><div><button class="random-buttons"id="sign-begin-random">随机</button></div></div><div class="alert-inline"><div><input id="sign-end-time"type="text"placeholder="输入下班时间"></div><div><button class="random-buttons"id="sign-end-random">随机</button></div></div><button class="search-buttons card-buttons begin-buttons"id="save-sign">保存</button></div></div><div class="userinfo_dialog"style="display: none"><div class="alert"><div class="job-card-title"><span style="font-size: 24px">打卡信息</span></div><div class="alert-inline"><div><label for="_user_input">用户名:</label><input id="_user_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_project_id_input">项目I D:</label><input id="_project_id_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_project_name_input">项目名称:</label><input id="_project_name_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_area_input">打卡地区:</label><input id="_area_input"readonly="readonly"type="text"></div></div><div class="alert-inline"><div><label for="_device_input">设备信息:</label><input id="_device_input"readonly="readonly"type="text"></div></div></div></div><div class="wrapper"><div class="main-container"><div class="searched-jobs"><div class="searched-bar"><div class="searched-show">打卡记录</div><!--<button class="search-button">餐补<span class="canbu-span"></span></button>--></div><div class="job-cards"></div></div></div></div><script src="./coco-message.js"></script><script src="./jquery.min.js"></script><script src="./script.js"></script></div></body></html>

View File

@@ -29,13 +29,13 @@ if ($('#login-span').css('display') !== 'none') {
} }
let jsessonIdInput = document.querySelector('#jsessionId'); //let jsessonIdInput = document.querySelector('#jsessionId');
let autoDaka = document.querySelector("#toggle--switch") let autoDaka = document.querySelector("#toggle--switch")
autoDaka.checked = window.localStorage.getItem("autodaka") autoDaka.checked = window.localStorage.getItem("autodaka")
document.querySelector('#login').addEventListener("click", () => { document.querySelector('#login').addEventListener("click", () => {
window.localStorage.setItem("employeeNo", employeeNumberInput.value); window.localStorage.setItem("employeeNo", employeeNumberInput.value);
window.localStorage.setItem("jsessionId", jsessonIdInput.value); // window.localStorage.setItem("jsessionId", jsessonIdInput.value);
window.localStorage.setItem("autodaka", autoDaka.checked); window.localStorage.setItem("autodaka", autoDaka.checked);
loginAndLoadRecord(); loginAndLoadRecord();
}) })
@@ -44,12 +44,12 @@ function loginAndLoadRecord() {
$.ajax({ $.ajax({
method: "get", method: "get",
url: "/api/daka/username/" + window.localStorage.getItem("employeeNo") + "/" + window.localStorage.getItem("jsessionId") + "/" + window.localStorage.getItem("autodaka") , url: "/api/daka/username/" + window.localStorage.getItem("employeeNo") + "/" + window.localStorage.getItem("autodaka"),
success: function (result) { success: function (result) {
if (result.success) { if (result.success) {
// $("#login-span").css("display", "none"); // $("#login-span").css("display", "none");
$("#login").css("display", "none"); $("#login").css("display", "none");
$("#jsessionId").css("display", "none"); //$("#jsessionId").css("display", "none");
$("#employee-number").css("display", "none"); $("#employee-number").css("display", "none");
$('#username').text(result.data.username); $('#username').text(result.data.username);
window.localStorage.setItem("username", result.data.username); window.localStorage.setItem("username", result.data.username);