提交 85717af6 编写于 作者: F fancy

新版考勤 打卡功能

上级 808a7fb0
package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.main
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenter
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseView
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.attendance.*
object AttendanceCheckInV2Contract {
interface View : BaseView {
fun preCheckData(data: AttendanceV2PreCheckData?)
fun checkInPostResponse(result: Boolean)
}
interface Presenter : BasePresenter<View> {
fun preCheckDataLoad()
fun checkInPost(body: AttendanceV2CheckInBody)
}
}
package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.main
import android.graphics.drawable.GradientDrawable
import android.os.Handler
import android.os.Message
import android.text.TextUtils
import android.widget.EditText
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation
import com.baidu.location.LocationClient
import com.baidu.location.LocationClientOption
import com.baidu.mapapi.model.LatLng
import com.baidu.mapapi.utils.DistanceUtil
import kotlinx.android.synthetic.main.fragment_attendance_check_in_new.*
import kotlinx.android.synthetic.main.fragment_attendance_check_in_v2.*
import kotlinx.android.synthetic.main.fragment_attendance_check_in_v2.image_attendance_check_in_new_location_check_icon
import kotlinx.android.synthetic.main.fragment_attendance_check_in_v2.rl_attendance_check_in_new_knock_btn
import kotlinx.android.synthetic.main.fragment_attendance_check_in_v2.rv_attendance_check_in_new_schedules
import kotlinx.android.synthetic.main.fragment_attendance_check_in_v2.tv_attendance_check_in_new_check_in
import kotlinx.android.synthetic.main.fragment_attendance_check_in_v2.tv_attendance_check_in_new_now_time
import kotlinx.android.synthetic.main.fragment_attendance_check_in_v2.tv_attendance_check_in_new_workplace
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPViewPagerFragment
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecycleViewAdapter
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecyclerViewHolder
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.attendance.*
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.im.MessageType
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.CheckButtonDoubleClick
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.DateHelper
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XToast
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.gone
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.visible
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.GridLayoutItemDecoration
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.dialog.O2DialogSupport
import org.jetbrains.anko.dip
import java.util.*
import kotlin.collections.ArrayList
/**
* Created by fancyLou on 2020-07-17.
* Copyright © 2020 O2. All rights reserved.
*/
class AttendanceCheckInV2NewFragment : BaseMVPViewPagerFragment<AttendanceCheckInV2Contract.View, AttendanceCheckInV2Contract.Presenter>(),
AttendanceCheckInV2Contract.View {
override var mPresenter: AttendanceCheckInV2Contract.Presenter = AttendanceCheckInV2Presenter()
override fun layoutResId(): Int = R.layout.fragment_attendance_check_in_v2
private val workplaceList = ArrayList<AttendanceV2WorkPlace>()
private val recordList = ArrayList<AttendanceV2CheckItemData>()
private var lastRecord: AttendanceV2CheckItemData? = null
private var needCheckIn = false //是否可打卡
private var allowFieldWork = false // 是否允许外勤
private var requiredFieldWorkRemarks = false // 外勤是否必须打卡
private val recordAdapter: CommonRecycleViewAdapter<AttendanceV2CheckItemData> by lazy {
object : CommonRecycleViewAdapter<AttendanceV2CheckItemData>(activity, recordList, R.layout.item_attendance_check_in_schdule_list) {
override fun convert(holder: CommonRecyclerViewHolder?, t: AttendanceV2CheckItemData?) {
if (holder != null && t != null) {
val status = if(t.isRecord) {
t.recordTime
} else {
"未打卡"
}
holder.setText(R.id.tv_item_attendance_check_in_schedule_list_type, t.checkInTypeString)
.setText(R.id.tv_item_attendance_check_in_schedule_list_time, t.preDutyTime)
.setText(R.id.tv_item_attendance_check_in_schedule_list_status, status)
val updateBtn = holder.getView<TextView>(R.id.tv_item_attendance_check_in_schedule_list_update_btn)
updateBtn.gone()
if (t.isLastRecord) {
updateBtn.visible()
}
}
}
}
}
//定位
private val mLocationClient: LocationClient by lazy { LocationClient(activity) }
private var myLocation: BDLocation? = null //当前我的位置
private var checkInPosition: AttendanceV2WorkPlace? = null//离的最近的工作地点位置
private var isInCheckInPositionRange = false
//刷新打卡按钮的时间
private val handler = Handler { msg ->
if (msg.what == 1) {
val nowTime = DateHelper.nowByFormate("HH:mm:ss")
tv_attendance_check_in_new_now_time?.text = nowTime
}
return@Handler true
}
private val timerTask = object : TimerTask() {
override fun run() {
val message = Message()
message.what = 1
handler.sendMessage(message)
}
}
private val timer: Timer by lazy { Timer() }
override fun lazyLoad() {
mPresenter.preCheckDataLoad()
}
override fun initUI() {
LocationClient.setAgreePrivacy(true)
//定位
mLocationClient.registerLocationListener(object : BDAbstractLocationListener() {
override fun onReceiveLocation(location: BDLocation?) {
XLog.debug("onReceive locType:${location?.locType}, latitude:${location?.latitude}, longitude:${location?.longitude}")
if (location != null) {
myLocation = location
//计算
calNearestWorkplace()
}
}
})
initBaiduLocation()
mLocationClient.start()
//打卡班次
rv_attendance_check_in_new_schedules.layoutManager = GridLayoutManager(activity, 2)
rv_attendance_check_in_new_schedules.addItemDecoration(GridLayoutItemDecoration(activity?.dip(10) ?: 10, activity?.dip(10) ?: 10, 2))
rv_attendance_check_in_new_schedules.adapter = recordAdapter
recordAdapter.setOnItemClickListener { _, position ->
// 点击更新打卡
clickUpdateRecord(recordList[position])
}
//打卡按钮
rl_attendance_check_in_new_knock_btn.setOnClickListener {
if (CheckButtonDoubleClick.isFastDoubleClick(R.id.rl_attendance_check_in_new_knock_btn)) {
return@setOnClickListener
}
// 打卡
clickCheckIn()
}
//时间
timer.schedule(timerTask, 0, 1000)
}
private fun setCheckInBtnEnable(enable: Boolean) {
needCheckIn = enable
val draw = rl_attendance_check_in_new_knock_btn.background as? GradientDrawable
if (enable) {
activity?.let {
draw?.setColor(ContextCompat.getColor(it, R.color.z_color_primary))
}
} else {
activity?.let {
draw?.setColor(ContextCompat.getColor(it, R.color.disabled))
}
}
}
override fun onDestroyView() {
timer.cancel()
timerTask.cancel()
super.onDestroyView()
}
override fun onDestroy() {
// 退出时销毁定位
mLocationClient.stop()
super.onDestroy()
}
override fun preCheckData(data: AttendanceV2PreCheckData?) {
if (data == null) {
setCheckInBtnEnable(false)
return
}
XLog.debug("$data")
needCheckIn = data.canCheckIn //今天是否还需要打卡
allowFieldWork = data.allowFieldWork
requiredFieldWorkRemarks = data.requiredFieldWorkRemarks
workplaceList.clear()
workplaceList.addAll(data.workPlaceList ?: ArrayList())
// 检查是否在范围内
calNearestWorkplace()
if (needCheckIn) {
// 打卡记录
val checkItemList = data.checkItemList ?: ArrayList()
// 是否最后一条已经打卡过的数据
lastRecord = checkItemList.firstOrNull { element -> element.checkInResult == "PreCheckIn" }
needCheckIn = lastRecord != null
for ((index, item) in checkItemList.withIndex()) {
var isRecord = false
var recordTime = ""
if (item.checkInResult != "PreCheckIn") {
isRecord = true
var signTime = item.recordDate
if (signTime.length > 16) {
signTime = signTime.substring(11, 16);
}
recordTime = "已打卡 $signTime" // lpFormat(lp, 'mobile.checkInWithTime', {time: signTime});
}
item.recordTime = recordTime
item.isRecord = isRecord // 是否已经打卡
item.checkInTypeString = if(item.checkInType == "OnDuty") { "上班打卡" }else{ "下班打卡"}
var preDutyTime = item.preDutyTime
if (TextUtils.isEmpty(item.shiftId)) {
preDutyTime = "" // 如果没有班次信息 表示 自由工时 或者 休息日 不显示 打卡时间
}
item.preDutyTime = preDutyTime
// 处理是否是最后一个已经打卡的记录
if (item.checkInResult != "PreCheckIn") {
if (index == checkItemList.size - 1) { // 最后一条
item.isLastRecord = true // 最后一条已经打卡的记录
} else {
val nextItem = checkItemList[index+1]
if (nextItem.checkInResult == "PreCheckIn") {
item.isLastRecord = true
}
}
}
checkItemList[index] = item
}
recordList.clear()
recordList.addAll(checkItemList)
}
// 刷新页面
setCheckInBtnEnable(needCheckIn)
recordAdapter.notifyDataSetChanged()
}
override fun checkInPostResponse(result: Boolean) {
tv_attendance_check_in_new_check_in?.setText(R.string.attendance_check_in_knock)
tv_attendance_check_in_new_now_time?.visible()
if (result) {
XToast.toastShort(activity, "打卡成功!")
} else {
XToast.toastShort(activity, "打卡失败!")
}
mPresenter.preCheckDataLoad()
}
/**
* 点击更新打卡
*/
private fun clickUpdateRecord(record: AttendanceV2CheckItemData) {
if (myLocation == null || TextUtils.isEmpty(myLocation?.addrStr)) {
XLog.error("没有定位到信息,可能是定位权限没开!!!")
XToast.toastShort(activity!!, R.string.attendance_message_no_location_info)
return
}
if (record.isLastRecord) { // 只有最后一条可以更新
tv_attendance_check_in_new_check_in.text = getString(R.string.attendance_check_in_knock_loading)
tv_attendance_check_in_new_now_time.gone()
if (isInCheckInPositionRange && checkInPosition != null) { // 正常打卡
postCheckIn(record, checkInPosition!!.id, false, null)
} else {
// 外勤
outSide(record)
}
} else {
XLog.info("不是最后一条,不能更新打卡,怎么点击到的???")
}
}
/**
* 点击打卡
*/
private fun clickCheckIn() {
if (myLocation == null || TextUtils.isEmpty(myLocation?.addrStr)) {
XLog.error("没有定位到信息,可能是定位权限没开!!!")
XToast.toastShort(activity!!, R.string.attendance_message_no_location_info)
return
}
if (needCheckIn && lastRecord != null) {
tv_attendance_check_in_new_check_in.text = getString(R.string.attendance_check_in_knock_loading)
tv_attendance_check_in_new_now_time.gone()
if (isInCheckInPositionRange && checkInPosition != null) { // 正常打卡
postCheckIn(lastRecord!!, checkInPosition!!.id, false, null)
} else {
// 外勤
outSide(lastRecord!!)
}
} else {
XLog.info("不允许打卡或lastRecord is null")
}
}
/**
* 外勤打卡处理
*/
private fun outSide(record: AttendanceV2CheckItemData) {
if (allowFieldWork) {
if (requiredFieldWorkRemarks) {
if (activity != null) {
val dialog = O2DialogSupport.openCustomViewDialog(
activity!!,
getString(R.string.attendance_message_work_out),
R.layout.dialog_name_modify
) { dialog ->
val text = dialog.findViewById<EditText>(R.id.dialog_name_editText_id)
if (TextUtils.isEmpty(text.text.toString())) {
XToast.toastShort(activity!!, R.string.attendance_message_work_out_hint)
} else {
postCheckIn(record, null, true, text.text.toString())
}
}
val text = dialog.findViewById<EditText>(R.id.dialog_name_editText_id)
text.hint = getString(R.string.attendance_message_work_out_hint)
}
} else {
postCheckIn(record, null, true, null)
}
} else {
XToast.toastShort(activity, "不在工作地点的打卡范围内!")
}
}
/**
* 提交打卡信息
*/
private fun postCheckIn(record: AttendanceV2CheckItemData, workPlaceId: String?, outSide: Boolean, outSideDesc:String?) {
val body = AttendanceV2CheckInBody()
body.recordId = record.id
body.checkInType = record.checkInType
body.latitude = myLocation!!.latitude.toString()
body.longitude = myLocation!!.longitude.toString()
body.recordAddress = myLocation!!.addrStr
body.workPlaceId = workPlaceId ?: ""
body.fieldWork = outSide
body.signDescription = outSideDesc ?: ""
XLog.debug(body.toString())
mPresenter.checkInPost(body)
}
/**
* 检查是否进入打卡范围
*/
private fun checkIsInWorkplace() {
XLog.info("checkIsInWorkplace.....${checkInPosition?.placeName}, ${myLocation?.addrStr}")
if (checkInPosition != null && myLocation != null) {
val workplacePosition = LatLng(checkInPosition!!.latitude.toDouble(), checkInPosition!!.longitude.toDouble())
val position = LatLng(myLocation!!.latitude, myLocation!!.longitude)
val distance = DistanceUtil.getDistance(position, workplacePosition)
XLog.info("distance:$distance")
if (distance < checkInPosition!!.errorRange) {
isInCheckInPositionRange = true
activity?.runOnUiThread {
tv_attendance_check_in_new_workplace.text = checkInPosition?.placeName
image_attendance_check_in_new_location_check_icon.setImageResource(R.mipmap.list_selected)
}
} else {
isInCheckInPositionRange = false
activity?.runOnUiThread {
tv_attendance_check_in_new_workplace.text = myLocation?.addrStr
image_attendance_check_in_new_location_check_icon.setImageResource(R.mipmap.icon_delete_people)
}
}
}
}
/**
* 找到最近的打卡地点
*/
private fun calNearestWorkplace() {
if ( myLocation!=null) {
if (workplaceList.isNotEmpty()) {
var minDistance: Double = -1.0
XLog.debug("calNearestWorkplace...................")
workplaceList.map {
val p2 = LatLng(it.latitude.toDouble(), it.longitude.toDouble())
val position = LatLng(myLocation!!.latitude, myLocation!!.longitude)
val distance = DistanceUtil.getDistance(position, p2)
if (minDistance == -1.0) {
minDistance = distance
checkInPosition = it
} else {
if (minDistance > distance) {
minDistance = distance
checkInPosition = it
}
}
}
XLog.info("checkInposition:${checkInPosition?.placeName}")
checkIsInWorkplace()
} else {
activity?.runOnUiThread {
tv_attendance_check_in_new_workplace.text = myLocation?.addrStr
}
}
}
}
private fun initBaiduLocation() {
val option = LocationClientOption()
option.locationMode = LocationClientOption.LocationMode.Hight_Accuracy//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
option.setCoorType("bd09ll")//百度坐标系 可选,默认gcj02,设置返回的定位结果坐标系
option.setScanSpan(5000)//5秒一次定位 可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的
option.setIsNeedAddress(true)//可选,设置是否需要地址信息,默认不需要
option.isOpenGps = true//可选,默认false,设置是否使用gps
option.isLocationNotify = true//可选,默认false,设置是否当GPS有效时按照1S/1次频率输出GPS结果
option.setIsNeedLocationDescribe(true)//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近”
option.setIsNeedLocationPoiList(true)//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到
option.setIgnoreKillProcess(false)//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死
option.SetIgnoreCacheException(false)//可选,默认false,设置是否收集CRASH信息,默认收集
option.setEnableSimulateGps(false)//可选,默认false,设置是否需要过滤GPS仿真结果,默认需要
mLocationClient.locOption = option
}
}
\ No newline at end of file
package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.main
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.attendance.AttendanceV2CheckInBody
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
class AttendanceCheckInV2Presenter : BasePresenterImpl<AttendanceCheckInV2Contract.View>(), AttendanceCheckInV2Contract.Presenter {
override fun preCheckDataLoad() {
val service = getAttendanceAssembleControlService(mView?.getContext())
if (service != null) {
service.attendanceV2PreCheck()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.o2Subscribe {
onNext {
mView?.preCheckData(it?.data)
}
onError { e, _ ->
XLog.error("", e)
mView?.preCheckData(null)
}
}
} else {
mView?.preCheckData(null)
}
}
override fun checkInPost(body: AttendanceV2CheckInBody) {
val service = getAttendanceAssembleControlService(mView?.getContext())
if (service != null) {
service.attendanceV2CheckIn(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.o2Subscribe {
onNext {
if (it != null && it.data != null ) {
mView?.checkInPostResponse(true)
} else {
mView?.checkInPostResponse(false)
}
}
onError { e, _ ->
XLog.error("", e)
mView?.checkInPostResponse(false)
}
}
} else {
mView?.checkInPostResponse(false)
}
}
}
......@@ -33,17 +33,18 @@ class AttendanceMainActivity : BaseMVPActivity<AttendanceMainContract.View, Atte
var locationEnable: Boolean = false
private var isAttendanceAdmin: Boolean = false
private var attendanceVersion: String = "1"
private lateinit var fragmentList: ArrayList<Fragment>
private val titleList: ArrayList<String> by lazy { arrayListOf<String>(getString(R.string.attendance_check_in_title), getString(R.string.title_activity_attendance_chart)) }
override fun afterSetContentView(savedInstanceState: Bundle?) {
setupToolBar(getString(R.string.attendance_check_in_title), setupBackButton = true, isCloseBackIcon = true)
val attendanceVersion = O2SDKManager.instance().prefs().getString(O2.PRE_ATTENDANCE_VERSION_KEY, "0")
attendanceVersion = O2SDKManager.instance().prefs().getString(O2.PRE_ATTENDANCE_VERSION_KEY, "1") ?: "1"
fragmentList = if (attendanceVersion == "1") {
arrayListOf<Fragment>(AttendanceCheckInNewFragment(), AttendanceStatisticFragment())
}else {
arrayListOf<Fragment>(AttendanceCheckInFragment(), AttendanceStatisticFragment())
arrayListOf<Fragment>(AttendanceCheckInV2NewFragment(), AttendanceStatisticV2Fragment())
}
view_pager_attendance_main_content.adapter = CommonFragmentPagerAdapter(supportFragmentManager, fragmentList, titleList)
view_pager_attendance_main_content.addOnPageChangeListener {
......@@ -80,11 +81,12 @@ class AttendanceMainActivity : BaseMVPActivity<AttendanceMainContract.View, Atte
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
menu?.clear()
if (isAttendanceAdmin) {
menuInflater.inflate(R.menu.menu_attendance_main_admin, menu)
}
else {
menuInflater.inflate(R.menu.menu_attendance_main_normal, menu)
if (attendanceVersion == "1") {
if (isAttendanceAdmin) {
menuInflater.inflate(R.menu.menu_attendance_main_admin, menu)
} else {
menuInflater.inflate(R.menu.menu_attendance_main_normal, menu)
}
}
return super.onPrepareOptionsMenu(menu)
}
......
package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.main
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenter
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseView
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.group.Group
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.attendance.AttendanceDetailInfoJson
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.attendance.AttendanceStatisticGroupHeader
/**
* Created by fancyLou on 28/05/2018.
* Copyright © 2018 O2. All rights reserved.
*/
object AttendanceStatisticV2Contract {
interface View : BaseView {
}
interface Presenter : BasePresenter<View> {
}
}
\ No newline at end of file
package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.main
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import android.text.TextUtils
import com.jzxiang.pickerview.TimePickerDialog
import com.jzxiang.pickerview.data.Type
import com.jzxiang.pickerview.listener.OnDateSetListener
import kotlinx.android.synthetic.main.fragment_attendance_statistic.*
import kotlinx.android.synthetic.main.picker_activity_map_picker.*
import net.muliba.changeskin.FancySkinManager
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPViewPagerFragment
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.CommonRecyclerViewHolder
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.group.Group
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.adapter.group.GroupRecyclerViewAdapter
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.attendance.AttendanceDetailInfoJson
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.attendance.AttendanceStatisticGroupHeader
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.DateHelper
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.CircleTextView
import java.util.*
/**
* Created by fancyLou on 28/05/2018.
* Copyright © 2018 O2. All rights reserved.
*/
class AttendanceStatisticV2Fragment : BaseMVPViewPagerFragment<AttendanceStatisticV2Contract.View, AttendanceStatisticV2Contract.Presenter>(),
AttendanceStatisticV2Contract.View {
override var mPresenter: AttendanceStatisticV2Contract.Presenter = AttendanceStatisticV2Presenter()
override fun layoutResId(): Int = R.layout.fragment_attendance_statistic_v2
override fun initUI() {
}
override fun lazyLoad() {
}
}
\ No newline at end of file
package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.main
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
/**
* Created by fancyLou on 28/05/2018.
* Copyright © 2018 O2. All rights reserved.
*/
class AttendanceStatisticV2Presenter : BasePresenterImpl<AttendanceStatisticV2Contract.View>(), AttendanceStatisticV2Contract.Presenter {
}
\ No newline at end of file
......@@ -442,19 +442,16 @@ class MainActivity : BaseMVPActivity<MainContract.View, MainContract.Presenter>(
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private fun registerSchedulerJob() {
val componentName = ComponentName(this, ClearTempFileJobService::class.java)
val jobInfo = JobInfo.Builder(O2.O2_CLEAR_TEMP_FILE_JOB_ID, componentName)
.setPersisted(true)//手机重启之后是否继续
// .setPersisted(true)//手机重启之后是否继续
.setRequiresCharging(true)//充电的时候才执行
.setPeriodic(24 * 60 * 60 * 1000)
.build()
val jobScheduler = applicationContext.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
val result = jobScheduler.schedule(jobInfo)
// val result2 = jobScheduler.schedule(jobCollectLog)
// XLog.info("jobScheduler result:$result, result2:$result2")
XLog.info("jobScheduler result:$result")
}
......
package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.main
import android.text.TextUtils
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2CustomStyle
import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
......@@ -61,25 +62,25 @@ class MainPresenter : BasePresenterImpl<MainContract.View>(), MainContract.Prese
override fun checkAttendanceFeature() {
getAttendanceAssembleControlService(mView?.getContext())?.let {
service ->
service.listMyRecords().subscribeOn(Schedulers.io())
service.attendanceV2Check().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.o2Subscribe {
onNext {
val data = it.data
if (data?.scheduleInfos != null && data.scheduleInfos.isNotEmpty()) {
if (it.data?.version != null) {
O2SDKManager.instance().prefs().edit {
putString(O2.PRE_ATTENDANCE_VERSION_KEY, "1");
putString(O2.PRE_ATTENDANCE_VERSION_KEY, "2");
}
}else {
} else {
O2SDKManager.instance().prefs().edit {
putString(O2.PRE_ATTENDANCE_VERSION_KEY, "0");
putString(O2.PRE_ATTENDANCE_VERSION_KEY, "1");
}
}
}
onError { e, _ ->
XLog.error("", e)
O2SDKManager.instance().prefs().edit {
putString(O2.PRE_ATTENDANCE_VERSION_KEY, "0");
putString(O2.PRE_ATTENDANCE_VERSION_KEY, "1");
}
}
}
......
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/z_color_background_checkin">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/attendance_check_in_new_out_bg"
android:layout_marginStart="@dimen/spacing_normal"
android:layout_marginEnd="@dimen/spacing_normal"
android:layout_marginTop="@dimen/spacing_normal"
android:layout_marginBottom="@dimen/spacing_normal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_attendance_check_in_new_schedules"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_normal"
android:layout_marginStart="@dimen/spacing_normal"
android:layout_marginEnd="@dimen/spacing_normal"
app:layout_constraintBottom_toTopOf="@+id/rl_attendance_check_in_new_knock_btn"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0" />
<RelativeLayout
android:id="@+id/rl_attendance_check_in_new_knock_btn"
android:layout_width="128dp"
android:layout_height="128dp"
android:background="@drawable/attendance_check_in_bg"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@+id/ll_attendance_check_in_new_location"
android:layout_marginBottom="@dimen/spacing_large">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<TextView
android:id="@+id/tv_attendance_check_in_new_check_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textStyle="bold"
android:textSize="@dimen/font_large"
android:layout_gravity="center_horizontal"
android:text="@string/attendance_check_in_knock"/>
<TextView
android:id="@+id/tv_attendance_check_in_new_now_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:layout_marginTop="@dimen/spacing_tiny"
tools:text="12:00:00"/>
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_attendance_check_in_new_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="64dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/image_attendance_check_in_new_location_check_icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginEnd="@dimen/spacing_tiny"
android:src="@mipmap/icon_delete_people"
/>
<TextView
android:id="@+id/tv_attendance_check_in_new_workplace"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="位置信息还在查询中..."
android:textSize="@dimen/font_small"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/z_color_background">
</LinearLayout>
\ No newline at end of file
......@@ -14,6 +14,31 @@ import rx.Observable
interface AttendanceAssembleControlService {
////////////////v2/////////////////
/**
* v2版本检查
*/
@GET("jaxrs/v2/my/version")
fun attendanceV2Check():Observable<ApiResponse<AttendanceV2CheckData>>
/**
* 预打卡接口
* 打卡之前调用
*/
@GET("jaxrs/v2/mobile/check/pre")
fun attendanceV2PreCheck():Observable<ApiResponse<AttendanceV2PreCheckData>>
/**
* 打卡
*/
@POST("jaxrs/v2/mobile/check")
fun attendanceV2CheckIn(@Body body: AttendanceV2CheckInBody):Observable<ApiResponse<AttendanceV2CheckResponse>>
//////////////////////v1/////////////
/**
* 获取当前用户的考勤周期
*/
......
......@@ -8,6 +8,79 @@ import java.io.Serializable
* Created by fancy on 2017/3/28.
*/
/**
* 新版考勤 检查对象
*/
data class AttendanceV2CheckData(
var version: String = "",
)
data class AttendanceV2CheckItemData(
var id: String = "",
var userId: String = "",
var recordDateString: String = "",
var recordDate: String = "",
var preDutyTime: String = "",
var preDutyTimeBeforeLimit: String = "",
var preDutyTimeAfterLimit: String = "",
var sourceType: String = "",
var checkInResult: String = "",
var checkInType: String = "",
var sourceDevice: String = "",
var description: String = "",
var groupId: String = "",
var groupName: String = "",
var shiftId: String = "",
var shiftName: String = "",
var createTime: String = "",
var updateTime: String = "",
var sequence: String = "",
// 是否最后一条已经打卡过的数据
var isLastRecord: Boolean = false,
var isRecord: Boolean = false,
var recordTime: String = "", // 已打卡的显示内容
var checkInTypeString: String = "", // 打卡类型
)
data class AttendanceV2WorkPlace(
var id: String = "",
var placeName: String = "",
var placeAlias: String = "",
var creator: String = "",
var longitude: String = "",
var latitude: String = "",
var errorRange: Int = 200,
var description: String = "",
)
data class AttendanceV2PreCheckData(
var allowFieldWork: Boolean = false,
var requiredFieldWorkRemarks: Boolean = false,
var canCheckIn: Boolean = false,
var checkItemList: ArrayList<AttendanceV2CheckItemData>? = ArrayList(),
var workPlaceList: ArrayList<AttendanceV2WorkPlace>? = ArrayList(),
)
data class AttendanceV2CheckResponse(
var checkInRecordId: String = "",
var checkInResult: String = "",
var recordDate: String = "",
)
data class AttendanceV2CheckInBody(
var recordId: String = "",
var checkInType: String = "",
var workPlaceId: String = "",
var fieldWork: Boolean = false, // 是否外勤打卡
var signDescription: String = "", //打卡说明:上班打卡,下班打卡, 可以为空.
var sourceDevice: String = "", //操作设备类别:Mac|Windows|IOS|Android|其他, 可以为空.
var description: String = "",
var recordAddress: String = "", //打卡地点描述, 可以为空.
var longitude: String = "", //经度
var latitude: String = "", //纬度
)
/////////////////////////////////////
/**
* 管理员
*/
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册