初始化
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -23,7 +23,9 @@
|
|||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
replay_pid*
|
replay_pid*
|
||||||
.iml
|
*.iml
|
||||||
|
target
|
||||||
|
logs
|
||||||
**/target
|
**/target
|
||||||
**/logs
|
**/logs
|
||||||
*.sh
|
*.sh
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.pomelotea.hoperun.sign
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.boot.SpringApplication
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @version 0.0.1
|
||||||
|
* @author jimlee
|
||||||
|
* date 2022-07-15 10:53
|
||||||
|
* 启动入口
|
||||||
|
**/
|
||||||
|
@SpringBootApplication
|
||||||
|
open class DakaApplication {
|
||||||
|
}
|
||||||
|
private val logger = LoggerFactory.getLogger("APPLICATION-STARTER")
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
SpringApplication.run(DakaApplication::class.java, *args)
|
||||||
|
logger.info("hoperun打卡服务启动成功:{}", SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(Date()))
|
||||||
|
}
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
package com.pomelotea.hoperun.sign.api
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON
|
||||||
|
import com.alibaba.fastjson.JSONArray
|
||||||
|
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<String, String?> = HashMap()
|
||||||
|
val expireMap: MutableMap<String, Long> = 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<LoginResponse?> {
|
||||||
|
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<Any?> {
|
||||||
|
val jsessionId = getJsessionIdAutoLogin(employeeNo) ?: return WebResult.getFailed("登陆失败")
|
||||||
|
return WebResult.getSuccess(monthAtt(employeeNo, jsessionId))
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/endTime")
|
||||||
|
fun endTime(@RequestBody request: DakaRequest): WebResult<Any?> {
|
||||||
|
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<Any?> {
|
||||||
|
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 getUsernameAutoLogin(employeeNo: String): String? {
|
||||||
|
val userConfig = hoperunUserConfig.userConfigMap.get(employeeNo)
|
||||||
|
if (userConfig?.username == null) {
|
||||||
|
login(employeeNo)
|
||||||
|
}
|
||||||
|
return hoperunUserConfig.userConfigMap.get(employeeNo)?.username
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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<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)
|
||||||
|
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 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(0)
|
||||||
|
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 = lastDakaInfo.getString("project_id")
|
||||||
|
}
|
||||||
|
if (userConfig.projectname == null) {
|
||||||
|
userConfig.projectname = lastDakaInfo.getString("projectname")
|
||||||
|
}
|
||||||
|
if (userConfig.project_id == null) {
|
||||||
|
userConfig.project_id = lastDakaInfo.getString("project_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<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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.pomelotea.hoperun.sign.config
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @version 0.0.1
|
||||||
|
* @author jimlee
|
||||||
|
* date 2022-07-18 09:56
|
||||||
|
* 用户配置
|
||||||
|
**/
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties("hoperun")
|
||||||
|
open class HoperunUserConfig {
|
||||||
|
val userConfigMap: MutableMap<String, UserConfig> = 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"
|
||||||
|
|
||||||
|
fun getUA(emplotyeeNo: String): String {
|
||||||
|
return address +
|
||||||
|
"$longitueHead${random(11)}," +
|
||||||
|
"$latitudeHead${random(12)};" +
|
||||||
|
"$longitueShort," +
|
||||||
|
"$latitudeShort;" +
|
||||||
|
"$qingUa;" +
|
||||||
|
(userConfigMap.get(emplotyeeNo)!!.device ?: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addUserConfig(emplotyeeNo: String, userConfig: UserConfig) {
|
||||||
|
userConfigMap.put(emplotyeeNo, userConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun random(place: Int): Long {
|
||||||
|
var random = 0L
|
||||||
|
var index = 1
|
||||||
|
var divisor = 1
|
||||||
|
while (index <= place) {
|
||||||
|
random += (Math.random() * 10).toInt() * divisor
|
||||||
|
divisor *= 10
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
return if (random < 0) -random else random
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data class UserConfig(
|
||||||
|
var username: String? = null,
|
||||||
|
var device: String? = null,
|
||||||
|
var project_id: String? = null,
|
||||||
|
var projectname: String? = null,
|
||||||
|
var projectcode: String? = null
|
||||||
|
)
|
||||||
@@ -0,0 +1,331 @@
|
|||||||
|
package com.pomelotea.hoperun.sign.error
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.pomelotea.hoperun.sign.api.WebResult
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController
|
||||||
|
import org.springframework.boot.web.servlet.error.ErrorAttributes
|
||||||
|
import org.springframework.core.Ordered
|
||||||
|
import org.springframework.core.annotation.Order
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.validation.BindException
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus
|
||||||
|
import org.springframework.web.client.HttpServerErrorException
|
||||||
|
import org.springframework.web.servlet.NoHandlerFoundException
|
||||||
|
import org.springframework.web.servlet.view.RedirectView
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
import java.text.MessageFormat
|
||||||
|
import javax.servlet.ServletOutputStream
|
||||||
|
import javax.servlet.http.HttpServletRequest
|
||||||
|
import javax.servlet.http.HttpServletResponse
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @version 0.0.1
|
||||||
|
* @author jimlee
|
||||||
|
* date 2022-07-18 10:51
|
||||||
|
* 全局异常处理器
|
||||||
|
**/
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
@ControllerAdvice
|
||||||
|
@RequestMapping("/error")
|
||||||
|
open class ExtendExceptionHandler(errorAttributes: ErrorAttributes) : AbstractErrorController(errorAttributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数断言异常
|
||||||
|
* @param request HttpServletRequest 请求
|
||||||
|
* @param response HttpServletResponse 响应
|
||||||
|
* @param ex Exception 服务异常
|
||||||
|
* @throws Exception 方法抛出异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(IllegalArgumentException::class)
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun illegalArgumentException(request: HttpServletRequest, response: HttpServletResponse, ex: Exception) {
|
||||||
|
log.error(
|
||||||
|
MessageFormat.format(
|
||||||
|
"!!! request uri:{0} from {1} assert exception:{2}",
|
||||||
|
request.requestURI,
|
||||||
|
getIpAddr(request),
|
||||||
|
ex.message
|
||||||
|
), ex
|
||||||
|
)
|
||||||
|
out(
|
||||||
|
response,
|
||||||
|
"${if (ex.message != null && ex.message!!.length > 40) ex.message!!.substring(0, 40) else ex.message}",
|
||||||
|
false,
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||||
|
ex.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空指针异常
|
||||||
|
* @param request HttpServletRequest 请求
|
||||||
|
* @param response HttpServletResponse 响应
|
||||||
|
* @param ex Exception 服务异常
|
||||||
|
* @throws Exception 方法抛出异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(NullPointerException::class)
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun nullPointerException(request: HttpServletRequest, response: HttpServletResponse, ex: Exception) {
|
||||||
|
log.error(
|
||||||
|
MessageFormat.format(
|
||||||
|
"!!! request uri:{0} from {1} null pointor exception:{2}",
|
||||||
|
request.requestURI,
|
||||||
|
getIpAddr(request),
|
||||||
|
ex.message
|
||||||
|
), ex
|
||||||
|
)
|
||||||
|
out(
|
||||||
|
response,
|
||||||
|
"服务器开小差了:${if (ex.message != null && ex.message!!.length > 40) ex.message!!.substring(0, 40) else ex.message}",
|
||||||
|
false,
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||||
|
ex.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 其他异常
|
||||||
|
* @param request HttpServletRequest 请求
|
||||||
|
* @param response HttpServletResponse 响应
|
||||||
|
* @param ex Exception 服务异常
|
||||||
|
* @throws Exception 方法抛出异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(Exception::class)
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun unknownException(request: HttpServletRequest, response: HttpServletResponse, ex: Exception) {
|
||||||
|
log.error(
|
||||||
|
MessageFormat.format(
|
||||||
|
"!!! request uri:{0} from {1} unknown exception:{2}",
|
||||||
|
request.requestURI,
|
||||||
|
getIpAddr(request),
|
||||||
|
ex.message
|
||||||
|
), ex
|
||||||
|
)
|
||||||
|
out(
|
||||||
|
response,
|
||||||
|
"服务器错误:${if (ex.message != null && ex.message!!.length > 40) ex.message!!.substring(0, 40) else ex.message}",
|
||||||
|
false,
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||||
|
ex.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 500状态异常
|
||||||
|
* @param request HttpServletRequest 请求
|
||||||
|
* @param response HttpServletResponse 响应
|
||||||
|
* @param ex Exception 服务异常
|
||||||
|
* @throws Exception 方法抛出异常
|
||||||
|
*/
|
||||||
|
@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
@ExceptionHandler(HttpServerErrorException.InternalServerError::class)
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun serverError(request: HttpServletRequest, response: HttpServletResponse, ex: Exception) {
|
||||||
|
log.error(
|
||||||
|
MessageFormat.format(
|
||||||
|
"!!! request uri:{0} from {1} server error[500] exception:{2}",
|
||||||
|
request.requestURI,
|
||||||
|
getIpAddr(request),
|
||||||
|
ex.message
|
||||||
|
), ex
|
||||||
|
)
|
||||||
|
out(
|
||||||
|
response,
|
||||||
|
"服务器内部错误:${if (ex.message != null && ex.message!!.length > 40) ex.message!!.substring(0, 40) else ex.message}",
|
||||||
|
false,
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR.value(),
|
||||||
|
ex.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 404状态异常
|
||||||
|
* @param request HttpServletRequest 请求
|
||||||
|
* @param response HttpServletResponse 响应
|
||||||
|
* @param ex Exception 服务异常
|
||||||
|
* @throws Exception 方法抛出异常
|
||||||
|
*/
|
||||||
|
@ResponseStatus(code = HttpStatus.NOT_FOUND)
|
||||||
|
@ExceptionHandler(NoHandlerFoundException::class)
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun notFound(request: HttpServletRequest, response: HttpServletResponse, ex: Exception) {
|
||||||
|
log.error(
|
||||||
|
MessageFormat.format(
|
||||||
|
"!!! request uri:{0} from {1} not found mapping url exception:{2}",
|
||||||
|
request.requestURI,
|
||||||
|
getIpAddr(request),
|
||||||
|
ex.message
|
||||||
|
), ex
|
||||||
|
)
|
||||||
|
out(
|
||||||
|
response,
|
||||||
|
"404 Not Fount:${if (ex.message != null && ex.message!!.length > 40) ex.message!!.substring(0, 40) else ex.message}",
|
||||||
|
false,
|
||||||
|
HttpStatus.NOT_FOUND.value(),
|
||||||
|
ex.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求校验缺少必要参数
|
||||||
|
* @param request HttpServletRequest 请求
|
||||||
|
* @param response HttpServletResponse 响应
|
||||||
|
* @param ex Exception 服务异常
|
||||||
|
* @throws Exception 方法抛出异常
|
||||||
|
*/
|
||||||
|
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException::class)
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun methodArgumentNotValidException(request: HttpServletRequest, response: HttpServletResponse, ex: MethodArgumentNotValidException) {
|
||||||
|
val msg = StringBuilder()
|
||||||
|
ex.bindingResult.fieldErrors.forEach {
|
||||||
|
msg.append(
|
||||||
|
"[${it.field}]:${it.defaultMessage}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
out(
|
||||||
|
response,
|
||||||
|
msg.toString(),
|
||||||
|
false,
|
||||||
|
HttpStatus.NOT_FOUND.value(),
|
||||||
|
ex.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数绑定请求实体错误
|
||||||
|
* @param request HttpServletRequest 请求
|
||||||
|
* @param response HttpServletResponse 响应
|
||||||
|
* @param ex Exception 服务异常
|
||||||
|
* @throws Exception 方法抛出异常
|
||||||
|
*/
|
||||||
|
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
|
||||||
|
@ExceptionHandler(BindException::class)
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun bindException(request: HttpServletRequest, response: HttpServletResponse, ex: BindException) {
|
||||||
|
val msg = StringBuilder()
|
||||||
|
ex.bindingResult.fieldErrors.forEach {
|
||||||
|
msg.append(
|
||||||
|
"[${it.field}]:${it.defaultMessage}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
out(
|
||||||
|
response,
|
||||||
|
msg.toString(),
|
||||||
|
false,
|
||||||
|
HttpStatus.NOT_FOUND.value(),
|
||||||
|
ex.javaClass.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping
|
||||||
|
@ResponseBody
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun handleErrors(request: HttpServletRequest, response: HttpServletResponse, e: Exception) {
|
||||||
|
val status = getStatus(request)
|
||||||
|
if (status === HttpStatus.NOT_FOUND) {
|
||||||
|
notFound(request, response, e)
|
||||||
|
} else if (status === HttpStatus.INTERNAL_SERVER_ERROR) {
|
||||||
|
serverError(request, response, e)
|
||||||
|
} else unknownException(request, response, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
@ResponseBody
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun defaultGetError(request: HttpServletRequest, response: HttpServletResponse, e: Exception) {
|
||||||
|
handleErrors(request, response, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(code = HttpStatus.NOT_FOUND)
|
||||||
|
@RequestMapping(produces = ["text/html"])
|
||||||
|
@Throws(Exception::class)
|
||||||
|
fun handleHtml(request: HttpServletRequest, response: HttpServletResponse): RedirectView {
|
||||||
|
return RedirectView("/404")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val log: Logger = LoggerFactory.getLogger(ExtendExceptionHandler::class.java)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局异常错误输出
|
||||||
|
* @param response 响应对象
|
||||||
|
* @param msg 消息
|
||||||
|
* @param success 状态
|
||||||
|
* @param code 响应码
|
||||||
|
* @param data 响应实体
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun out(response: HttpServletResponse, msg: String?, success: Boolean, code: Int?, data: Any? = null) {
|
||||||
|
val out: ServletOutputStream
|
||||||
|
try {
|
||||||
|
out = response.outputStream
|
||||||
|
response.reset()
|
||||||
|
response.characterEncoding = "UTF-8"
|
||||||
|
response.contentType = "application/json;charset=utf-8"
|
||||||
|
response.status = HttpStatus.OK.value()
|
||||||
|
out.write(ObjectMapper().writeValueAsBytes(WebResult.getWebResult(success, data, msg, code)))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.error(e.toString() + "响应错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取请求IP地址
|
||||||
|
* @param request 请求
|
||||||
|
* @return String? ip地址
|
||||||
|
*/
|
||||||
|
fun getIpAddr(request: HttpServletRequest): String? {
|
||||||
|
var ipAddress: String?
|
||||||
|
return try {
|
||||||
|
ipAddress = request.getHeader("x-forwarded-for")
|
||||||
|
if (ipAddress == null || ipAddress.length == 0 || "unknown".equals(ipAddress, ignoreCase = true)) {
|
||||||
|
ipAddress = request.getHeader("Proxy-Client-IP")
|
||||||
|
}
|
||||||
|
if (ipAddress == null || ipAddress.length == 0 || "unknown".equals(ipAddress, ignoreCase = true)) {
|
||||||
|
ipAddress = request.getHeader("WL-Proxy-Client-IP")
|
||||||
|
}
|
||||||
|
if (ipAddress == null || ipAddress.length == 0 || "unknown".equals(ipAddress, ignoreCase = true)) {
|
||||||
|
ipAddress = request.remoteAddr
|
||||||
|
// 本机访问, 获取网卡地址
|
||||||
|
if (ipAddress == "127.0.0.1" || ipAddress == "0:0:0:0:0:0:0:1") {
|
||||||
|
try {
|
||||||
|
ipAddress = InetAddress.getLocalHost().hostAddress
|
||||||
|
if (ipAddress != null) {
|
||||||
|
ipAddress += "(local)"
|
||||||
|
}
|
||||||
|
} catch (e: UnknownHostException) {
|
||||||
|
log.error("获取本机网卡IP失败", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ipAddress != null) {
|
||||||
|
if (ipAddress.contains(",")) {
|
||||||
|
ipAddress.split(",".toRegex()).toTypedArray()[0]
|
||||||
|
} else {
|
||||||
|
ipAddress
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.error("获取请求IP为空")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.error("获取用户IP失败", e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/resources/config/application-dev.yml
Normal file
10
src/main/resources/config/application-dev.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
hoperun:
|
||||||
|
address: "浙江省杭州市西湖区转塘街道凌家桥路飞天园区120"
|
||||||
|
longitueHead: "120.085"
|
||||||
|
latitudeHead: "30.138"
|
||||||
|
longitueShort: "120.0845715522375"
|
||||||
|
latitudeShort: "30.140219809955912"
|
||||||
|
qingUa: "Qing/0.9.113"
|
||||||
34
src/main/resources/config/application.yml
Normal file
34
src/main/resources/config/application.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
server:
|
||||||
|
port: 8080
|
||||||
|
error:
|
||||||
|
path: /error
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
root: debug
|
||||||
|
file:
|
||||||
|
path: ./logs
|
||||||
|
logback:
|
||||||
|
rollingpolicy:
|
||||||
|
max-file-size: 50MB
|
||||||
|
max-history: 10
|
||||||
|
|
||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: 打卡平台
|
||||||
|
profiles:
|
||||||
|
active: dev
|
||||||
|
|
||||||
|
hoperun:
|
||||||
|
address: "浙江省杭州市西湖区转塘街道凌家桥路飞天园区120"
|
||||||
|
longitueHead: "120.085"
|
||||||
|
latitudeHead: "30.138"
|
||||||
|
longitueShort: "120.0845715522375"
|
||||||
|
latitudeShort: "30.140219809955912"
|
||||||
|
qingUa: "Qing/0.9.113"
|
||||||
|
userConfigMap:
|
||||||
|
"16638":
|
||||||
|
"project_id": "U2103S000112"
|
||||||
|
"projectcode": "U2103S000112"
|
||||||
|
"projectname": "JRKF-浙江网商-技术服务外包"
|
||||||
|
"device": "Android 12;Redmi;M2007J3SC;deviceId:OAIDe7fa6084205e9a22d8f6f71bc91893ff;deviceName:Android"
|
||||||
129
src/main/resources/logback-spring.xml
Normal file
129
src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- 在spring boot应用中应该使用 logback-spring.xml 而不是logback.xml -->
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<!-- 日志根目录 -->
|
||||||
|
<springProperty scope="context" name="logging.path" source="logging.file.path"/>
|
||||||
|
<!-- 日志级别 -->
|
||||||
|
<springProperty scope="context" name="logging.level" source="logging.level.root"/>
|
||||||
|
<!-- 单日志文件大小 -->
|
||||||
|
<springProperty scope="context" name="logging.size" source="logging.logback.rollingpolicy.max-file-size"/>
|
||||||
|
<!-- 历史记录数量 -->
|
||||||
|
<springProperty scope="context" name="logging.maxHistory" source="logging.logback.rollingpolicy.max-history"/>
|
||||||
|
|
||||||
|
<!-- 控制台 -->
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} [%line] - %msg%n</Pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 错误日志文件 -->
|
||||||
|
<appender name="ERROR-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<append>true</append>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>error</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${logging.path}/common-error.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<maxFileSize>${logging.size}</maxFileSize>
|
||||||
|
<FileNamePattern>${logging.path}/common-error.log.%d{yyyy-MM-dd}.%i</FileNamePattern>
|
||||||
|
<MaxHistory>${logging.maxHistory}</MaxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} [%line] - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- 默认系统日志文件 -->
|
||||||
|
<appender name="ROOT-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<append>true</append>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>${logging.level}</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${logging.path}/common-default.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<maxFileSize>${logging.size}</maxFileSize>
|
||||||
|
<FileNamePattern>${logging.path}/common-default.log.%d{yyyy-MM-dd}.%i</FileNamePattern>
|
||||||
|
<MaxHistory>${logging.maxHistory}</MaxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} [%line] - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!-- REST接口日志文件 -->
|
||||||
|
<appender name="REST-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<append>true</append>
|
||||||
|
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||||
|
<level>${logging.level}</level>
|
||||||
|
<onMatch>ACCEPT</onMatch>
|
||||||
|
<onMismatch>DENY</onMismatch>
|
||||||
|
</filter>
|
||||||
|
<file>${logging.path}/rest.log</file>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||||
|
<maxFileSize>${logging.size}</maxFileSize>
|
||||||
|
<FileNamePattern>${logging.path}/rest.log.%d{yyyy-MM-dd}.%i</FileNamePattern>
|
||||||
|
<MaxHistory>${logging.maxHistory}</MaxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||||
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} [%line] - %msg%n</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!--==================async appender======================= -->
|
||||||
|
<appender name="ASYNC-REST-APPENDER" class="ch.qos.logback.classic.AsyncAppender">
|
||||||
|
<queueSize>256</queueSize>
|
||||||
|
<discardingThreshold>0</discardingThreshold>
|
||||||
|
<neverBlock>true</neverBlock>
|
||||||
|
<appender-ref ref="REST-APPENDER"/>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!--==================logger======================= -->
|
||||||
|
<!-- boot logger -->
|
||||||
|
<logger name="APPLICATION-STARTER" level="${logging.level}" additivity="false">
|
||||||
|
<appender-ref ref="ERROR-APPENDER"/>
|
||||||
|
<appender-ref ref="ROOT-APPENDER"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<!-- application logger -->
|
||||||
|
<logger name="com.pomelotea.hoperun.sign" level="${logging.level}" additivity="false">
|
||||||
|
<appender-ref ref="ROOT-APPENDER"/>
|
||||||
|
<appender-ref ref="ERROR-APPENDER"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<root level="${logging.level}">
|
||||||
|
<appender-ref ref="ROOT-APPENDER"/>
|
||||||
|
<appender-ref ref="ERROR-APPENDER"/>
|
||||||
|
</root>
|
||||||
|
|
||||||
|
<!-- 本地调试日志输出到控制台 -->
|
||||||
|
<springProfile name="dev">
|
||||||
|
<!-- boot logger -->
|
||||||
|
<logger name="APPLICATION-STARTER" level="debug" additivity="false">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ERROR-APPENDER"/>
|
||||||
|
<appender-ref ref="ROOT-APPENDER"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<logger name="com.pomelotea.hoperun.sign" level="debug" additivity="false">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ROOT-APPENDER"/>
|
||||||
|
<appender-ref ref="ERROR-APPENDER"/>
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<root level="debug">
|
||||||
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="ROOT-APPENDER"/>
|
||||||
|
<appender-ref ref="ERROR-APPENDER"/>
|
||||||
|
</root>
|
||||||
|
</springProfile>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
12
src/main/resources/static/coco-message.js
Normal file
12
src/main/resources/static/coco-message.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
function _typeof(f){"@babel/helpers - typeof";_typeof="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(g){return typeof g}:function(g){return g&&"function"===typeof Symbol&&g.constructor===Symbol&&g!==Symbol.prototype?"symbol":typeof g};return _typeof(f)}
|
||||||
|
!function(f,g){"object"===("undefined"===typeof exports?"undefined":_typeof(exports))&&"undefined"!==typeof module?module.exports=g():"function"===typeof define&&define.amd?define(g):(f=f||self,f.cocoMessage=g())}(void 0,function(){function f(a,b){var c=document.createElement("div");for(e in a){var d=a[e];if("className"==e){var e="class";c.setAttribute(e,d)}else"_"==e[0]&&c.addEventListener(e.slice(1),d)}if("string"==typeof b)c.innerHTML=b;else if("object"==_typeof(b)&&b.tagName)c.appendChild(b);
|
||||||
|
else if(b)for(a=0;a<b.length;a++)c.appendChild(b[a]);return c}function g(a,b){["a","webkitA"].forEach(function(c){a.addEventListener(c+"nimationEnd",function(){b()})})}function t(a,b){for(var c in b)a.style[c]=b[c];""===a.getAttribute("style")&&a.removeAttribute("style")}function v(a,b){var c=a.className||"";-1<c.indexOf(b)||(c=c.split(/\s+/),c.push(b),a.className=c.join(" "))}function n(a,b){var c={},d;for(d in u)c[d]=u[d];for(d=0;d<a.length;d++){var e=a[d];void 0!==e&&("string"==typeof e||"object"==
|
||||||
|
_typeof(e)?c.msg=e:"boolean"==typeof e?c.showClose=e:"function"==typeof e?c.onClose=e:"number"==typeof e&&(c.duration=e))}c.type=b;return w(c)}function w(a){var b=a.type,c=a.duration,d=a.msg,e=a.showClose,p=a.onClose,q=0===c;"loading"==b&&(d=""===d?"\u6b63\u5728\u52a0\u8f7d\uff0c\u8bf7\u7a0d\u540e":d,q=e,c=0);a=f({className:"coco-msg-icon"},{info:'\n <svg t="1609810636603" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3250"><path d="M469.333333 341.333333h85.333334v469.333334H469.333333z" fill="#ffffff" p-id="3251"></path><path d="M469.333333 213.333333h85.333334v85.333334H469.333333z" fill="#ffffff" p-id="3252"></path><path d="M384 341.333333h170.666667v85.333334H384z" fill="#ffffff" p-id="3253"></path><path d="M384 725.333333h256v85.333334H384z" fill="#ffffff" p-id="3254"></path></svg>\n ',
|
||||||
|
success:'\n <svg t="1609781242911" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1807"><path d="M455.42 731.04c-8.85 0-17.75-3.05-24.99-9.27L235.14 553.91c-16.06-13.81-17.89-38.03-4.09-54.09 13.81-16.06 38.03-17.89 54.09-4.09l195.29 167.86c16.06 13.81 17.89 38.03 4.09 54.09-7.58 8.83-18.31 13.36-29.1 13.36z" p-id="1808" fill="#ffffff"></path><path d="M469.89 731.04c-8.51 0-17.07-2.82-24.18-8.6-16.43-13.37-18.92-37.53-5.55-53.96L734.1 307.11c13.37-16.44 37.53-18.92 53.96-5.55 16.43 13.37 18.92 37.53 5.55 53.96L499.67 716.89c-7.58 9.31-18.64 14.15-29.78 14.15z" p-id="1809" fill="#ffffff"></path></svg>\n ',
|
||||||
|
warning:'\n <svg t="1609776406944" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18912"><path d="M468.114286 621.714286c7.314286 21.942857 21.942857 36.571429 43.885714 36.571428s36.571429-14.628571 43.885714-36.571428L585.142857 219.428571c0-43.885714-36.571429-73.142857-73.142857-73.142857-43.885714 0-73.142857 36.571429-73.142857 80.457143l29.257143 394.971429zM512 731.428571c-43.885714 0-73.142857 29.257143-73.142857 73.142858s29.257143 73.142857 73.142857 73.142857 73.142857-29.257143 73.142857-73.142857-29.257143-73.142857-73.142857-73.142858z" p-id="18913" fill="#ffffff"></path></svg>\n ',
|
||||||
|
error:'\n <svg t="1609810716933" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5514"><path d="M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z" p-id="5515" fill="#ffffff"></path></svg>\n ',loading:'\n <div class="coco-msg_loading">\n <svg class="coco-msg-circular" viewBox="25 25 50 50">\n <circle class="coco-msg-path" cx="50" cy="50" r="20" fill="none" stroke-width="4" stroke-miterlimit="10"/>\n </svg>\n </div>\n '}[b]);
|
||||||
|
d=f({className:"coco-msg-content"},d);e={className:"coco-msg-wait "+(q?"coco-msg-pointer":""),_click:function(){q&&l(k,p)}};var k=f({className:"coco-msg-wrapper"},[f({className:"coco-msg coco-msg-fade-in "+b},[a,d,f(e,q?'\n <svg class="coco-msg-close" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5514"><path d="M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z" p-id="5515"></path></svg>\n ':'<svg class="coco-msg-progress" viewBox="0 0 33.83098862 33.83098862" xmlns="http://www.w3.org/2000/svg">\n <circle class="coco-msg__background" cx="16.9" cy="16.9" r="15.9"></circle>\n <circle class="coco-msg__circle" stroke-dasharray="100,100" cx="16.9" cy="16.9" r="15.9"></circle>\n </svg>\n ')])]);
|
||||||
|
if(d=k.querySelector(".coco-msg__circle"))t(d,{animation:"coco-msg_"+b+" "+c+"ms linear"}),"onanimationend"in window?g(d,function(){l(k,p)}):setTimeout(function(){l(k,p)},c);"loading"==b&&0!==c&&setTimeout(function(){l(k,p)},c);h.children.length||document.body.appendChild(h);h.appendChild(k);t(k,{height:k.offsetHeight+"px"});setTimeout(function(){var r=k.children[0],m=r.className||"";if(-1<m.indexOf("coco-msg-fade-in")){m=m.split(/\s+/);var x=m.indexOf("coco-msg-fade-in");m.splice(x,1);r.className=
|
||||||
|
m.join(" ")}""===r.className&&r.removeAttribute("class")},300);if("loading"==b)return function(){l(k,p)}}function l(a,b){a&&(t(a,{padding:0,height:0}),v(a.children[0],"coco-msg-fade-out"),b&&b(),setTimeout(function(){if(a){for(var c=!1,d=0;d<h.children.length;d++)h.children[d]===a&&(c=!0);c&&a&&a.parentNode.removeChild(a);a=null;h.children.length||c&&h&&h.parentNode.removeChild(h)}},300))}var h=f({className:"coco-msg-stage"}),u={msg:"",duration:2E3,showClose:!1};window.addEventListener("DOMContentLoaded",
|
||||||
|
function(){var a=document;if(a&&a.head){var b=a.head;a=a.createElement("style");a.innerHTML="\n\n[class|=coco],[class|=coco]::after,[class|=coco]::before{box-sizing:border-box;outline:0}.coco-msg-progress{width:13px;height:13px}.coco-msg__circle{stroke-width:2;stroke-linecap:square;fill:none;transform:rotate(-90deg);transform-origin:center}.coco-msg-stage:hover .coco-msg__circle{-webkit-animation-play-state:paused!important;animation-play-state:paused!important}.coco-msg__background{stroke-width:2;fill:none}.coco-msg-stage{position:fixed;top:20px;left:50%;width:auto;transform:translate(-50%,0);z-index:3000}.coco-msg-wrapper{position:relative;left:50%;transform:translate(-50%,0);transform:translate3d(-50%,0,0);transition:height .3s ease,padding .3s ease;padding:6px 0;will-change:transform,opacity}.coco-msg{padding:15px 21px;border-radius:3px;position:relative;left:50%;transform:translate(-50%,0);transform:translate3d(-50%,0,0);display:flex;align-items:center}.coco-msg-content,.coco-msg-icon,.coco-msg-wait{display:inline-block}.coco-msg-icon{position:relative;width:13px;height:13px;border-radius:100%;display:flex;justify-content:center;align-items:center}.coco-msg-icon svg{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:11px;height:11px}.coco-msg-wait{width:20px;height:20px;position:relative;fill:#4eb127}.coco-msg-wait svg{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.coco-msg-close{width:14px;height:14px}.coco-msg-content{margin:0 10px;min-width:240px;text-align:left;font-size:14px;font-weight:500;font-family:-apple-system,Microsoft Yahei,sans-serif;text-shadow:0 0 1px rgba(0,0,0,.01)}.coco-msg.info{color:#0fafad;background-color:#e7fdfc;box-shadow:0 0 2px 0 rgba(0,1,1,.01),0 0 0 1px #c0faf9}.coco-msg.info .coco-msg-icon{background-color:#0fafad}.coco-msg.success{color:#4ebb23;background-color:#f3ffe8;box-shadow:0 0 2px 0 rgba(0,1,0,.01),0 0 0 1px #d9f8bb}.coco-msg.success .coco-msg-icon{background-color:#4ebb23}.coco-msg.warning{color:#f1b306;background-color:#fff9eb;box-shadow:0 0 2px 0 rgba(1,1,0,.01),0 0 0 1px #fcf2cd}.coco-msg.warning .coco-msg-icon{background-color:#f1b306}.coco-msg.error{color:#f34b51;background-color:#fff7f7;box-shadow:0 0 2px 0 rgba(1,0,0,.01),0 0 0 1px #ffe3e3}.coco-msg.error .coco-msg-icon{background-color:#f34b51}.coco-msg.loading{color:#0fafad;background-color:#e7fdfc;box-shadow:0 0 2px 0 rgba(0,1,1,.01),0 0 0 1px #c2faf9}.coco-msg_loading{flex-shrink:0;width:20px;height:20px;position:relative}.coco-msg-circular{-webkit-animation:coco-msg-rotate 2s linear infinite both;animation:coco-msg-rotate 2s linear infinite both;transform-origin:center center;height:18px!important;width:18px!important}.coco-msg-path{stroke-dasharray:1,200;stroke-dashoffset:0;stroke:#0fafad;-webkit-animation:coco-msg-dash 1.5s ease-in-out infinite;animation:coco-msg-dash 1.5s ease-in-out infinite;stroke-linecap:round}@-webkit-keyframes coco-msg-rotate{100%{transform:translate(-50%,-50%) rotate(360deg)}}@keyframes coco-msg-rotate{100%{transform:translate(-50%,-50%) rotate(360deg)}}@-webkit-keyframes coco-msg-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px}100%{stroke-dasharray:89,200;stroke-dashoffset:-124px}}@keyframes coco-msg-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px}100%{stroke-dasharray:89,200;stroke-dashoffset:-124px}}.coco-msg.info .coco-msg-wait{fill:#0fafad}.coco-msg.success .coco-msg-wait{fill:#4ebb23}.coco-msg.warning .coco-msg-wait{fill:#f1b306}.coco-msg.error .coco-msg-wait{fill:#f34b51}.coco-msg.loading .coco-msg-wait{fill:#0fafad}.coco-msg-pointer{cursor:pointer}@-webkit-keyframes coco-msg_info{0%{stroke:#0fafad}to{stroke:#0fafad;stroke-dasharray:0 100}}@keyframes coco-msg_info{0%{stroke:#0fafad}to{stroke:#0fafad;stroke-dasharray:0 100}}@-webkit-keyframes coco-msg_success{0%{stroke:#4eb127}to{stroke:#4eb127;stroke-dasharray:0 100}}@keyframes coco-msg_success{0%{stroke:#4eb127}to{stroke:#4eb127;stroke-dasharray:0 100}}@-webkit-keyframes coco-msg_warning{0%{stroke:#fcbc0b}to{stroke:#fcbc0b;stroke-dasharray:0 100}}@keyframes coco-msg_warning{0%{stroke:#fcbc0b}to{stroke:#fcbc0b;stroke-dasharray:0 100}}@-webkit-keyframes coco-msg_error{0%{stroke:#eb262d}to{stroke:#eb262d;stroke-dasharray:0 100}}@keyframes coco-msg_error{0%{stroke:#eb262d}to{stroke:#eb262d;stroke-dasharray:0 100}}.coco-msg-fade-in{-webkit-animation:coco-msg-fade .2s ease-out both;animation:coco-msg-fade .2s ease-out both}.coco-msg-fade-out{animation:coco-msg-fade .3s linear reverse both}@-webkit-keyframes coco-msg-fade{0%{opacity:0;transform:translate(-50%,0);transform:translate3d(-50%,-80%,0)}to{opacity:1;transform:translate(-50%,0);transform:translate3d(-50%,0,0)}}@keyframes coco-msg-fade{0%{opacity:0;transform:translate(-50%,0);transform:translate3d(-50%,-80%,0)}to{opacity:1;transform:translate(-50%,0);transform:translate3d(-50%,0,0)}}\n ";
|
||||||
|
b.children.length?b.insertBefore(a,b.children[0]):b.appendChild(a)}});return{info:function(){n(arguments,"info")},success:function(){n(arguments,"success")},warning:function(){n(arguments,"warning")},error:function(){n(arguments,"error")},loading:function(){return n(arguments,"loading")},destroyAll:function(){for(var a=0;a<h.children.length;a++)l(h.children[a])},config:function(a){for(var b in a)Object.hasOwnProperty.call(a,b)&&void 0!==a[b]&&(u[b]=a[b])}}});
|
||||||
15
src/main/resources/static/img/ico_checkon.svg
Normal file
15
src/main/resources/static/img/ico_checkon.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
x<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="ico_checkon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||||
|
y="0px" viewBox="0 0 42 42" style="enable-background:new 0 0 42 42;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#00A4FF;}
|
||||||
|
.st1{fill:#FFFFFF;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<polygon class="st0" points="42,42 42,0.5 0.5,42 "/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<path class="st1" d="M19.4,26.9l8.5,8.5L25,38.2l-8.5-8.5L19.4,26.9z M36.4,21.2l2.8,2.8L25.1,38.2l-2.8-2.8L36.4,21.2z"/>
|
||||||
|
</svg>
|
||||||
BIN
src/main/resources/static/img/tx.png
Normal file
BIN
src/main/resources/static/img/tx.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
112
src/main/resources/static/index.0.html
Normal file
112
src/main/resources/static/index.0.html
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<!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><!--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><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="login_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>
|
||||||
1
src/main/resources/static/index.html
Normal file
1
src/main/resources/static/index.html
Normal file
@@ -0,0 +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><!--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><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="login_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>
|
||||||
6
src/main/resources/static/jquery.min.js
vendored
Normal file
6
src/main/resources/static/jquery.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
190
src/main/resources/static/normalize.min.css
vendored
Normal file
190
src/main/resources/static/normalize.min.css
vendored
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
button,hr,input {
|
||||||
|
overflow: visible
|
||||||
|
}
|
||||||
|
|
||||||
|
audio,canvas,progress,video {
|
||||||
|
display: inline-block
|
||||||
|
}
|
||||||
|
|
||||||
|
progress,sub,sup {
|
||||||
|
vertical-align: baseline
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
menu,article,aside,details,footer,header,nav,section {
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: .67em 0
|
||||||
|
}
|
||||||
|
|
||||||
|
figcaption,figure,main {
|
||||||
|
display: block
|
||||||
|
}
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 40px
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box;
|
||||||
|
height: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
code,kbd,pre,samp {
|
||||||
|
font-family: monospace,monospace;
|
||||||
|
font-size: 1em
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
-webkit-text-decoration-skip: objects
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active,a:hover {
|
||||||
|
outline-width: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration: underline dotted
|
||||||
|
}
|
||||||
|
|
||||||
|
b,strong {
|
||||||
|
font-weight: bolder
|
||||||
|
}
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: #ff0;
|
||||||
|
color: #000
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%
|
||||||
|
}
|
||||||
|
|
||||||
|
sub,sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -.25em
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -.5em
|
||||||
|
}
|
||||||
|
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none
|
||||||
|
}
|
||||||
|
|
||||||
|
svg:not(:root) {
|
||||||
|
overflow: hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
button,input,optgroup,select,textarea {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 100%;
|
||||||
|
line-height: 1.15;
|
||||||
|
margin: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
button,input {
|
||||||
|
}
|
||||||
|
|
||||||
|
button,select {
|
||||||
|
text-transform: none
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=submit], [type=reset],button,html [type=button] {
|
||||||
|
-webkit-appearance: button
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring {
|
||||||
|
outline: ButtonText dotted 1px
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
border: 1px solid silver;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: .35em .625em .75em
|
||||||
|
}
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: inherit;
|
||||||
|
display: table;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
white-space: normal
|
||||||
|
}
|
||||||
|
|
||||||
|
progress {
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=checkbox],[type=radio] {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button {
|
||||||
|
height: auto
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=search] {
|
||||||
|
-webkit-appearance: textfield;
|
||||||
|
outline-offset: -2px
|
||||||
|
}
|
||||||
|
|
||||||
|
[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
font: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item
|
||||||
|
}
|
||||||
|
|
||||||
|
[hidden],template {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
/*# sourceMappingURL=normalize.min.css.map */
|
||||||
310
src/main/resources/static/script.js
Normal file
310
src/main/resources/static/script.js
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
const toggleButton = document.querySelector(".dark-light");
|
||||||
|
|
||||||
|
toggleButton.addEventListener("click", () => {
|
||||||
|
document.body.classList.toggle("dark-mode");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.localStorage.getItem("employeeNo") != null && window.localStorage.getItem("employeeNo") !== '') {
|
||||||
|
loginAndLoadRecord()
|
||||||
|
} else {
|
||||||
|
cocoMessage.info(2000, "请先登录!");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('#logout').addEventListener("click", () => {
|
||||||
|
window.localStorage.removeItem("employeeNo");
|
||||||
|
window.localStorage.removeItem("username");
|
||||||
|
$('.job-cards').text("");
|
||||||
|
$('#employee-number').val("");
|
||||||
|
$('#username').text("未登陆");
|
||||||
|
$("#logout-div").hide();
|
||||||
|
$("#login-span").show();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
let employeeNumberInput = document.querySelector('#employee-number');
|
||||||
|
if ($('#login-span').css('display') !== 'none') {
|
||||||
|
employeeNumberInput.focus()
|
||||||
|
}
|
||||||
|
employeeNumberInput.addEventListener("keypress", (e) => {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
window.localStorage.setItem("employeeNo", employeeNumberInput.value);
|
||||||
|
loginAndLoadRecord();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
document.querySelector('#login').addEventListener("click", () => {
|
||||||
|
window.localStorage.setItem("employeeNo", employeeNumberInput.value);
|
||||||
|
loginAndLoadRecord();
|
||||||
|
})
|
||||||
|
|
||||||
|
function loginAndLoadRecord() {
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
method: "get",
|
||||||
|
url: "/api/daka/username/" + window.localStorage.getItem("employeeNo"),
|
||||||
|
success: function (result) {
|
||||||
|
if (result.success) {
|
||||||
|
$("#login-span").css("display", "none");
|
||||||
|
$('#username').text(result.data.username);
|
||||||
|
window.localStorage.setItem("username", result.data.username);
|
||||||
|
$("#logout-div").css("display", "block");
|
||||||
|
|
||||||
|
// 登录信息
|
||||||
|
$('#_user_input').val(result.data.username)
|
||||||
|
$('#_project_id_input').val(result.data.project_id)
|
||||||
|
$('#_project_name_input').val(result.data.projectname)
|
||||||
|
$('#_area_input').val(result.data.area)
|
||||||
|
$('#_device_input').val(result.data.device)
|
||||||
|
let loginDialog = $('.login_dialog')
|
||||||
|
loginDialog.show();
|
||||||
|
setTimeout(
|
||||||
|
() => {
|
||||||
|
loginDialog.hide();
|
||||||
|
}, 3000
|
||||||
|
)
|
||||||
|
$('#user-head').off('click').on("click", () => {
|
||||||
|
if (loginDialog.css("display") === 'block') {
|
||||||
|
$('.login_dialog').hide()
|
||||||
|
} else {
|
||||||
|
$('.login_dialog').show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
loadDakaList();
|
||||||
|
} else {
|
||||||
|
window.localStorage.setItem("employeeNo", '');
|
||||||
|
cocoMessage.error("登陆失败!" + result.message, 3000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
cocoMessage.error("请求失败!", 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let dateBeginTimeMap = {};
|
||||||
|
let dateEndTimeMap = {};
|
||||||
|
|
||||||
|
function loadDakaList() {
|
||||||
|
let closeLoading = cocoMessage.loading(true);
|
||||||
|
$.ajax({
|
||||||
|
method: "get",
|
||||||
|
url: "/api/daka/last/" + window.localStorage.getItem("employeeNo"),
|
||||||
|
success: function (result) {
|
||||||
|
if (result.success) {
|
||||||
|
let data = result.data;
|
||||||
|
let date = new Date();
|
||||||
|
let nowDate = date.getFullYear() + '-' + ((date.getMonth() + 1) < 10 ? '0' + date.getMonth() + 1 : date.getMonth() + 1) + '-' + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
|
||||||
|
let index = 0;
|
||||||
|
for (var signlog of data) {
|
||||||
|
dateBeginTimeMap[signlog.yearmonth] = (signlog.begin_time == null ? "未打卡" : signlog.begin_time.substr(11, 5));
|
||||||
|
dateEndTimeMap[signlog.yearmonth] = (signlog.end_time == null ? "未打卡" : signlog.end_time.substr(11, 5));
|
||||||
|
index++;
|
||||||
|
$('.job-cards').append('<div class="job-card">' +
|
||||||
|
'<div class="job-card-title">' + (nowDate === signlog.yearmonth ? "今天" : signlog.yearmonth) + '</div>' +
|
||||||
|
'<div class="job-card-subtitle">' +
|
||||||
|
signlog.area_id +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="job-detail-buttons">' +
|
||||||
|
'<button class="search-buttons detail-button">' + (signlog.begin_time == null ? "未打卡" : signlog.begin_time.substr(11, 5)) + '</button>' +
|
||||||
|
'<button class="search-buttons detail-button">' + (signlog.end_time == null ? "未打卡" : signlog.end_time.substr(11, 5)) + '</button>' +
|
||||||
|
(signlog.end_time != null && signlog.end_time.substr(11, 5) > "20:30" ? '<button class="search-buttons detail-button">餐补</button>' : '') +
|
||||||
|
'</div>' +
|
||||||
|
(index <= 3 ? '<div class="job-card-buttons">' +
|
||||||
|
'<button class="search-buttons card-buttons daka-buttons"' +
|
||||||
|
'">打卡</button>' +
|
||||||
|
'<button class="search-buttons card-buttons auto-daka-buttons">自动补卡</button>' +
|
||||||
|
'</div>' : '') +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bindDakaClick();
|
||||||
|
bindAutoDakaClick();
|
||||||
|
bindRandomBeginTime();
|
||||||
|
bindRandomEndTime();
|
||||||
|
bindSaveDakaTime();
|
||||||
|
} else {
|
||||||
|
cocoMessage.error("加载打卡记录失败!" + result.message, 3000);
|
||||||
|
}
|
||||||
|
closeLoading()
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
cocoMessage.error("请求失败!", 3000);
|
||||||
|
closeLoading()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindDakaClick() {
|
||||||
|
document.querySelectorAll(".daka-buttons").forEach((dakaButton) => {
|
||||||
|
$(dakaButton).off('click').on('click', function (e) {
|
||||||
|
let dialogDom = $('.dialog');
|
||||||
|
dialogDom.css("left", e.clientX)
|
||||||
|
dialogDom.css("top", e.clientY)
|
||||||
|
let titleDate = e.target.parentElement.parentElement.children[0];
|
||||||
|
let times = e.target.parentElement.parentElement.children[2].children;
|
||||||
|
let beginTime = times[0].outerText
|
||||||
|
let date = new Date()
|
||||||
|
let nowTime = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':' + (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes())
|
||||||
|
if (beginTime === '未打卡' && nowTime < '09:30') {
|
||||||
|
beginTime = nowTime
|
||||||
|
}
|
||||||
|
let endTime = times[1].outerText
|
||||||
|
if (endTime === '未打卡' && nowTime > '18:00') {
|
||||||
|
endTime = nowTime
|
||||||
|
}
|
||||||
|
$('#sign-date > span').text(titleDate.outerText);
|
||||||
|
$('#sign-begin-time').val(beginTime);
|
||||||
|
$('#sign-end-time').val(endTime);
|
||||||
|
dialogDom.show();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindAutoDakaClick() {
|
||||||
|
document.querySelectorAll(".auto-daka-buttons").forEach((autoDakaButton) => {
|
||||||
|
$(autoDakaButton).off('click').on('click', function (e) {
|
||||||
|
let titleDate = e.target.parentElement.parentElement.children[0].outerText;
|
||||||
|
let times = e.target.parentElement.parentElement.children[2].children;
|
||||||
|
let beginTime = times[0].outerText;
|
||||||
|
let endTime = times[1].outerText;
|
||||||
|
if (beginTime > "09:30") {
|
||||||
|
beginTime = randomBeginTime();
|
||||||
|
}
|
||||||
|
if (endTime === "未打卡" || endTime < '20:30') {
|
||||||
|
endTime = randomEndTime();
|
||||||
|
}
|
||||||
|
saveDakaTime(titleDate, beginTime, endTime);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindRandomBeginTime() {
|
||||||
|
$('#sign-begin-random').off('click').on("click", () => {
|
||||||
|
$('#sign-begin-time').val(randomBeginTime());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindRandomEndTime() {
|
||||||
|
|
||||||
|
$('#sign-end-random').off('click').on("click", () => {
|
||||||
|
$('#sign-end-time').val(randomEndTime());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindSaveDakaTime() {
|
||||||
|
$('#save-sign').off('click').on("click", () => {
|
||||||
|
let signDate = $('#sign-date > span').text();
|
||||||
|
let beginTime = $('#sign-begin-time').val();
|
||||||
|
let endTime = $('#sign-end-time').val();
|
||||||
|
saveDakaTime(signDate, beginTime, endTime);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDakaTime(signDate, beginTime, endTime) {
|
||||||
|
let messageType = 0;
|
||||||
|
let beginTimeMessage = dateBeginTimeMap[signDate] !== beginTime;
|
||||||
|
let endTimeMessage = endTime !== '' && dateEndTimeMap[signDate] !== endTime;
|
||||||
|
if (beginTimeMessage && endTimeMessage) {
|
||||||
|
messageType = 1;
|
||||||
|
} else if (beginTimeMessage && !endTimeMessage) {
|
||||||
|
messageType = 2;
|
||||||
|
} else if (!beginTimeMessage && endTimeMessage) {
|
||||||
|
messageType = 3;
|
||||||
|
} else {
|
||||||
|
messageType = 4;
|
||||||
|
}
|
||||||
|
if (dateBeginTimeMap[signDate] !== beginTime) {
|
||||||
|
$.ajax({
|
||||||
|
method: "post",
|
||||||
|
url: "/api/daka/beginTime",
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
dataType: 'json',
|
||||||
|
data: JSON.stringify({
|
||||||
|
'employeeNo': window.localStorage.getItem("employeeNo"),
|
||||||
|
'date': signDate,
|
||||||
|
'time': beginTime
|
||||||
|
}),
|
||||||
|
success: function (result) {
|
||||||
|
if (!result.success) {
|
||||||
|
success = false;
|
||||||
|
cocoMessage.error("打上班卡失败!" + result.message, 3000);
|
||||||
|
} else {
|
||||||
|
if (messageType === 2) {
|
||||||
|
setTimeout(function () {
|
||||||
|
$('.dialog').hide();
|
||||||
|
$('.job-cards').html('');
|
||||||
|
loadDakaList();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
cocoMessage.error("请求失败!", 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (endTime !== '' && dateEndTimeMap[signDate] !== endTime) {
|
||||||
|
$.ajax({
|
||||||
|
method: "post",
|
||||||
|
url: "/api/daka/endTime",
|
||||||
|
contentType: "application/json; charset=utf-8",
|
||||||
|
dataType: 'json',
|
||||||
|
data: JSON.stringify({
|
||||||
|
'employeeNo': window.localStorage.getItem("employeeNo"),
|
||||||
|
'date': signDate,
|
||||||
|
'time': endTime
|
||||||
|
}),
|
||||||
|
success: function (result) {
|
||||||
|
if (!result.success) {
|
||||||
|
success = false;
|
||||||
|
cocoMessage.error("打下班卡失败!" + result.message, 3000);
|
||||||
|
} else {
|
||||||
|
if (messageType === 1 || messageType === 3) {
|
||||||
|
setTimeout(function () {
|
||||||
|
$('.dialog').hide();
|
||||||
|
$('.job-cards').html('');
|
||||||
|
loadDakaList();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (e) {
|
||||||
|
cocoMessage.error("请求失败!", 3000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (messageType === 4) {
|
||||||
|
cocoMessage.info(1000, "没有变更");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomBeginTime() {
|
||||||
|
let randomMinutes = Math.round(Math.random() * 30);
|
||||||
|
return "09:" + (randomMinutes < 10 ? "0" + randomMinutes : randomMinutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomEndTime() {
|
||||||
|
let hourArray = [20, 21, 22, 23, 20, 21, 22, 20, 20, 21];
|
||||||
|
let randomHour = hourArray[Math.round(Math.random() * 9)];
|
||||||
|
let randomMinute = 0;
|
||||||
|
if (randomHour === 20) {
|
||||||
|
randomMinute = Math.round(Math.random() * 30) + 29;
|
||||||
|
} else {
|
||||||
|
randomMinute = Math.round(Math.random() * 59);
|
||||||
|
if (randomMinute < 10) {
|
||||||
|
randomMinute = '0' + randomMinute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return randomHour + ":" + randomMinute;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).click(function(e) {
|
||||||
|
var $target = $(e.target);
|
||||||
|
//点击表情选择按钮和表情选择框以外的地方 隐藏表情选择框
|
||||||
|
if (!$target.is('.dialog *') && !$target.is('.daka-buttons')) {
|
||||||
|
$('.dialog').hide();
|
||||||
|
}
|
||||||
|
if (!$target.is('.login_dialog *') && !$target.is('#user-head')) {
|
||||||
|
$('.login_dialog').hide();
|
||||||
|
}
|
||||||
|
})
|
||||||
1116
src/main/resources/static/style.css
Normal file
1116
src/main/resources/static/style.css
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user