diff --git a/.gitignore b/.gitignore
index 950739f..113f68d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,7 @@ logs
**/target
**/logs
*.sh
+
+.idea
+
+
diff --git a/DockerFile b/DockerFile
new file mode 100644
index 0000000..f01ee85
--- /dev/null
+++ b/DockerFile
@@ -0,0 +1,8 @@
+FROM openjdk:8-jre
+LABEL name="hoperun-custom-sign"
+MAINTAINER li@2ha.me
+WORKDIR /
+ADD target/hoperun-sign-1.0-SNAPSHOT.jar app.jar
+EXPOSE 8982
+ENTRYPOINT ["java", "-jar"]
+CMD ["app.jar"]
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index e5ab319..be3be00 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
UTF-8
official
1.8
- 1.7.22
+ 2.0.20
@@ -34,7 +34,7 @@
true
./target
- executable
+
@@ -89,6 +89,7 @@
1.8
+
@@ -116,6 +117,12 @@
kotlin-stdlib-jdk8
${kotlin.version}
+
+
+ org.jsoup
+ jsoup
+ 1.15.3
+
diff --git a/settings.xml b/settings.xml
new file mode 100644
index 0000000..75e7680
--- /dev/null
+++ b/settings.xml
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2ha
+ jimlee
+ wysnih-dybbyQ-0rigti
+
+
+ maven-releases
+ jimlee
+ wysnih-dybbyQ-0rigti
+
+
+ maven-snapshots
+ jimlee
+ wysnih-dybbyQ-0rigti
+
+
+
+
+
+
+
+ mirror-all
+ *
+ 2ha mirror
+ https://2ha.me:18082/repository/maven-public/
+
+
+
+
+
+
+
+
+
+ jimlee-dev
+
+
+ 2ha
+ 2ha.me nexus private
+ https://2ha.me:18082/repository/maven-public/
+
+ true
+
+
+ true
+ always
+
+
+
+ maven-releases
+ Nexus Release Repository
+ https://2ha.me:18082/repository/private/
+
+
+ maven-snapshots
+ Nexus Snapshot Repository
+ https://2ha.me:18082/repository/private/
+
+
+
+
+
+
+
+ jimlee-dev
+
+
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/DakaApplication.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/DakaApplication.kt
index a1caff0..c5e5b87 100644
--- a/src/main/kotlin/com/pomelotea/hoperun/sign/DakaApplication.kt
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/DakaApplication.kt
@@ -1,5 +1,6 @@
package com.pomelotea.hoperun.sign
+import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@@ -14,8 +15,29 @@ import java.util.*
* 启动入口
**/
@SpringBootApplication
-open class DakaApplication {
-}
+open class DakaApplication
+
+val T.logger: Logger
+ get() = LoggerFactory.getLogger(this::class.java)
+
+val holidays: List = listOf(
+ // 元旦
+ "2025-01-01",
+ // 春节
+ "2025-01-28", "2025-01-29", "2025-01-30", "2025-01-31", "2025-02-01", "2025-02-02", "2025-02-03", "2025-02-04",
+ // 清明
+ "2025-04-04", "2025-04-05", "2025-04-06",
+ // 劳动节
+ "2025-05-01", "2025-05-02", "2025-05-05", "2025-05-04", "2025-05-05",
+ // 端午节
+ "2025-05-31", "2025-06-01", "2025-06-02",
+ // 中秋
+ // 国庆
+ "2025-10-01", "2025-10-02", "2025-10-03", "2025-10-04", "2025-10-05", "2025-10-06", "2025-10-07", "2025-10-08")
+
+// 周末要上班的日期
+val workdays: List = listOf("2025-01-26", "2025-02-08", "2025-04-27", "2025-10-11", "2025-09-28", "2025-10-12")
+
private val logger = LoggerFactory.getLogger("APPLICATION-STARTER")
fun main(args: Array) {
SpringApplication.run(DakaApplication::class.java, *args)
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/api/HoperunDakaController.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/api/HoperunDakaController.kt
index 7bd3da0..a20ce96 100644
--- a/src/main/kotlin/com/pomelotea/hoperun/sign/api/HoperunDakaController.kt
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/api/HoperunDakaController.kt
@@ -3,81 +3,66 @@ 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.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.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 org.springframework.web.bind.annotation.*
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
+ * update: 2023/3/22
* 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()
+class HoperunSignController {
- 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"
- }
+ 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}")
- fun getUsername(@PathVariable employeeNo: String): WebResult {
- val userConfig = getUserConfig(employeeNo)
- if (userConfig == null) {
- return WebResult.getFailed("登陆失败")
+// @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,
@@ -89,19 +74,26 @@ class HoperunSignController(
)
}
+ @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 = getJsessionIdAutoLogin(employeeNo) ?: return WebResult.getFailed("登陆失败")
+ val jsessionId = sessionMap.get(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)
+ val userConfig = userConfigMap.get(request.employeeNo)
if (userConfig?.device == null) {
return WebResult.getFailed("用户没有配置的deviceUA")
}
- val jsessionId = getJsessionIdAutoLogin(request.employeeNo)
+ val jsessionId = sessionMap.get(request.employeeNo)
if (jsessionId == null) {
return WebResult.getFailed("登陆失败")
}
@@ -126,14 +118,11 @@ class HoperunSignController(
@PostMapping("/beginTime")
fun beginTime(@RequestBody request: DakaRequest): WebResult {
- val userConfig = hoperunUserConfig.userConfigMap.get(request.employeeNo)
+ val userConfig = userConfigMap.get(request.employeeNo)
if (userConfig?.device == null) {
return WebResult.getFailed("用户没有配置的deviceUA")
}
- val jsessionId = getJsessionIdAutoLogin(request.employeeNo)
- if (jsessionId == null) {
- return WebResult.getFailed("登陆失败")
- }
+ 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)
@@ -152,20 +141,6 @@ class HoperunSignController(
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)
- }
/**
* 查询近两个月的
@@ -181,6 +156,13 @@ class HoperunSignController(
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
+ }
return monthAttResult
}
@@ -201,30 +183,77 @@ class HoperunSignController(
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 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")
@@ -260,8 +289,8 @@ class HoperunSignController(
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()
-
+ 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)
@@ -273,7 +302,8 @@ class HoperunSignController(
val username: String = lastDakaInfo.getString("staff_name")
userConfig.username = username
if (userConfig.device == null) {
- if (lastDakaInfo.getString("actual_area_end") != 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) {
@@ -292,59 +322,8 @@ class HoperunSignController(
if (userConfig.project_id == null) {
userConfig.project_id = dakaInfo.getString("pro_id")
}
- hoperunUserConfig.addUserConfig(
- employeeNo, userConfig
- )
+ userConfigMap[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
- }
- }
-
}
@@ -358,7 +337,13 @@ 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
@@ -402,7 +387,9 @@ data class MonthAttLog(
var project_id: String? = null,
var projectcode: String? = null,
var staff_code: String? = null,
- var yearmonth: String? = null
+ var yearmonth: String? = null,
+ var autoDakaBeginTime: String? = null,
+ var autoDakaEndTime: String? = null,
)
data class HoperunDakaRequest(
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/api/model/AttendancesDetailResponse.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/api/model/AttendancesDetailResponse.kt
new file mode 100644
index 0000000..ff2ec5f
--- /dev/null
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/api/model/AttendancesDetailResponse.kt
@@ -0,0 +1,30 @@
+package com.pomelotea.hoperun.sign.api.model
+
+/**
+ *
+ * @version 0.0.1
+ * @author jimlee
+ * date 2023-03-22 13:52
+ *
+ **/
+data class AttendancesDetailResponse(
+ val data: String,
+ val success: Boolean = false
+)
+
+data class AttendancesDetail(
+ val area_id: String? = null,
+ val area_id_begin: String? = null,
+ val area_id_end: String? = null,
+ val attState: String? = null,
+ val att_type: String? = null,
+ val begin_time: String? = null,
+ val dateType: String? = null,
+ val departmentcode: String? = null,
+ val end_time: String? = null,
+ val project_id: String? = null,
+ val projectcode: String? = null,
+ val projectname: String? = null,
+ val staff_code: String? = null,
+ val yearmonth: String? = null,
+)
\ No newline at end of file
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/common/Common.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/common/Common.kt
new file mode 100644
index 0000000..42296ed
--- /dev/null
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/common/Common.kt
@@ -0,0 +1,188 @@
+package com.pomelotea.hoperun.sign.common
+
+import com.alibaba.fastjson.JSON
+import com.alibaba.fastjson.JSONObject
+import com.pomelotea.hoperun.sign.api.DakaResponse
+import com.pomelotea.hoperun.sign.api.HoperunDakaRequest
+import com.pomelotea.hoperun.sign.config.HoperunUserConfig
+import com.pomelotea.hoperun.sign.config.HoperunUserConfig.getUserConfig
+import com.pomelotea.hoperun.sign.config.UserConfig
+import com.pomelotea.hoperun.sign.holidays
+import com.pomelotea.hoperun.sign.workdays
+import okhttp3.FormBody
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import java.time.DayOfWeek
+import java.time.Duration
+import java.time.LocalDate
+import java.time.ZoneOffset
+import java.time.format.DateTimeFormatter
+import java.util.*
+
+/**
+ *
+ * @version 0.0.1
+ * @author jimlee
+ * date 2023-03-22 15:45
+ *
+ **/
+
+
+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"
+val DEFAULT_ZONE: ZoneOffset = ZoneOffset.of("+8")
+
+val client = OkHttpClient()
+ .newBuilder()
+ .connectTimeout(Duration.ofSeconds(10))
+ .callTimeout(Duration.ofSeconds(10))
+// .addInterceptor(LogInterceptor())
+ .build()
+val sessionMap: 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)}"
+}
+
+fun getYesterdayyyyy_MM_dd(): String {
+ val localDate = LocalDate.now()
+ localDate.plusDays(-1)
+ return "${localDate.year}-${pad(localDate.monthValue)}-${pad(localDate.dayOfMonth)}"
+}
+
+
+private fun pad(num: Int): String {
+ return if (num < 10) "0$num" else "$num"
+}
+fun isWeekend(dakaDate: String): Boolean {
+ val date = LocalDate.parse(dakaDate, DateTimeFormatter.ISO_LOCAL_DATE)
+ return date.dayOfWeek == DayOfWeek.SATURDAY || date.dayOfWeek == DayOfWeek.SUNDAY
+}
+
+fun isWeekday(dakaDate: String): Boolean {
+ val date = LocalDate.parse(dakaDate, DateTimeFormatter.ISO_LOCAL_DATE)
+ return date.dayOfWeek == DayOfWeek.MONDAY || date.dayOfWeek == DayOfWeek.TUESDAY
+ || date.dayOfWeek == DayOfWeek.WEDNESDAY || date.dayOfWeek == DayOfWeek.THURSDAY || date.dayOfWeek == DayOfWeek.FRIDAY
+}
+
+fun beginTime(employeeNo: String, date: String, time: String, jsessionId: String = sessionMap.get(employeeNo)!!): DakaResponse {
+ val dakaRequest = Request.Builder()
+ .url(DAKA_URL)
+ .post(
+ JSON.toJSONString(
+ beginTimeHoperunDakaRequest(
+ employeeNo,
+ date,
+ time
+ )
+ ).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull())
+ )
+ .addHeader("Cookie", "JSESSIONID=$jsessionId")
+ .build()
+ val result: String? = client.newCall(dakaRequest).execute().body?.string()
+ return JSONObject.parseObject(result, DakaResponse::class.java)
+}
+
+
+
+fun beginTimeHoperunDakaRequest(
+ employeeNo: String,
+ yearmonth: String,
+ begin_time: String?
+): HoperunDakaRequest {
+ val ua = HoperunUserConfig.getUA(employeeNo)
+ val userConfig: UserConfig = HoperunUserConfig.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
+}
+
+fun endTime(employeeNo: String, date: String, time: String, jsessionId: String = sessionMap.get(employeeNo)!!): DakaResponse {
+ val dakaRequest = Request.Builder()
+ .url(DAKA_URL)
+ .post(
+ JSON.toJSONString(
+ endTimeHoperunDakaRequest(
+ employeeNo,
+ date,
+ time
+ )
+ ).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull())
+ )
+ .addHeader("Cookie", "JSESSIONID=$jsessionId")
+ .build()
+ val result: String? = client.newCall(dakaRequest).execute().body?.string()
+ return JSONObject.parseObject(result, DakaResponse::class.java)
+}
+
+fun padEmployeeNumber(employeeNumber: String): String {
+ return when (employeeNumber.length) {
+ 5 -> "0000" + employeeNumber
+ 4 -> "00000" + employeeNumber
+ else -> employeeNumber
+ }
+}
+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
+}
+
+const val LOGIN_URL = "http://pom.hoperun.com:8187/attm/login/login"
+fun resetJSessionId(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)
+}
+
+fun randowSecond(): String {
+ val second = Random().nextInt(59)
+ return if (second < 10) "0$second" else "$second"
+}
+
+fun isNeedDaka(dakaDate: String): Boolean {
+ return workdays.contains(dakaDate) || (isWeekday(dakaDate) && !holidays.contains(dakaDate))
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/config/HoperunUserConfig.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/config/HoperunUserConfig.kt
index e3ea191..a506680 100644
--- a/src/main/kotlin/com/pomelotea/hoperun/sign/config/HoperunUserConfig.kt
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/config/HoperunUserConfig.kt
@@ -1,8 +1,5 @@
package com.pomelotea.hoperun.sign.config
-import org.springframework.boot.context.properties.ConfigurationProperties
-import org.springframework.context.annotation.Configuration
-
/**
*
* @version 0.0.1
@@ -10,16 +7,24 @@ import org.springframework.context.annotation.Configuration
* date 2022-07-18 09:56
* 用户配置
**/
-@Configuration
-@ConfigurationProperties("hoperun")
-open class HoperunUserConfig {
+object HoperunUserConfig {
+
+ val deviceMap = mapOf(
+ "16638" to "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android",
+ "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 = HashMap()
- var address: String = "浙江省杭州市西湖区万塘路18号黄龙时代广场B座"
- var longitueHead: String = "120.131"
- var latitudeHead: String = "30.279"
- var longitueShort: String = "120.136679"
- var latitudeShort: String = "30.279766"
- var qingUa: String = "Qing/0.9.101"
+ var address: String = "浙江省杭州市西湖区飞天园区1号楼"
+ var longitueHead: String = "120.085"
+ var latitudeHead: String = "30.138"
+ var longitueShort: String = "120.0845715522375"
+ var latitudeShort: String = "30.140219809955912"
+ var qingUa: String = "Qing/0.9.113"
+
+ fun getUserConfig(employeeNo: String): UserConfig? {
+ return userConfigMap.get(employeeNo)
+ }
fun getUA(emplotyeeNo: String): String {
return address +
@@ -28,7 +33,7 @@ open class HoperunUserConfig {
"$longitueShort," +
"$latitudeShort;" +
"$qingUa;" +
- (userConfigMap.get(emplotyeeNo)!!.device ?: "")
+ (deviceMap.get(emplotyeeNo) ?: "")
}
fun addUserConfig(emplotyeeNo: String, userConfig: UserConfig) {
@@ -52,8 +57,11 @@ open class HoperunUserConfig {
data class UserConfig(
var username: String? = null,
+ var employeeNo: String? = null,
var device: String? = null,
var project_id: String? = null,
var projectname: String? = null,
- var projectcode: String? = null
+ var projectcode: String? = null,
+ var autoDaka: Boolean = false,
+ val timeout: Long = System.currentTimeMillis() + 1000 * 60 * 30
)
\ No newline at end of file
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/config/WebConfig.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/config/WebConfig.kt
new file mode 100644
index 0000000..397eeb2
--- /dev/null
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/config/WebConfig.kt
@@ -0,0 +1,22 @@
+package com.pomelotea.hoperun.sign.config
+
+import org.springframework.context.annotation.Configuration
+import org.springframework.web.servlet.config.annotation.CorsRegistry
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
+
+/**
+ *
+ * @author jimlee
+ * @create 2024/11/1 13:15
+ */
+@Configuration
+open class CorsConfig : WebMvcConfigurer {
+ override fun addCorsMappings(registry: CorsRegistry) {
+ registry.addMapping("/**")
+ .allowedMethods("*")
+ .allowedHeaders("*")
+ .allowedOriginPatterns("*")
+ .allowCredentials(true)
+ .maxAge(3600)
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/scheduler/AutoDakaScheduler.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/scheduler/AutoDakaScheduler.kt
new file mode 100644
index 0000000..ad370a0
--- /dev/null
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/scheduler/AutoDakaScheduler.kt
@@ -0,0 +1,170 @@
+package com.pomelotea.hoperun.sign.scheduler
+
+import com.pomelotea.hoperun.sign.api.DakaResponse
+import com.pomelotea.hoperun.sign.common.*
+import com.pomelotea.hoperun.sign.config.HoperunUserConfig
+import com.pomelotea.hoperun.sign.config.UserConfig
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
+import java.util.*
+import java.util.concurrent.Executors
+import java.util.concurrent.ScheduledExecutorService
+import java.util.concurrent.ScheduledThreadPoolExecutor
+import java.util.concurrent.TimeUnit
+
+/**
+ *
+ * @version 0.0.1
+ * @author jimlee
+ * date 2023-03-22 14:50
+ * 自动打卡定时任务
+ **/
+class AutoDakaScheduler {
+
+ val timeThreadPool: ScheduledExecutorService = Executors.newScheduledThreadPool(1)
+ val schedulerThreadPool: ScheduledExecutorService = Executors.newScheduledThreadPool(10)
+
+ init {
+ timeThreadPool.scheduleAtFixedRate({ addAutoDakaScheduled() }, 1, 60, TimeUnit.MINUTES)
+ }
+
+ companion object {
+ val dakaQueue: MutableList = LinkedList()
+ val logger: Logger = LoggerFactory.getLogger("DAKA-SHCEDULER")
+ }
+
+ fun addAutoDakaScheduled(dakaDate: String = getNowDateyyyy_MM_dd()) {
+ // 调休的工作日
+ if (isNeedDaka(dakaDate)) {
+ HoperunUserConfig.userConfigMap.forEach { (_, v) ->
+ if (v.autoDaka) {
+ // 没有当日的打卡信息才插入
+ var daka = dakaQueue.find { it.dakaDate == dakaDate && it.employeeNo == v.employeeNo }
+ if (daka == null) {
+ daka = generateDakaInfo(v, dakaDate)
+ dakaQueue.add(daka)
+ }
+ logger.info("${v.username},${daka.toCsv()}")
+ }
+ }
+ }
+
+ dakaQueue.forEach {
+ if (!it.added) {
+ it.added = true
+ val beginDate = LocalDateTime.parse(
+ it.dakaDate + "T" + it.beginTime + ":" + randowSecond(),
+ DateTimeFormatter.ISO_LOCAL_DATE_TIME
+ )
+ val endDate = LocalDateTime.parse(
+ it.dakaDate + "T" + it.endTime + ":" + randowSecond(),
+ DateTimeFormatter.ISO_LOCAL_DATE_TIME
+ )
+ val beginSeconds = beginDate.toEpochSecond(DEFAULT_ZONE) - (System.currentTimeMillis() / 1000)
+ val endSeconds = endDate.toEpochSecond(DEFAULT_ZONE) - (System.currentTimeMillis() / 1000)
+ if (beginSeconds > 0) {
+ logger.info("[ADD-SCHEDULE]BEGIN:${it.employeeNo}:DATE:${it.dakaDate}TIME:${it.beginTime}")
+ schedulerThreadPool.schedule({ beginDaka(it) }, beginSeconds, TimeUnit.SECONDS)
+ }
+ if (endSeconds > 0) {
+ logger.info("[ADD-SCHEDULE]END:${it.employeeNo}:DATE:${it.dakaDate}TIME:${it.endTime}")
+ schedulerThreadPool.schedule({ endDaka(it) }, endSeconds, TimeUnit.SECONDS)
+ }
+ }
+// schedulerThreadPool.schedule({beginDaka(it)}, 5, TimeUnit.SECONDS)
+// schedulerThreadPool.schedule({ endDaka(it) }, 10, TimeUnit.SECONDS)
+ }
+
+ dakaQueue.removeIf { it.dakaDate.compareTo(dakaDate) == -1 }
+ printScheduler()
+ dakaQueue.forEach {
+ logger.info("Task: ${it.toCsv()}")
+ }
+ }
+
+ private fun beginDaka(daka: Daka) {
+// println("begin:${daka.toCsv()}")
+ try {
+ logger.info("[EXECUTE]BEGIN:${daka.employeeNo}:DATE:${daka.dakaDate}:TIME:${daka.beginTime}")
+ // 模拟重新登录打卡
+ logger.info("${daka.employeeNo}OLD-JSESSIONID: ${sessionMap[daka.employeeNo]}")
+ resetJSessionId(employeeNo = daka.employeeNo)
+ logger.info("${daka.employeeNo}NEW-JSESSIONID: ${sessionMap[daka.employeeNo]}")
+ val resp: DakaResponse =
+ beginTime(employeeNo = daka.employeeNo, date = daka.dakaDate, time = daka.beginTime)
+ if (resp.result != "success") {
+ logger.error("打上班卡失败")
+ } else {
+ logger.info("打上班卡成功")
+ }
+ } catch (e: Exception) {
+ logger.error(e.message, e)
+ }
+
+ }
+
+ private fun endDaka(daka: Daka) {
+// println("end:${daka.toCsv()}")
+ try {
+ logger.info("[EXECUTE]END:${daka.employeeNo}:DATE:${daka.dakaDate}:TIME:${daka.endTime}")
+ // 模拟重新登录打卡
+ logger.info("${daka.employeeNo}OLD-JSESSIONID: ${sessionMap[daka.employeeNo]}")
+ resetJSessionId(employeeNo = daka.employeeNo)
+ logger.info("${daka.employeeNo}NEW-JSESSIONID: ${sessionMap[daka.employeeNo]}")
+ val resp: DakaResponse = endTime(employeeNo = daka.employeeNo, date = daka.dakaDate, time = daka.endTime)
+ if (resp.result != "success") {
+ logger.error("打下班卡失败")
+ } else {
+ logger.info("打下班卡成功")
+ }
+ } catch (e: Exception) {
+ logger.error(e.message, e)
+ }
+ }
+
+ private fun generateDakaInfo(userConfig: UserConfig, dakaDate: String): Daka {
+ return Daka(
+ beginTime = "09:" + (10 + Random().nextInt(19)),
+ endTime = getRandomEndTime(),
+ employeeNo = userConfig.employeeNo!!,
+ dakaDate = dakaDate
+ )
+ }
+
+ fun printScheduler() {
+ schedulerThreadPool as ScheduledThreadPoolExecutor
+ val queue = schedulerThreadPool.queue
+ logger.info("任务队列数量: ${queue.size}")
+ }
+
+ private fun getRandomEndTime(): String {
+ val hourArray = intArrayOf(18, 19, 20, 19, 19, 20, 19, 20, 20, 19, 18, 20)
+ val randomHour = hourArray[Math.round(Math.random() * 9).toInt()]
+ val randomMinute = if (randomHour == 18) {
+ 30 + Random().nextInt(19)
+ } else {
+ val min = Random().nextInt(59)
+ if (min < 10) {
+ "0$min"
+ } else {
+ min
+ }
+ }
+ return "$randomHour:$randomMinute"
+ }
+
+}
+
+data class Daka(
+ val beginTime: String,
+ val endTime: String,
+ val employeeNo: String,
+ val dakaDate: String,
+ var added: Boolean = false
+) {
+ fun toCsv(): String {
+ return "$employeeNo,$dakaDate,$beginTime,$endTime,$added"
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/pomelotea/hoperun/sign/scheduler/AutoRenewSessionScheduler.kt b/src/main/kotlin/com/pomelotea/hoperun/sign/scheduler/AutoRenewSessionScheduler.kt
new file mode 100644
index 0000000..03cdc35
--- /dev/null
+++ b/src/main/kotlin/com/pomelotea/hoperun/sign/scheduler/AutoRenewSessionScheduler.kt
@@ -0,0 +1,70 @@
+package com.pomelotea.hoperun.sign.scheduler
+
+import com.pomelotea.hoperun.sign.common.client
+import com.pomelotea.hoperun.sign.common.sessionMap
+import com.pomelotea.hoperun.sign.logger
+import okhttp3.Request
+import org.jsoup.Jsoup
+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 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) {
+ logger.info("[RENEW-SESSION]:SUCCESS:USER:$result")
+ } else {
+ logger.info("[REMOVE-SESSION]:USER:$result")
+ 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
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml
index dcee88a..d0f4f66 100644
--- a/src/main/resources/config/application-dev.yml
+++ b/src/main/resources/config/application-dev.yml
@@ -1,5 +1,5 @@
server:
- port: 8080
+ port: 8982
hoperun:
address: "浙江省杭州市西湖区转塘街道凌家桥路飞天园区120"
@@ -8,3 +8,4 @@ hoperun:
longitueShort: "120.0845715522375"
latitudeShort: "30.140219809955912"
qingUa: "Qing/0.9.113"
+
diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml
index 37e5d36..677f0b8 100644
--- a/src/main/resources/config/application.yml
+++ b/src/main/resources/config/application.yml
@@ -1,5 +1,5 @@
server:
- port: 8080
+ port: 8082
error:
path: /error
@@ -18,7 +18,12 @@ spring:
name: 打卡平台
profiles:
active: dev
+ thymeleaf:
+ cache: false
+deviceMap:
+ "16638": "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android"
+ "9119": "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"
hoperun:
address: "浙江省杭州市西湖区转塘街道凌家桥路飞天园区120"
longitueHead: "120.085"
diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml
index c7d5795..d46ac36 100644
--- a/src/main/resources/logback-spring.xml
+++ b/src/main/resources/logback-spring.xml
@@ -58,18 +58,19 @@
-
-
+
+
+
true
${logging.level}
ACCEPT
DENY
- ${logging.path}/rest.log
+ ${logging.path}/scheduler.log
${logging.size}
- ${logging.path}/rest.log.%d{yyyy-MM-dd}.%i
+ ${logging.path}/scheduler.log.%d{yyyy-MM-dd}.%i
${logging.maxHistory}
@@ -78,14 +79,6 @@
-
-
- 256
- 0
- true
-
-
-
@@ -93,37 +86,20 @@
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/static/error.html b/src/main/resources/static/error.html
new file mode 100644
index 0000000..c146e2f
--- /dev/null
+++ b/src/main/resources/static/error.html
@@ -0,0 +1,56 @@
+
+
+
+ 404 Not Found
+
+
+
+
+
+
+
+
+
+
+ 非常抱歉,您访
+
+ 问的页面不存在
+
+
返回首页
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/static/favicon.ico b/src/main/resources/static/favicon.ico
new file mode 100644
index 0000000..4f2b071
Binary files /dev/null and b/src/main/resources/static/favicon.ico differ
diff --git a/src/main/resources/static/img/ico_checkon.svg b/src/main/resources/static/img/ico_checkon.svg
index 7bcf6a7..7c1f7e0 100644
--- a/src/main/resources/static/img/ico_checkon.svg
+++ b/src/main/resources/static/img/ico_checkon.svg
@@ -1,4 +1,4 @@
-x
+