Browse Source

添加了websocket连接 增加考勤打卡根据排版情况来

fancy 5 năm trước cách đây
mục cha
commit
934e4a0539

+ 7 - 1
o2ios/O2Platform.xcodeproj/project.pbxproj

@@ -118,6 +118,7 @@
 		B14E078A230141AC00AE85A0 /* ContactGroupPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E0789230141AC00AE85A0 /* ContactGroupPickerViewController.swift */; };
 		B14E078C230141BE00AE85A0 /* ContactPersonPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E078B230141BE00AE85A0 /* ContactPersonPickerViewController.swift */; };
 		B14E07C523025C6A00AE85A0 /* OOContactExpressAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E07C423025C6A00AE85A0 /* OOContactExpressAPI.swift */; };
+		B14E0C0C2484F1F0008AF6AE /* O2WebsocketManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E0C0B2484F1F0008AF6AE /* O2WebsocketManager.swift */; };
 		B1534E3F21F712EA00CC8C35 /* O2DemoAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1534E3E21F712EA00CC8C35 /* O2DemoAlertView.swift */; };
 		B158E95E215DD3F500AB2727 /* AIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B158E95D215DD3F500AB2727 /* AIConstants.swift */; };
 		B15D26EC235EF7480092F8B8 /* genstrings.sh in Resources */ = {isa = PBXBuildFile; fileRef = B15D26EB235EF7480092F8B8 /* genstrings.sh */; };
@@ -1416,6 +1417,7 @@
 		B14E0789230141AC00AE85A0 /* ContactGroupPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactGroupPickerViewController.swift; sourceTree = "<group>"; };
 		B14E078B230141BE00AE85A0 /* ContactPersonPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactPersonPickerViewController.swift; sourceTree = "<group>"; };
 		B14E07C423025C6A00AE85A0 /* OOContactExpressAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OOContactExpressAPI.swift; sourceTree = "<group>"; };
+		B14E0C0B2484F1F0008AF6AE /* O2WebsocketManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2WebsocketManager.swift; sourceTree = "<group>"; };
 		B1534E3E21F712EA00CC8C35 /* O2DemoAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2DemoAlertView.swift; sourceTree = "<group>"; };
 		B158E95D215DD3F500AB2727 /* AIConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AIConstants.swift; sourceTree = "<group>"; };
 		B15D26BF235EF0850092F8B8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/CloudFile.storyboard; sourceTree = "<group>"; };
@@ -1540,7 +1542,7 @@
 		B1FFF885223A23B200C170FD /* O2FlutterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = O2FlutterViewController.swift; sourceTree = "<group>"; };
 		B1FFF890223A4DA700C170FD /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
 		B1FFF891223A4DA700C170FD /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
-		C33461DCBCEEAF5B8597D54E /* Pods______.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = "Pods______.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+		C33461DCBCEEAF5B8597D54E /* Pods______.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods______.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		E40502C220722208009A8D30 /* ImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerController.swift; sourceTree = "<group>"; };
 		E40502C320722208009A8D30 /* ImageRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageRow.swift; sourceTree = "<group>"; };
 		E40502C420722208009A8D30 /* ImageCheckRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCheckRow.swift; sourceTree = "<group>"; };
@@ -2838,6 +2840,7 @@
 				B13A011023692A8B00025F3B /* O2CloudFileManager.swift */,
 				B1E0BAA02378FC01001D741F /* O2JPushManager.swift */,
 				B1ABAA0B237E498C0027EC48 /* O2VersionManager.swift */,
+				B14E0C0B2484F1F0008AF6AE /* O2WebsocketManager.swift */,
 			);
 			path = Manager;
 			sourceTree = "<group>";
@@ -5630,6 +5633,7 @@
 				"${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
 				"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
 				"${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework",
+				"${BUILT_PRODUCTS_DIR}/Starscream/Starscream.framework",
 				"${BUILT_PRODUCTS_DIR}/SwiftValidator/SwiftValidator.framework",
 				"${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework",
 				"${BUILT_PRODUCTS_DIR}/SwiftyTimer/SwiftyTimer.framework",
@@ -5672,6 +5676,7 @@
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework",
+				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Starscream.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftValidator.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework",
 				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyTimer.framework",
@@ -6371,6 +6376,7 @@
 				E4C24B8D20844F3C00E426B0 /* JCMessageLocationContentView.swift in Sources */,
 				E4CDB8851E7CFB9C008E788D /* ZLNormalNavViewController.swift in Sources */,
 				B1DA305F2282754500669418 /* QCalendarPicker.swift in Sources */,
+				B14E0C0C2484F1F0008AF6AE /* O2WebsocketManager.swift in Sources */,
 				E46E6CBC1DD41F5D00AB7561 /* HRCgUtil.m in Sources */,
 				E496E89E207314B100C68EEE /* NavView.swift in Sources */,
 				E4C24BD720844F3C00E426B0 /* JCMyInfoViewController.swift in Sources */,

+ 65 - 37
o2ios/O2Platform/App/NewAttance-考勤打卡/c/OOAttanceCheckInController.swift

@@ -19,7 +19,8 @@ class OOAttanceCheckInController: UITableViewController {
     
     var checkinForm:OOAttandanceMobileCheckinForm = OOAttandanceMobileCheckinForm()
     
-    var myButton:UIButton!
+    var myButton:UIButton?
+    var feature : OOAttandanceFeature?
     
     private lazy var headerView:OOAttanceHeaderView = {
        let view = Bundle.main.loadNibNamed("OOAttanceHeaderView", owner: self, options: nil)?.first as! OOAttanceHeaderView
@@ -38,7 +39,7 @@ class OOAttanceCheckInController: UITableViewController {
         headerView.startBMKMapViewService()
         NotificationCenter.default.addObserver(self, selector: #selector(locationReceive(_:)), name: OONotification.location.notificationName, object: nil)
         if myButton != nil {
-            myButton.isHidden = false
+            myButton?.isHidden = false
         }
     }
     
@@ -47,7 +48,7 @@ class OOAttanceCheckInController: UITableViewController {
         headerView.stopBMKMapViewService()
         NotificationCenter.default.removeObserver(self)
         if myButton != nil {
-            myButton.isHidden = true
+            myButton?.isHidden = true
         }
     }
     
@@ -70,30 +71,37 @@ class OOAttanceCheckInController: UITableViewController {
         tableView.register(UINib.init(nibName: "OOAttanceItemCell", bundle: nil), forCellReuseIdentifier: "OOAttanceItemCell")
         
         getCurrentCheckinList()
-        self.perform(#selector(createButton), with: nil, afterDelay: 0)
+        getMyRecords()
+//        self.perform(#selector(createButton), with: nil, afterDelay: 0)
     }
     
     
-    @objc func closeWindow() {
-        self.tabBarController?.navigationController?.dismiss(animated: true, completion: nil)
-    }
+//    @objc func closeWindow() {
+//        self.tabBarController?.navigationController?.dismiss(animated: true, completion: nil)
+//    }
     
-    @objc private func createButton() {
+    //创建打卡按钮
+    @objc private func createButton(feature: OOAttandanceFeature) {
         let window = UIApplication.shared.windows[0]
         myButton = UIButton(type: .custom)
-        myButton.frame = CGRect(x: kScreenW - 90, y: kScreenH - 150, width: 70, height: 70)
-        myButton.setTitle("打卡", for: .normal)
-        myButton.setTitle("打卡", for: .disabled)
-        myButton.titleLabel?.font = UIFont(name: "PingFangSC-Medium", size: 18.0)!
-        myButton.theme_backgroundColor = ThemeColorPicker(keyPath: "Base.base_color")
-        myButton.setBackgroundColor(UIColor.gray, forState: .disabled)
-        myButton.isEnabled = false
-        myButton.layer.cornerRadius = 35
-        myButton.layer.masksToBounds = true
-        myButton.addTarget(self, action: #selector(postCheckinButton(_:)), for: .touchUpInside)
-        window.addSubview(myButton)
-        let pan = UIPanGestureRecognizer(target: self, action: #selector(changePostion(_:)))
-        myButton.addGestureRecognizer(pan)
+        myButton?.frame = CGRect(x: kScreenW - 90, y: kScreenH - 150, width: 70, height: 70)
+        myButton?.setTitle("打卡", for: .normal)
+        myButton?.setTitle("打卡", for: .disabled)
+        myButton?.titleLabel?.font = UIFont(name: "PingFangSC-Medium", size: 14.0)!
+        myButton?.theme_backgroundColor = ThemeColorPicker(keyPath: "Base.base_color")
+        myButton?.setBackgroundColor(UIColor.gray, forState: .disabled)
+        myButton?.isEnabled = false
+        myButton?.layer.cornerRadius = 35
+        myButton?.layer.masksToBounds = true
+        myButton?.addTarget(self, action: #selector(postCheckinButton(_:)), for: .touchUpInside)
+        window.addSubview(myButton!)
+    }
+    //删除打卡按钮
+    private func removeButton() {
+        if myButton != nil {
+            myButton?.removeFromSuperview()
+            myButton = nil
+        }
     }
     
     @objc private func locationReceive(_ notification:Notification){
@@ -102,27 +110,27 @@ class OOAttanceCheckInController: UITableViewController {
             checkinForm.desc = result.sematicDescription
             checkinForm.longitude = String(result.location.longitude)
             checkinForm.latitude = String(result.location.latitude)
-            
             checkinForm.empNo = O2AuthSDK.shared.myInfo()?.employee
             checkinForm.empName = O2AuthSDK.shared.myInfo()?.name
             let currenDate = Date()
             checkinForm.recordDateString = currenDate.toString("yyyy-MM-dd")
             checkinForm.signTime = currenDate.toString("HH:mm:ss")
-            
-            checkinForm.optMachineType = UIDevice.deviceModel()
+            checkinForm.optMachineType = UIDevice.deviceModelReadable()
             checkinForm.optSystemName = "\(UIDevice.systemName()) \(UIDevice.systemVersion())"
-            // button enable
-            myButton.isEnabled = true
+            // 打卡按钮启用
+            myButton?.isEnabled = true
             headerView.addSubview(promptView)
             DDLogDebug("checkForm set completed")
         }else{
-            myButton.isEnabled = false
-            promptView.removeSubviews()
+            //打卡按钮禁用
+            myButton?.isEnabled = false
+            promptView.removeFromSuperview()
         }
     }
     
     @objc private func postCheckinButton(_ sender:UIButton){
         MBProgressHUD_JChat.showMessage(message: "打卡中...", toView: self.view)
+        checkinForm.checkin_type = self.feature?.checkinType ?? ""
         viewModel.postMyCheckin(checkinForm) { (result) in
             MBProgressHUD_JChat.hide(forView: self.view, animated: true)
             switch result {
@@ -130,6 +138,7 @@ class OOAttanceCheckInController: UITableViewController {
                 DispatchQueue.main.async {
                     MBProgressHUD_JChat.show(text:"打卡成功", view: self.view)
                     self.getCurrentCheckinList()
+                    self.getMyRecords()
                 }
                 break
             case .fail(let errorMessage):
@@ -143,9 +152,9 @@ class OOAttanceCheckInController: UITableViewController {
         }
     }
     
-    @objc private func changePostion(_ pan:UIPanGestureRecognizer){
-        
-    }
+//    @objc private func changePostion(_ pan:UIPanGestureRecognizer){
+//
+//    }
     
     func getWorkPlace() {
         viewModel.getLocationWorkPlace { (myResult) in
@@ -165,6 +174,27 @@ class OOAttanceCheckInController: UITableViewController {
         }
     }
     
+    func getMyRecords() {
+        viewModel.listMyRecords { (result) in
+            switch result {
+            case .ok(let record):
+                let model = record as? OOMyAttandanceRecords
+                if let feature = model?.feature, feature.signSeq ?? -1 > 0 {
+                    self.feature = feature
+                    self.createButton(feature: feature)
+                }else {
+                    self.removeButton()
+                }
+                break
+            case .fail(let err):
+                DDLogError(err)
+                break
+            default:
+                break
+            }
+        }
+    }
+    
     func getCurrentCheckinList() {
         var model = CommonPageModel()
         model.pageSize = 200
@@ -194,9 +224,7 @@ class OOAttanceCheckInController: UITableViewController {
         }
     }
     
-    func postCheckIn() {
-        
-    }
+     
 
     override func didReceiveMemoryWarning() {
         super.didReceiveMemoryWarning()
@@ -252,7 +280,7 @@ class OOAttanceCheckInController: UITableViewController {
     }
     
     
-//    deinit {
-//         headerView.stopBMKMapViewService()
-//    }
+    deinit {
+         DDLogDebug("deinit 这里是checkin controller 。。。。。。。。。")
+    }
 }

+ 70 - 0
o2ios/O2Platform/App/NewAttance-考勤打卡/m/OOAttandanceModels.swift

@@ -46,6 +46,7 @@ class OOAttandanceMobileDetail:NSObject,DataModel {
     @objc var optMachineType:String? // 操作设备类别:手机品牌|PAD|PC|其他
     @objc var optSystemName:String?  // 操作设备类别:Mac|Windows|IOS|Android|其他
     var recordStatus:Int?  //记录状态:0-未分析 1-已分析
+    @objc var checkin_type: String? // 打卡类型 上午上班打卡 下午下班打卡
     
     required override init() {
         
@@ -57,6 +58,73 @@ class OOAttandanceMobileDetail:NSObject,DataModel {
 
 }
 
+// MARK: - 打卡班次对象
+class OOAttandanceScheduleSetting: NSObject, DataModel {
+    /**
+     "id": "7c89ddfe-7e69-40ce-9908-d699081aa660",
+                "topUnitName": "浙江兰德纵横网络技术股份有限公司@1@U",
+                "unitName": "移动开发组@320494093@U",
+                "unitOu": "移动开发组@320494093@U",
+                "onDutyTime": "09:00",
+                "offDutyTime": "17:00",
+                "signProxy": 0,
+                "lateStartTime": "9:05",
+                "createTime": "2020-05-27 09:19:16",
+                "updateTime": "2020-05-27 09:19:16"
+     */
+    @objc var id: String?
+    @objc var topUnitName: String?
+    @objc var unitName: String?
+    @objc var unitOu: String?
+    @objc var onDutyTime: String?
+    @objc var offDutyTime: String?
+    var signProxy: Int?
+    @objc var lateStartTime: String?
+    @objc var createTime: String?
+    @objc var updateTime: String?
+    
+    required override init() {
+        
+    }
+    
+}
+
+// MARK: - 当前用户当天打卡功能
+class OOAttandanceFeature: NSObject, DataModel {
+    /**
+     "signSeq": 1,
+     "signDate": "2020-06-02",
+     "signTime": "09:00",
+     "checkinType": "上午上班打卡"
+     */
+    @objc var signDate: String?
+    @objc var signTime: String?
+    @objc var checkinType: String?
+    var signSeq: Int?
+    
+    required override init() {
+        
+    }
+    
+}
+
+// MARK: - istMyRecords 登录者当天的所有移动打卡信息记录 排版情况等
+class OOMyAttandanceRecords: NSObject, DataModel {
+    /**
+     {
+         "records": [],
+         "scheduleSetting": {},
+         "feature": {}
+     },
+     */
+    @objc var records:[OOAttandanceMobileDetail]?
+    @objc var scheduleSetting:OOAttandanceScheduleSetting?
+    @objc var feature: OOAttandanceFeature?
+    
+    required override init() {
+        
+    }
+}
 
 // MARK:- 提交打卡数据FormBean
 class OOAttandanceMobileCheckinForm:NSObject,DataModel {
@@ -83,6 +151,8 @@ class OOAttandanceMobileCheckinForm:NSObject,DataModel {
     
     @objc var optSystemName:String? //操作设备类别:Mac|Windows|IOS|Android|其他, 可以为空
     
+    @objc var checkin_type: String? //上午上班打卡 下午下班打卡 。。。。 对应OOAttandanceFeature里面的checkinType
+    
     required override init() {
         
     }

+ 13 - 1
o2ios/O2Platform/App/NewAttance-考勤打卡/v/OOAttanceItemCell.swift

@@ -35,7 +35,19 @@ class OOAttanceItemCell: UITableViewCell,Configurable {
         guard let model = item as? OOAttandanceMobileDetail else {
             return
         }
-        checkTimeLabel.text = "打卡时间:\(model.recordDateString ?? "") \(model.signTime ?? "")"
+        var showTime = ""
+        if let time = model.signTime {
+            if time.length > 5 {
+                showTime = time.subString(from: 0, to: 5)
+            }else {
+                showTime = time
+            }
+        }
+        if let type = model.checkin_type {
+            checkTimeLabel.text = "\(type): \(showTime)"
+        }else {
+            checkTimeLabel.text = "打开时间: \(showTime)"
+        }
         checkLocationLabel.text = "\(model.recordAddress ?? "")"
     }
     

+ 6 - 9
o2ios/O2Platform/App/NewAttance-考勤打卡/v/OOAttanceItemCell.xib

@@ -1,12 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
-    <device id="retina4_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
-        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -17,7 +14,7 @@
             <rect key="frame" x="0.0" y="0.0" width="320" height="68"/>
             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
             <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
-                <rect key="frame" x="0.0" y="0.0" width="320" height="67.5"/>
+                <rect key="frame" x="0.0" y="0.0" width="320" height="68"/>
                 <autoresizingMask key="autoresizingMask"/>
                 <subviews>
                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="打卡时间:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RNb-B2-SgD">
@@ -58,7 +55,7 @@
                         </constraints>
                     </imageView>
                     <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="地点" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5EJ-nc-2M4">
-                        <rect key="frame" x="57" y="32" width="247" height="21"/>
+                        <rect key="frame" x="57" y="32" width="248" height="21"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="21" id="CV2-av-WsC"/>
                         </constraints>
@@ -66,7 +63,7 @@
                         <color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
                         <nil key="highlightedColor"/>
                     </label>
-                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="pic_normal" translatesAutoresizingMaskIntoConstraints="NO" id="ZwF-rR-gyd">
+                    <imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="pic_normal" translatesAutoresizingMaskIntoConstraints="NO" id="ZwF-rR-gyd">
                         <rect key="frame" x="254" y="10" width="50" height="18"/>
                         <constraints>
                             <constraint firstAttribute="height" constant="18" id="1J7-7C-1jg"/>

+ 15 - 0
o2ios/O2Platform/App/NewAttance-考勤打卡/vm/OOAttandanceViewModel.swift

@@ -39,6 +39,21 @@ final class OOAttandanceViewModel: NSObject {
 }
 
 extension OOAttandanceViewModel{
+    
+    // MARK: -
+    func listMyRecords(_ completedBlock:@escaping CallbackBlockDefine) {
+        ooAttanceAPI.request(.listMyRecord) { response in
+            let myResult = OOResult<BaseModelClass<OOMyAttandanceRecords>>(response)
+            if myResult.isResultSuccess() {
+                let records = myResult.model?.data
+                completedBlock(.ok(records))
+            }else {
+                let errorMessage = myResult.error?.errorDescription ?? ""
+                completedBlock(.fail(errorMessage))
+            }
+        }
+    }
+    
     // MARK:- 读取配置的打卡位置
     func getLocationWorkPlace(_ completedBlock:@escaping CallbackBlockDefine) {
         ooAttanceAPI.request(.myWorkplace) { (responseResult) in

+ 98 - 1
o2ios/O2Platform/App/O2MainController.swift

@@ -9,6 +9,7 @@
 import UIKit
 import CocoaLumberjack
 import O2OA_Auth_SDK
+import Starscream
 
 class O2MainController: UITabBarController, UITabBarControllerDelegate {
     
@@ -46,12 +47,19 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
             //处理内部直连的时候推送的设备绑定
             O2JPushManager.shared.o2JPushBind()
         }
+        //连接websocket
+        self._startWebsocket()
+    }
+    
+    deinit {
+        //关闭websocket
+        self._stopWebsocket()
     }
     
     override func viewDidAppear(_ animated: Bool) {
         // 判断是否 第一次安装 是否是连接的demo服务器
         if let unit = O2AuthSDK.shared.bindUnit() {
-            if "demo.o2oa.net" == unit.centerHost || "demo.o2oa.io" == unit.centerHost || "demo.o2server.io" == unit.centerHost {
+            if "demo.o2oa.net" == unit.centerHost || "demo.o2oa.io" == unit.centerHost || "demo.o2server.io" == unit.centerHost || "sample.o2oa.net" == unit.centerHost {
                 let tag = AppConfigSettings.shared.demoAlertTag
                 if !tag {
                     demoAlertView.showFallDown()
@@ -181,4 +189,93 @@ class O2MainController: UITabBarController, UITabBarControllerDelegate {
         }
     }
     
+   
+    
+    // MARK: - websocket
+    private var timer:Timer?
+    private var isWsOpen = false
+    
+    private func _startWebsocket() {
+        DDLogDebug("启动websocket连接。。。。。。")
+       let url = AppDelegate.o2Collect.generateWebsocketURL()
+       DDLogDebug("这个是wsurl :\(url)")
+       O2WebsocketManager.instance.startConnect(wsUrl: url, delegate: self)
+   }
+    
+    private func _stopWebsocket() {
+        DDLogDebug("关闭websocket连接。。。。。。")
+        self.stopTiming()
+        O2WebsocketManager.instance.closeConnect()
+    }
+    
+    private func startTiming() {
+        DDLogDebug("开启定时器 。。。。。。")
+        if timer != nil {
+            timer?.invalidate()
+            timer = nil
+        }
+        timer = Timer.scheduledTimer(timeInterval: 30, target: self, selector: #selector(sendHeartbeatMsg), userInfo: nil, repeats: true)
+        timer?.fire()
+    }
+    private func stopTiming() {
+        DDLogDebug("关闭定时器 。。。。。。")
+        if timer != nil {
+            timer?.invalidate()
+            timer = nil
+        }
+    }
+    //发送心跳
+    @objc private func sendHeartbeatMsg() {
+        if isWsOpen {
+            O2WebsocketManager.instance.send(msg: "heartbeat")
+        }else {//重新启动
+            _startWebsocket()
+        }
+    }
+    
 }
+
+extension O2MainController: WebSocketDelegate {
+    
+
+    func didReceive(event: WebSocketEvent, client: WebSocket) {
+        switch event {
+        case .text(let text):
+            DDLogDebug("接收的ws消息:\(text)")
+            break
+        case .connected(let headers):
+            DDLogDebug("websocket is connected: \(headers)")
+            isWsOpen = true
+            self.startTiming()
+            break
+        case .disconnected(let reason, let code):
+            DDLogDebug("websocket is disconnected: \(reason) with code: \(code)")
+            isWsOpen = false
+             break
+        case .binary(let data):
+            DDLogDebug("Received binary data: \(data.count)")
+             break
+        case .ping(_):
+            break
+        case .pong(_):
+            break
+        case .viablityChanged(_):
+             DDLogDebug("websocket viablityChanged")
+            break
+        case .reconnectSuggested(_):
+            DDLogDebug("websocket reconnectSuggested")
+            break
+        case .cancelled:
+            DDLogDebug("websocket is canceled")
+            isWsOpen = false
+             break
+        case .error(let error):
+            DDLogError("websocket is error, \(String(describing: error?.localizedDescription))")
+            isWsOpen = false
+            break
+        }
+    }
+    
+    
+}
+

+ 7 - 0
o2ios/O2Platform/Extension/UIDeviceExtensions.swift

@@ -29,6 +29,13 @@ private let DeviceList = [
     /* iPhone 8 */        "iPhone10,1": "iPhone 8", "iPhone10,4": "iPhone 8",
     /* iPhone 8 Plus */   "iPhone10,2": "iPhone 8 Plus", "iPhone10,5": "iPhone 8 Plus",
     /* iPhone X */        "iPhone10,3": "iPhone X", "iPhone10,6": "iPhone X",
+    /* iPhone XS */       "iPhone11,2": "iPhone XS",
+    /* iPhone XS Max */   "iPhone11,4": "iPhone XS Max", "iPhone11,6": "iPhone XS Max",
+    /* iPhone XR */       "iPhone11,8": "iPhone XR",
+    /* iPhone 11 */       "iPhone12,1": "iPhone 11",
+    /* iPhone 11 Pro*/    "iPhone12,3": "iPhone 11 Pro",
+    /* iPhone 11 Pro Max*/"iPhone12,5": "iPhone 11 Pro Max",
+    /* iPhone SE 2*/      "iPhone12,8": "iPhone SE 2",
 
     /* iPad 2 */          "iPad2,1": "iPad 2", "iPad2,2": "iPad 2", "iPad2,3": "iPad 2", "iPad2,4": "iPad 2",
     /* iPad 3 */          "iPad3,1": "iPad 3", "iPad3,2": "iPad 3", "iPad3,3": "iPad 3",

+ 7 - 0
o2ios/O2Platform/Framework/O2API/AttendanceAPI/OOAttendanceAPI.swift

@@ -22,6 +22,7 @@ enum OOAttendanceAPI {
     case checkinCycle(String,String) //考勤周期
     case checkinTotalForMonth(OOAttandanceTotalBean) //考勤统计
     case checkinAnalyze(OOAttandanceTotalBean) //考勤分析
+    case listMyRecord //当前用户当前的打卡情况和班次
 }
 
 // MARK:- 上下文实现
@@ -66,6 +67,8 @@ extension OOAttendanceAPI:TargetType {
             return "/jaxrs/attendancedetail/filter/list"
         case .checkinAnalyze(let bean):
             return "/jaxrs/statisticshow/person/\(bean.q_empName!)/\(bean.q_year!)/\(bean.q_month!)"
+        case .listMyRecord:
+            return "/jaxrs/attendancedetail/mobile/my"
         
         }
     }
@@ -90,6 +93,8 @@ extension OOAttendanceAPI:TargetType {
             return .put
         case .checkinAnalyze(_):
             return .get
+        case .listMyRecord:
+            return .get
         }
     }
     
@@ -117,6 +122,8 @@ extension OOAttendanceAPI:TargetType {
             return .requestParameters(parameters: bean.toJSON() ?? [:], encoding: JSONEncoding.default)
         case .checkinAnalyze(_):
             return .requestPlain
+        case .listMyRecord:
+            return .requestPlain
         }
     }
     

+ 56 - 0
o2ios/O2Platform/Manager/O2WebsocketManager.swift

@@ -0,0 +1,56 @@
+//
+//  O2WebsocketManager.swift
+//  O2Platform
+//
+//  Created by FancyLou on 2020/6/1.
+//  Copyright © 2020 zoneland. All rights reserved.
+//
+
+import Foundation
+import Starscream
+import CocoaLumberjack
+
+
+class O2WebsocketManager {
+
+    static let instance: O2WebsocketManager = {
+        return O2WebsocketManager()
+    }()
+
+    private init() { }
+
+    private var socket: WebSocket?
+
+
+    // wsUrl: ws://xxx.o2oa.net:20020/x_message_assemble_communicate/ws/collaboration?x-token=xxxxxxx
+    //开启连接
+    func startConnect(wsUrl: String, delegate: WebSocketDelegate) {
+        let request = URLRequest(url: URL(string: wsUrl)!)
+        socket = WebSocket(request: request)
+        socket?.delegate = delegate
+        socket?.connect()
+    }
+
+    //发送消息
+    func send(msg: String) {
+        guard let s = socket else {
+            DDLogError("socket 为空 还未启动 无法发送消息")
+            return
+        }
+        s.write(string: msg)
+    }
+
+    //关闭连接
+    func closeConnect() {
+        guard let s = socket else {
+            DDLogError("socket 为空 无需关闭")
+            return
+        }
+        s.disconnect(closeCode: CloseCode.goingAway.rawValue)
+        socket = nil
+    }
+
+}
+
+
+

+ 0 - 1
o2ios/O2Platform/O2Platform-Bridging-Header.h

@@ -44,4 +44,3 @@
 // flutter
 #import "GeneratedPluginRegistrant.h"
 
-

+ 14 - 0
o2ios/O2Platform/config/O2Collect.swift

@@ -83,6 +83,20 @@ class O2Collect{
         return self.generateURLWithAppContextKey(appContextKey, scheme: "http", query: query, parameter: parameter,coverted: coverted,generateTime: generateTime)
     }
     
+    /**
+        生成websocket连接地址
+     */
+    func generateWebsocketURL() -> String {
+        if let webServer = O2AuthSDK.shared.centerServerInfo()?.webServer, let communicateNode = O2AuthSDK.shared.centerServerInfo()?.assembles?["x_message_assemble_communicate"] {
+            var wsProtocol = "ws://"
+            if webServer.httpProtocol == "https" {
+                wsProtocol = "wss://"
+            }
+            return "\(wsProtocol)\(communicateNode.host ?? ""):\(communicateNode.port ?? 20020)\(communicateNode.context ?? "/x_message_assemble_communicate")/ws/collaboration?x-token=\(O2AuthSDK.shared.myInfo()?.token ?? "")"
+        }
+        return ""
+    }
+    
     
     /**
      前台请求H5页面路径生成方法

+ 2 - 0
o2ios/Podfile

@@ -93,6 +93,8 @@ target 'O2Platform' do
     pod 'JPush', '3.2.4'
     pod 'JMessage'
     
+    # websocket
+    pod 'Starscream', '~> 4.0.0'
     
     
     

+ 5 - 1
o2ios/Podfile.lock

@@ -71,6 +71,7 @@ PODS:
     - SDWebImage/Core (= 4.4.2)
   - SDWebImage/Core (4.4.2)
   - SnapKit (4.0.1)
+  - Starscream (4.0.0)
   - SwiftValidator (4.0.0)
   - SwiftyJSON (3.1.4)
   - SwiftyTimer (2.1.0)
@@ -113,6 +114,7 @@ DEPENDENCIES:
   - RxCocoa (~> 4.0)
   - SDWebImage (~> 4.0)
   - SnapKit (~> 4.0.0)
+  - Starscream (~> 4.0.0)
   - SwiftValidator (from `https://github.com/jpotts18/SwiftValidator.git`, branch `master`)
   - SwiftyJSON (~> 3.1)
   - SwiftyTimer
@@ -161,6 +163,7 @@ SPEC REPOS:
     - RxSwift
     - SDWebImage
     - SnapKit
+    - Starscream
     - SwiftyJSON
     - SwiftyTimer
     - SwiftyUserDefaults
@@ -217,6 +220,7 @@ SPEC CHECKSUMS:
   RxSwift: 5976ecd04fc2fefd648827c23de5e11157faa973
   SDWebImage: 624d6e296c69b244bcede364c72ae0430ac14681
   SnapKit: 0de968a9fec17499afa29683b05d0c775b6d1c29
+  Starscream: 04b26f02727e10a002e6b5d21b188ba0d049910b
   SwiftValidator: 25ded5ca1f10c05adf57f6ac82a72d28ac8d91af
   SwiftyJSON: c2842d878f95482ffceec5709abc3d05680c0220
   SwiftyTimer: 02dd6cf10cbc71cbf67cec494f6e5eb782102543
@@ -224,6 +228,6 @@ SPEC CHECKSUMS:
   YHPhotoKit: e88368af1fca0a110d41b88417088f7e49876981
   YHPopupView: 96d9c05c79a2a17cf69c3def09e5305cfae9e8e8
 
-PODFILE CHECKSUM: db8bd463f4a5f9d40d99734694cef3178373900d
+PODFILE CHECKSUM: c9dd30b0987ffddb95ec8f9c0af2a4134a03ae69
 
 COCOAPODS: 1.8.4