Преглед изворни кода

考勤打卡功能修改 使用钉钉类似的界面

fancy пре 5 година
родитељ
комит
ac4b4aa2a3
19 измењених фајлова са 614 додато и 86 уклоњено
  1. 2 0
      o2android/.gitignore
  2. 339 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/attendance/main/AttendanceCheckInNewFragment.kt
  3. 10 2
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/attendance/main/AttendanceMainActivity.kt
  4. 1 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatActivity.kt
  5. 1 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/about/AboutActivity.kt
  6. 2 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainActivity.kt
  7. 1 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainContract.kt
  8. 25 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainPresenter.kt
  9. 23 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/widgets/GridLayoutItemDecoration.kt
  10. 4 9
      o2android/app/src/main/res/drawable/attendance_check_in_bg.xml
  11. 0 43
      o2android/app/src/main/res/drawable/attendance_check_in_button.xml
  12. 15 0
      o2android/app/src/main/res/drawable/attendance_check_in_new_out_bg.xml
  13. 2 2
      o2android/app/src/main/res/drawable/attendance_check_in_schedule_item_bg.xml
  14. 90 0
      o2android/app/src/main/res/layout/fragment_attendance_check_in_new.xml
  15. 0 27
      o2android/app/src/main/res/layout/item_attendance_check_in_record_list.xml
  16. 76 0
      o2android/app/src/main/res/layout/item_attendance_check_in_schdule_list.xml
  17. 3 1
      o2android/app/src/main/res/values/colors.xml
  18. 2 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2.kt
  19. 18 1
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/attendance/AttendanceJSON.kt

+ 2 - 0
o2android/.gitignore

@@ -3,6 +3,8 @@
 /captures
 .svn/
 
+autopacking.sh
+
 reports/
 
 # Built application files

+ 339 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/attendance/main/AttendanceCheckInNewFragment.kt

@@ -0,0 +1,339 @@
+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.support.v4.content.ContextCompat
+import android.support.v7.widget.GridLayoutManager
+import android.widget.ImageView
+import android.widget.TextView
+import com.baidu.location.BDLocation
+import com.baidu.location.BDLocationListener
+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.*
+import kotlinx.android.synthetic.main.fragment_attendance_check_in_new.*
+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.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 AttendanceCheckInNewFragment : BaseMVPViewPagerFragment<AttendanceCheckInContract.View, AttendanceCheckInContract.Presenter>(),
+        AttendanceCheckInContract.View, BDLocationListener {
+    override var mPresenter: AttendanceCheckInContract.Presenter = AttendanceCheckInPresenter()
+    override fun layoutResId(): Int = R.layout.fragment_attendance_check_in_new
+
+
+    private val recordList = ArrayList<MobileScheduleInfo>()
+    private var lastRecord: MobileCheckInJson? = null
+    private val recordAdapter: CommonRecycleViewAdapter<MobileScheduleInfo> by lazy {
+        object : CommonRecycleViewAdapter<MobileScheduleInfo>(activity, recordList, R.layout.item_attendance_check_in_schdule_list) {
+            override fun convert(holder: CommonRecyclerViewHolder?, t: MobileScheduleInfo?) {
+                if (holder != null && t != null) {
+                    holder.setText(R.id.tv_item_attendance_check_in_schedule_list_type, t.checkinType)
+                            .setText(R.id.tv_item_attendance_check_in_schedule_list_time, t.signTime)
+                            .setText(R.id.tv_item_attendance_check_in_schedule_list_status, t.checkinStatus)
+//                    val image = holder.getView<ImageView>(R.id.image_item_attendance_check_in_schedule_list_enable_icon)
+                    val updateBtn = holder.getView<TextView>(R.id.tv_item_attendance_check_in_schedule_list_update_btn)
+                    updateBtn.gone()
+                    if (t.checkinStatus == "已打卡") {
+//                        image.visible()
+                        holder.setText(R.id.tv_item_attendance_check_in_schedule_list_status, t.checkinTime.substring(0, 5)+t.checkinStatus)
+                        if (lastRecord != null && lastRecord!!.id == t.recordId) {
+                            updateBtn.visible()
+                        }
+                    }else {
+//                        image.gone()
+                    }
+                }
+
+            }
+        }
+    }
+    private val workplaceList = ArrayList<MobileCheckInWorkplaceInfoJson>()
+
+    //定位
+    private val mLocationClient: LocationClient by lazy { LocationClient(activity) }
+    private var myLocation: BDLocation? = null //当前我的位置
+    private var checkInPosition: MobileCheckInWorkplaceInfoJson? = null//离的最近的工作地点位置
+    private var isInCheckInPositionRange = false
+    private var needCheckIn = 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.listMyRecords()
+        mPresenter.loadAllWorkplace()
+    }
+
+    override fun initUI() {
+        //定位
+        mLocationClient.registerLocationListener(this)
+        initBaiduLocation()
+        mLocationClient.start()
+
+        //打卡班次
+        rv_attendance_check_in_new_schedules.layoutManager = GridLayoutManager(activity, 2)
+        rv_attendance_check_in_new_schedules.addItemDecoration(GridLayoutItemDecoration(activity.dip(10), activity.dip(10), 2))
+        rv_attendance_check_in_new_schedules.adapter = recordAdapter
+        recordAdapter.setOnItemClickListener { view, position ->
+            val t = recordList[position]
+            if (t.checkinStatus == "已打卡") {
+                if (lastRecord != null && lastRecord!!.id == t.recordId) {
+                    updateCheckIn(t)
+                }
+            }
+        }
+
+        //打卡按钮
+        rl_attendance_check_in_new_knock_btn.setOnClickListener {
+            if (!needCheckIn) {
+                XToast.toastShort(activity, "今日已经不需要打卡!")
+                return@setOnClickListener
+            }
+            if (!isInCheckInPositionRange) {
+                XToast.toastShort(activity, "还未进入打卡范围,无法打卡!")
+                return@setOnClickListener
+            }
+            if (myLocation != 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()
+                val signDate = DateHelper.nowByFormate("yyyy-MM-dd")
+                val signTime = DateHelper.nowByFormate("HH:mm:ss")
+                val checkType = calCheckType()
+                mPresenter.checkIn(myLocation!!.latitude.toString(), myLocation!!.longitude.toString(),
+                        myLocation!!.addrStr, "", signDate, signTime, "", checkType)
+            }
+        }
+        //时间
+        timer.schedule(timerTask, 0, 1000)
+    }
+
+    /**
+     * 更新打卡
+     */
+    private fun updateCheckIn(info: MobileScheduleInfo) {
+        O2DialogSupport.openConfirmDialog(activity, "确定要更新这条打卡记录?",{ _ ->
+            val signDate = DateHelper.nowByFormate("yyyy-MM-dd")
+            val signTime = DateHelper.nowByFormate("HH:mm:ss")
+            mPresenter.checkIn(myLocation!!.latitude.toString(), myLocation!!.longitude.toString(),
+                    myLocation!!.addrStr, "", signDate, signTime, info.recordId, info.checkinType)
+        })
+    }
+
+
+    /**
+     * 计算下次打什么卡
+     */
+    private fun calCheckType() : String {
+        val list = recordList.reversed()
+        XLog.debug(list.joinToString())
+        val newList = ArrayList<MobileScheduleInfo>()
+        for (info in list) {
+            if(info.checkinStatus == "未打卡") {
+                newList.add(info)
+            }else {
+                break
+            }
+        }
+        XLog.debug(newList.joinToString())
+        if (newList.isNotEmpty()) {
+            return newList.last().checkinType
+        }
+        return ""
+    }
+
+    override fun onDestroyView() {
+        timer.cancel()
+        timerTask.cancel()
+        super.onDestroyView()
+
+    }
+
+    override fun onDestroy() {
+        // 退出时销毁定位
+        mLocationClient.stop()
+        super.onDestroy()
+    }
+
+
+    override fun myRecords(records: MobileMyRecords?) {
+        if (records != null) {
+            val rList = records.records//打卡结果
+            lastRecord = rList.lastOrNull()
+            recordList.clear()
+            var unCheckNumber = 0
+            val list = records.scheduleInfos.map {
+                val s = MobileScheduleInfo()
+                s.signSeq = it.signSeq
+                s.checkinType = it.checkinType
+                //是否已打卡
+                val record = rList.firstOrNull { re -> re.checkin_type == it.checkinType }
+                if (record != null) {
+                    s.checkinStatus =  "已打卡"
+                    s.checkinTime = record.signTime
+                    s.recordId = record.id
+                    unCheckNumber = 0 //清零
+                }else{
+                    s.checkinStatus =  "未打卡"
+                    unCheckNumber++
+                }
+                s.signDate = it.signDate
+                s.signTime = it.signTime
+                s
+            }
+            recordList.addAll(list)
+            recordAdapter.notifyDataSetChanged()
+            if (unCheckNumber > 0) {
+                needCheckIn = true
+                val draw = rl_attendance_check_in_new_knock_btn.background as? GradientDrawable
+                draw?.setColor(ContextCompat.getColor(activity, R.color.z_color_primary))
+            }else {
+                needCheckIn = false
+                val draw = rl_attendance_check_in_new_knock_btn.background as? GradientDrawable
+                draw?.setColor(ContextCompat.getColor(activity, R.color.disabled))
+            }
+        }else {
+            needCheckIn = false
+            val draw = rl_attendance_check_in_new_knock_btn.background as? GradientDrawable
+            draw?.setColor(ContextCompat.getColor(activity, R.color.disabled))
+        }
+    }
+
+    override fun workplaceList(list: List<MobileCheckInWorkplaceInfoJson>) {
+        workplaceList.clear()
+        workplaceList.addAll(list)
+        //计算
+        calNearestWorkplace()
+    }
+
+    override fun todayCheckInRecord(list: List<MobileCheckInJson>) {
+    }
+
+    override fun checkIn(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.listMyRecords()
+    }
+
+    override fun onReceiveLocation(location: BDLocation?) {
+        // 刷新定位信息
+        XLog.debug("onReceive locType:${location?.locType}, latitude:${location?.latitude}, longitude:${location?.longitude}")
+        if (location != null) {
+            myLocation = location
+            //计算
+            calNearestWorkplace()
+        }
+    }
+
+    override fun onConnectHotSpotMessage(p0: String?, p1: Int) {
+        XLog.debug("onConnectHotSpotMessage, p0:$p0, p1:$p1")
+    }
+
+    /**
+     * 检查是否进入打卡范围
+     */
+    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 (workplaceList.isNotEmpty() && myLocation!=null) {
+            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()
+        }
+    }
+
+    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
+    }
+}

+ 10 - 2
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/attendance/main/AttendanceMainActivity.kt

@@ -11,6 +11,8 @@ import android.view.Menu
 import android.view.MenuItem
 import kotlinx.android.synthetic.main.activity_attendance_main.*
 import net.muliba.changeskin.FancySkinManager
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2SDKManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.R
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.approval.AttendanceAppealApprovalActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.attendance.list.AttendanceListActivity
@@ -32,11 +34,17 @@ class AttendanceMainActivity : BaseMVPActivity<AttendanceMainContract.View, Atte
     var locationEnable: Boolean = false
     private var isAttendanceAdmin: Boolean = false
 
-    private val fragmentList: ArrayList<Fragment> by lazy { arrayListOf<Fragment>(AttendanceCheckInFragment(), AttendanceStatisticFragment()) }
+    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), true, true)
+        setupToolBar(getString(R.string.attendance_check_in_title), setupBackButton = true, isCloseBackIcon = true)
 
+        val attendanceVersion = O2SDKManager.instance().prefs().getString(O2.PRE_ATTENDANCE_VERSION_KEY, "0")
+        fragmentList = if (attendanceVersion == "1") {
+            arrayListOf<Fragment>(AttendanceCheckInNewFragment(), AttendanceStatisticFragment())
+        }else {
+            arrayListOf<Fragment>(AttendanceCheckInFragment(), AttendanceStatisticFragment())
+        }
         view_pager_attendance_main_content.adapter = CommonFragmentPagerAdapter(supportFragmentManager, fragmentList, titleList)
         view_pager_attendance_main_content.addOnPageChangeListener {
             onPageSelected { position ->

+ 1 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2ChatActivity.kt

@@ -514,7 +514,7 @@ class O2ChatActivity : BaseMVPActivity<O2ChatContract.View, O2ChatContract.Prese
                     .o2Subscribe {
                         onNext { (granted, _, _) ->
                             if (!granted){
-                                O2DialogSupport.openAlertDialog(this@O2ChatActivity, "需要定位权限, 去设置", { permissionSetting() })
+                                O2DialogSupport.openAlertDialog(this@O2ChatActivity, "语音消息需要权限, 去设置", { permissionSetting() })
                             }
                         }
                         onError { e, _ ->

+ 1 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/about/AboutActivity.kt

@@ -110,6 +110,7 @@ class AboutActivity : AppCompatActivity() {
 
             override fun onNoneUpdate(error: String) {
                 XLog.info(error)
+                XToast.toastShort(this@AboutActivity, "已经是最新版本了!")
                 callbackContinue?.invoke(false)
             }
 

+ 2 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainActivity.kt

@@ -144,6 +144,8 @@ class MainActivity : BaseMVPActivity<MainContract.View, MainContract.Presenter>(
         bindService(webSocketServiceIntent, serviceConnect, BIND_AUTO_CREATE)
 
         registerBroadcast()
+
+        mPresenter.checkAttendanceFeature()
     }
 
     override fun o2AIEnable(enable: Boolean) {

+ 1 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainContract.kt

@@ -15,5 +15,6 @@ object MainContract {
 
     interface Presenter: BasePresenter<View> {
         fun checkO2AIEnable()
+        fun checkAttendanceFeature()
     }
 }

+ 25 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MainPresenter.kt

@@ -1,9 +1,13 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.main
 
+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
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.enums.ApplicationEnum
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.realm.RealmDataService
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.edit
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
@@ -29,4 +33,25 @@ class MainPresenter : BasePresenterImpl<MainContract.View>(), MainContract.Prese
                     }
                 }
     }
+
+    override fun checkAttendanceFeature() {
+        getAttendanceAssembleControlService(mView?.getContext())?.let {
+            service ->
+            service.listMyRecords().subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            val data = it.data
+                            if (data?.scheduleInfos != null && data.scheduleInfos.isNotEmpty()) {
+                                O2SDKManager.instance().prefs().edit {
+                                    putString(O2.PRE_ATTENDANCE_VERSION_KEY, "1");
+                                }
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("", e)
+                        }
+                    }
+        }
+    }
 }

+ 23 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/widgets/GridLayoutItemDecoration.kt

@@ -0,0 +1,23 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets
+
+import android.graphics.Rect
+import android.support.v7.widget.RecyclerView
+import android.view.View
+
+/**
+ * Created by fancyLou on 2020-07-20.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+class GridLayoutItemDecoration(val leftSpace: Int, val bottomSpace: Int, val spanCount: Int) : RecyclerView.ItemDecoration() {
+
+    override fun getItemOffsets(outRect: Rect?, view: View?, parent: RecyclerView?, state: RecyclerView.State?) {
+        outRect?.left = leftSpace
+        outRect?.bottom = bottomSpace
+        val i = parent?.getChildLayoutPosition(view) ?: 0
+        if ((i % spanCount)==0) {
+            outRect?.left = 0
+        }
+    }
+}

+ 4 - 9
o2android/app/src/main/res/drawable/attendance_check_in_bg.xml

@@ -1,10 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
-    <!-- outer circle -->
-    <item>
-        <shape android:shape="oval" >
-            <solid android:color="@color/icon_light_blue" />
-        </shape>
-    </item>
-
-</layer-list>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="@color/colorPrimary"/>
+</shape>

+ 0 - 43
o2android/app/src/main/res/drawable/attendance_check_in_button.xml

@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <!-- normal -->
-    <item android:state_enabled="true" android:state_focused="false" android:state_pressed="false">
-        <layer-list>
-            <item android:drawable="@drawable/attendance_check_in_bg" />
-            <item android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp">
-                <shape android:shape="oval">
-                    <!--<stroke android:width="1dp" android:color="#FFFCFCFC" />-->
-                    <gradient android:angle="270" android:endColor="@color/okr_bg" android:startColor="@color/load_blue" />
-                </shape>
-            </item>
-        </layer-list>
-    </item>
-
-    <!-- pressed -->
-    <item android:state_enabled="true" android:state_pressed="true">
-        <layer-list>
-            <item android:drawable="@drawable/attendance_check_in_bg" />
-            <item android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp">
-                <shape android:shape="oval">
-                    <!--<stroke android:width="2dp" android:color="#FFf8f640" />-->
-                    <gradient android:angle="270" android:endColor="@color/icon_blue" android:startColor="@color/icon_blue" />
-                </shape>
-            </item>
-        </layer-list>
-    </item>
-
-    <!-- selected -->
-    <item android:state_enabled="true" android:state_focused="true" android:state_pressed="false">
-        <layer-list>
-            <item android:drawable="@drawable/attendance_check_in_bg" />
-            <item android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp">
-                <shape android:shape="oval">
-                    <!--<stroke android:width="2dp" android:color="#FFf8f640" />-->
-                    <gradient android:angle="270" android:endColor="@color/icon_blue" android:startColor="@color/icon_blue" />
-                </shape>
-            </item>
-        </layer-list>
-    </item>
-
-</selector>

+ 15 - 0
o2android/app/src/main/res/drawable/attendance_check_in_new_out_bg.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- 实心 -->
+    <solid android:color="@color/white"/>
+    <!-- 圆角 -->
+    <corners android:radius="24dp"/>
+    <!-- 边距 -->
+    <padding
+        android:top="5dp"
+        android:bottom="5dp"
+        android:left="5dp"
+        android:right="5dp"/>
+
+</shape>

+ 2 - 2
o2android/app/src/main/res/drawable/attendance_check_in_update_button_bg.xml → o2android/app/src/main/res/drawable/attendance_check_in_schedule_item_bg.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/icon_light_blue" />
-    <corners android:radius="4dp" />
+    <solid android:color="@color/z_color_background_checkin_record" />
+    <corners android:radius="10dp" />
     <padding
         android:left="5dp"
         android:top="5dp"

+ 90 - 0
o2android/app/src/main/res/layout/fragment_attendance_check_in_new.xml

@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.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">
+    <android.support.constraint.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">
+
+        <android.support.v7.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>
+
+    </android.support.constraint.ConstraintLayout>
+</android.support.constraint.ConstraintLayout>

+ 0 - 27
o2android/app/src/main/res/layout/item_attendance_check_in_record_list.xml

@@ -73,31 +73,4 @@
             android:layout_marginTop="@dimen/spacing_small"
             android:background="@color/z_color_bottom_bar_background" />
     </LinearLayout>
-
-
-    <!--<LinearLayout-->
-    <!--android:layout_width="match_parent"-->
-    <!--android:layout_height="wrap_content"-->
-    <!--android:layout_margin="@dimen/spacing_large">-->
-    <!--<LinearLayout-->
-    <!--android:id="@+id/linear_item_attendance_check_in_update_button"-->
-    <!--android:layout_width="wrap_content"-->
-    <!--android:layout_height="wrap_content"-->
-    <!--android:orientation="horizontal"-->
-    <!--android:gravity="center_vertical"-->
-    <!--android:visibility="gone"-->
-    <!--android:background="@drawable/attendance_check_in_update_button_bg">-->
-    <!--<TextView-->
-    <!--android:layout_width="wrap_content"-->
-    <!--android:layout_height="wrap_content"-->
-    <!--android:text="@string/attendance_check_in_update"-->
-    <!--android:textColor="@android:color/white"/>-->
-    <!--<ImageView-->
-    <!--android:layout_width="@dimen/font_normal"-->
-    <!--android:layout_height="@dimen/font_normal"-->
-    <!--android:layout_marginLeft="@dimen/spacing_small"-->
-    <!--android:src="@mipmap/icon_refresh"/>-->
-    <!--</LinearLayout>-->
-
-    <!--</LinearLayout>-->
 </LinearLayout>

+ 76 - 0
o2android/app/src/main/res/layout/item_attendance_check_in_schdule_list.xml

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.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="wrap_content"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:background="@drawable/attendance_check_in_schedule_item_bg">
+
+    <TextView
+        android:id="@+id/tv_item_attendance_check_in_schedule_list_type"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        tools:text="上午上班打卡"
+        android:textStyle="bold"
+        android:textSize="@dimen/font_normal"
+        android:textColor="@color/z_color_text_primary"
+        android:layout_marginStart="@dimen/spacing_small"
+        android:layout_marginTop="@dimen/spacing_small"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <TextView
+        android:id="@+id/tv_item_attendance_check_in_schedule_list_time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        tools:text="09:00"
+        android:textStyle="bold"
+        android:textSize="@dimen/font_normal"
+        android:textColor="@color/z_color_text_primary"
+        android:layout_marginStart="@dimen/spacing_tiny"
+        android:layout_marginTop="@dimen/spacing_small"
+        app:layout_constraintStart_toEndOf="@+id/tv_item_attendance_check_in_schedule_list_type"
+        app:layout_constraintTop_toTopOf="parent" />
+
+    <ImageView
+        android:id="@+id/image_item_attendance_check_in_schedule_list_enable_icon"
+        android:layout_width="16dp"
+        android:layout_height="16dp"
+        android:layout_marginStart="@dimen/spacing_small"
+        android:layout_marginTop="@dimen/spacing_tiny"
+        android:layout_marginBottom="@dimen/spacing_small"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/tv_item_attendance_check_in_schedule_list_type"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:visibility="gone"
+        android:src="@mipmap/list_selected" />
+
+    <TextView
+        android:id="@+id/tv_item_attendance_check_in_schedule_list_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        tools:text="未打卡"
+        android:textColor="@color/z_color_text_hint"
+        android:textSize="@dimen/font_small"
+        android:layout_marginStart="@dimen/spacing_small"
+        android:layout_marginTop="@dimen/spacing_tiny"
+        android:layout_marginBottom="@dimen/spacing_small"
+        app:layout_constraintStart_toEndOf="@+id/image_item_attendance_check_in_schedule_list_enable_icon"
+        app:layout_constraintTop_toBottomOf="@+id/tv_item_attendance_check_in_schedule_list_type"
+        app:layout_constraintBottom_toBottomOf="parent" />
+    <TextView
+        android:id="@+id/tv_item_attendance_check_in_schedule_list_update_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="更新打卡"
+        android:textColor="@color/z_color_primary_blue"
+        android:textSize="@dimen/font_small"
+        android:layout_marginTop="@dimen/spacing_tiny"
+        android:layout_marginStart="@dimen/spacing_small"
+        android:layout_marginBottom="@dimen/spacing_small"
+        app:layout_constraintStart_toEndOf="@+id/tv_item_attendance_check_in_schedule_list_status"
+        app:layout_constraintTop_toBottomOf="@+id/tv_item_attendance_check_in_schedule_list_type"
+        app:layout_constraintBottom_toBottomOf="parent"
+        android:visibility="gone"/>
+</android.support.constraint.ConstraintLayout>

+ 3 - 1
o2android/app/src/main/res/values/colors.xml

@@ -22,6 +22,7 @@
     <color name="z_color_black_alpha">#61000000</color>
 
 
+
     <!-- refresh layout loading color -->
     <color name="z_color_refresh_red">#ff0000</color>
     <color name="z_color_refresh_orange">#ff5722</color>
@@ -94,7 +95,8 @@
     <!-- attendance-->
     <color name="overlay_work_place">#1c3288dd</color>
     <color name="overlay_work_place_border">#3288dd</color>
-
+    <color name="z_color_background_checkin">#FFF1F3F4</color>
+    <color name="z_color_background_checkin_record">#FFF4F6F8</color>
     <color name="bg_biometry_dialog">#99000000</color>
 
     <!--im-->

+ 2 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/O2.kt

@@ -136,6 +136,8 @@ object O2 {
 
     val PRE_IS_FIRST = "IS_FIRST_LOGIN"
 
+    val PRE_ATTENDANCE_VERSION_KEY = "PRE_ATTENDANCE_VERSION_KEY" //考勤版本兼容问题的key  1表示新版本 其他表示老版本 切换打卡页面使用
+
     val BUSINESS_TYPE_MESSAGE_CENTER = 0//信息中心
     val BUSINESS_TYPE_WORK_CENTER = 1//工作中心
 

+ 18 - 1
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/attendance/AttendanceJSON.kt

@@ -235,13 +235,30 @@ data class MobileFeature(
         var checkinType: String = ""
 )
 
+/**
+ * 打卡结果和打卡班次的结合
+ * 兼容老的模式 如果没有班次就是用打卡结果替代
+ */
+data class MobileScheduleInfo(
+        var signSeq: Int = -1,
+        var signDate: String = "",
+        var signTime: String = "",
+        var checkinType: String = "",
+        var checkinStatus: String = "", // 未打卡 已打卡
+        var checkinTime: String = "", //打卡时间
+        var recordId: String = "" //打卡结果的id 更新打卡用
+)
+
+
+
 /**
  * listMyRecords 返回对象
  */
 data class MobileMyRecords(
         var records:List<MobileCheckInJson> = ArrayList(),
         var scheduleSetting: MobileScheduleSetting?,
-        var feature : MobileFeature?
+        var feature : MobileFeature?,
+        var scheduleInfos: List<MobileFeature> = ArrayList()
 )
 
 /**