diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/QrBean.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/QrBean.kt new file mode 100644 index 0000000000..10d80432cf --- /dev/null +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/QrBean.kt @@ -0,0 +1,227 @@ +package com.mogo.och.common.module.manager.scnner + +import com.mogo.eagle.core.utilcode.mogo.Product +import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_OCHCOMMON +import com.mogo.eagle.core.utilcode.util.GsonUtils +import com.mogo.eagle.core.utilcode.util.RegexUtils +import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager +import com.mogo.och.common.module.manager.socket.lan.LanSocketManager +import com.mogo.och.common.module.manager.socket.lan.bean.WriteOffDetialMsg +import java.net.URLDecoder + + +data class QrBean( + // 二维码版本 + val version: Int, + // 第一个版本 + val orderNo: String = "", // 订单Id + val uid: String = "",// 服务器端唯一码 + val phone: String = "",// 手机号码 + val bizType: Int = 0,// + val pipe: String = "",// 渠道ehsafety mogogosafety + + // 第二个版本 + val expiryTime: Long = 0, // 二维码有效期 + val bookingTime: Long = 0,// 预定时间 + val lineId: Long = 0, // 线路id + val availableTimes: Int = 0,//总票数 + val ticketSize: Int = 0,// 票上几个人 + val ticketName: String = "",// 票的名称 + val tenantId: Long = 0,// 租户id + + val shiftsId: Long = 0,// 班车业务 任务id + val startStationId: Long = 0,// bus业务使用 开始站点名称 +) { + companion object { + + const val TAG = "QrBean" + + fun parse(payload: String?): QrBean? { + val queryParameterNames = parseQuery(payload) + return if (queryParameterNames.isNotEmpty()) {// version 1 和 version 2 + parseVersion1to2(queryParameterNames) + } else { + parseVersion3ton(payload) + } + } + + private fun parseVersion3ton(payload: String?):QrBean? { + payload?.let { + val split = it.split(",") + if(split.isEmpty()){ + return null + } + // 业务模式+版本号 + val typeAndVersion92 = split[0] + val tenantId92 = split[1] + val orderNo92 = split[2] + val uidCode = split[3] + val pipeCode = split[4] + val phoneCode = split[5] + val lineIdCode = split[6] + val expiryTimeCode = split[7] + val bookingTimeCode = split[8] + val availableTimesCode = split[9] + val ticketSize = split[10].toInt() ?:0 + + val ticketNameCode = split[11] + val shiftsIdCode = split[12] + val startStationIdCode = split[13] + + val base92ToBase10 = Radix91.base91ToBase10(typeAndVersion92).toString() + val bizTypeCode = base92ToBase10.substring(0,1) + val bizType = Product.getCodeFromWxQr(bizTypeCode) + val version = base92ToBase10.substring(1).toInt() + 2// 0 1 这两个版本在Android端定义 二维码从优化后开始 + val tenantId = Radix91.base91ToBase10(tenantId92) + val orderNo = Radix91.base91ToBase10(orderNo92).toString() + val uid = uidCode.substring(0, 8) + "-" + + uidCode.substring(8, 12) + "-" + + uidCode.substring(12, 16) + "-" + + uidCode.substring(16, 20) + "-" + + uidCode.substring(20, 32) // 构造一个标准的 UUID 字符串 + + val pipe = if (pipeCode.equals("1")) { + "mogogosafety" + } else { + "ehsafety" + } + val phoneLike = Radix91.base91ToBase10(phoneCode).toString() + val phone = if (RegexUtils.isMobileExact(phoneLike)) { + phoneLike + }else{ + phoneCode + } + val lineId = Radix91.base91ToBase10(lineIdCode) + val expiryTime = Radix91.base91ToBase10(expiryTimeCode) + val bookingTime = Radix91.base91ToBase10(bookingTimeCode) + val availableTimes = Radix91.base91ToBase10(availableTimesCode).toInt() + + val ticketName =when (ticketNameCode) { + "0" -> { + "单站票" + } + "1" -> { + "多站票" + } + "2" -> { + "全站票" + } + "3" -> { + "通勤票" + } + else -> { + URLDecoder.decode(ticketNameCode?:"","UTF-8") + } + } + + val shiftsId = Radix91.base91ToBase10(shiftsIdCode) + val startStationId = Radix91.base91ToBase10(startStationIdCode) + + return QrBean(version, orderNo, uid, phone, bizType, pipe, expiryTime, + bookingTime, lineId, availableTimes, ticketSize, ticketName, tenantId, + shiftsId, startStationId + ) + } + return null + } + + /** + * 解析第一和第二版本的二维码 + */ + private fun parseVersion1to2(params: MutableMap): QrBean? { + val expiryTime = params["expiryTime"] + val bookingTime = params["bookingTime"] + val lineId = params["lineId"] + val availableTimes = params["availableTimes"] + val orderNo = params["orderNo"] + val uid = params["uid"] + val phone = params["phone"] + val ticketSize = params["ticketSize"] + val ticketName = params["ticketName"] + val type = params["type"] + val pipe = params["pipe"] + val startStationId = params["startStationId"] + val tenantId = params["tenantId"] + val shiftsId = params["shiftsId"] + + if (orderNo is String && uid is String) { + var phoneNum = "" + if (phone is String) { + if (RegexUtils.isMobileExact(phone)) { + phoneNum = phone + }else{ + phoneNum = phone + } + } + var tempType = 0 + if (type is String) { + when (type) { + "shuttle" -> { + tempType = 11 + } + + "bus" -> { + tempType = 10 + } + + else -> { + tempType = type.toInt() ?: 0 + } + } + } else { + tempType = type?.toInt() ?: 0 + } + try { + val version = if (expiryTime != null && bookingTime != null && lineId != null) { + 1 + } else { + 0 + } + return QrBean( + version, orderNo, uid, phoneNum, tempType, pipe?:"", + expiryTime?.toLong() ?: 0, bookingTime?.toLong() ?: 0, + lineId?.toLong() ?: 0, availableTimes?.toInt() ?: 0, + ticketSize?.toInt() ?: 0, URLDecoder.decode(ticketName?:"","UTF-8"), + tenantId?.toLong() ?: 0, shiftsId?.toLong() ?: 0, + startStationId?.toLong() ?: 0 + ) + } catch (e: Exception) { + e.printStackTrace() + CallerLogger.d(M_OCHCOMMON + TAG, "") + // 通知司机屏二维码错误 + val writeOffDetail = WriteOffDetialMsg(code = 3001, msg = "出示错误二维码") + OchChainLogManager.writeChainLogWriteOff("核销失败", "二维码错误+参数错误") + CallerLogger.d( + M_OCHCOMMON + TAG, + "sendTaskDetailsToClients = " + GsonUtils.toJson(writeOffDetail) + ) + LanSocketManager.sendMsgToServer(writeOffDetail) + } + } + return null + } + + private fun parseQuery(query: String?): MutableMap { + val params: MutableMap = HashMap() + if (query != null && !query.isEmpty()) { + val pairs = query.split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + if(pairs.size>1) { + for (pair in pairs) { + val indexOfEquals = pair.indexOf("=") + if (indexOfEquals == -1) { + // 键无值 + params[pair] = "" + } else { + val key = pair.substring(0, indexOfEquals) + val value = pair.substring(indexOfEquals + 1) + params[key] = value + } + } + } + } + return params + } + } + +} \ No newline at end of file diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/Radix91.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/Radix91.kt new file mode 100644 index 0000000000..eea03704d1 --- /dev/null +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/Radix91.kt @@ -0,0 +1,58 @@ +package com.mogo.och.common.module.manager.scnner + +fun main() { + + val value10 = "337197925358633123".toLong() + val value92 = Radix91.decimalToBase91(value10) + val old = Radix91.base91ToBase10(value92) + println("value10:$value10") + println("value92:$value92") + println("old:$old") + //337197925358633123 + //$#WFaRgz} + + //1879008917469057024 + //3|bnEad7%o + + //1736825612443 + //2}M3l*@ + + //1736784000000 + //2}LF-wM + + //18811539480 + //2{R\zk + +} + +object Radix91 { + val base32Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^*()_-+=[]{};':./<>?`~|\\" + fun decimalToBase91(decimal: Long): String { + if (decimal == 0L) return "0" + var num = decimal + val base32 = StringBuilder() + while (num > 0) { + val remainder = num % 91 + base32.insert(0, base32Chars[remainder.toInt()]) + num /= 91 + } + return base32.toString() + } + fun base91ToBase10(base92Number: String): Long { + // 定义92进制的字符集 + var base10Number: Long = 0 + var power: Long = 1 + + // 从右到左遍历每一位 + for (char in base92Number.reversed()) { + val index = base32Chars.indexOf(char) + if (index == -1) { + throw IllegalArgumentException("无效的92进制字符: $char") + } + base10Number += index * power + power *= 91 + } + + return base10Number + } +} \ No newline at end of file diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/ScannerManager.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/ScannerManager.kt index 9aad74393d..580993345f 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/ScannerManager.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/ScannerManager.kt @@ -236,19 +236,11 @@ object ScannerManager : IOchLanPassengerStatusListener { } fun parseParams(payload: String?) { - val parse = Uri.parse("${OchCommonConst.getShuttleUrl()}?${payload}") - val queryParameterNames = parse.queryParameterNames - val mutableMapOf = mutableMapOf() - queryParameterNames.forEach { - val queryParameter = parse.getQueryParameter(it) - if (it != null && queryParameter != null) { - mutableMapOf[it] = queryParameter - } - } - if (mutableMapOf.isNotEmpty()) { + val qrBean = QrBean.parse(payload) + if (qrBean!=null) { if (stateChanageListeners.size > 0) { stateChanageListeners.forEach { - it.value.parseData(mutableMapOf, payload) + it.value.parseData(qrBean) } } } else { diff --git a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/StateChangeListener.kt b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/StateChangeListener.kt index 6652b71e34..3e3d53e692 100644 --- a/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/StateChangeListener.kt +++ b/OCH/common/common/src/main/java/com/mogo/och/common/module/manager/scnner/StateChangeListener.kt @@ -2,5 +2,5 @@ package com.mogo.och.common.module.manager.scnner interface StateChangeListener { fun stateChange(newBindValue: BindStatus, newOpentValue: OpenStatus){} - fun parseData(params: MutableMap, payload: String?){} + fun parseData(qrBean: QrBean){} } \ No newline at end of file diff --git a/OCH/common/common/src/test/java/com/mogo/och/common/module/QrUnitTest.kt b/OCH/common/common/src/test/java/com/mogo/och/common/module/QrUnitTest.kt new file mode 100644 index 0000000000..f1b015be44 --- /dev/null +++ b/OCH/common/common/src/test/java/com/mogo/och/common/module/QrUnitTest.kt @@ -0,0 +1,73 @@ +package com.mogo.och.common.module + +import com.mogo.och.common.module.manager.scnner.QrBean +import com.mogo.och.common.module.manager.scnner.Radix91 +import org.junit.Test + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +open class QrUnitTest { + + @Test + fun testData() { + // 构建二维码信息 + val type = 1 + val version = 0 + val typeVersion = Radix91.decimalToBase91("$type${version.toString().padStart(2,'0')}".toLong()) + val tenantId = 233602957696827483 + val tenantldEncode = Radix91.decimalToBase91(tenantId) + val orderNo = 1889600789505798144 + val orderNoEncode = Radix91.decimalToBase91(orderNo) + val uid = "81ab22c914cb0ea286371c0d7e364ab8" + val pipe = "1" + val phone = 18811539480 + val phoneEncode = Radix91.decimalToBase91(phone) + val lineId = 85L + val lineIdEncode = Radix91.decimalToBase91(lineId) + val expiryTime = System.currentTimeMillis() + val expiryTimeEncode = Radix91.decimalToBase91(expiryTime) + val bookingTime = 1739289600000 + val bookingTimeEncode = Radix91.decimalToBase91(bookingTime) + val availableTimes = "1" + val ticketSize = "1" + val ticketName = "%E5%85%A8%E7%AB%99%E7%A5%A8" + val shiftsId = 3422L + val shiftsIdEncode = Radix91.decimalToBase91(shiftsId) + val startStationId = 3466L + val startStationIdEncode = Radix91.decimalToBase91(startStationId) + + val qrInfo2 = "$typeVersion,$tenantldEncode,$orderNoEncode,$uid,$pipe,$phoneEncode,$lineIdEncode,$expiryTimeEncode,$bookingTimeEncode,$availableTimes,$ticketSize,$ticketName,$shiftsIdEncode,$startStationIdEncode" + + println(qrInfo2) + val qrBean2 = QrBean.parse(qrInfo2) + + println("${type}_${qrBean2?.bizType}") + println("${version}_${qrBean2?.version}") + println("${tenantId}_${qrBean2?.tenantId}") + println("${orderNo}_${qrBean2?.orderNo}") + println("${uid}_${qrBean2?.uid}") + println("${pipe}_${qrBean2?.pipe}") + println("${phone}_${qrBean2?.phone}") + println("${lineId}_${qrBean2?.lineId}") + println("${expiryTime}_${qrBean2?.expiryTime}") + println("${bookingTime}_${qrBean2?.bookingTime}") + println("${availableTimes}_${qrBean2?.availableTimes}") + println("${ticketSize}_${qrBean2?.ticketSize}") + println("${ticketName}_${qrBean2?.ticketName}") + println("${shiftsId}_${qrBean2?.shiftsId}") + println("${startStationId}_${qrBean2?.startStationId}") + + + val qrInfo1 = "orderNo=1871744897569038336&uid=828aa91f-49a1-f9b3-4526-f58acda9df60&pipe=mogogosafety&phone=houyanli&lineId=134&expiryTime=1735094149070&bookingTime=1735056000000&tenantId=337197925358633123&availableTimes=1&ticketSize=1&ticketName=%E9%80%9A%E5%8B%A4%E7%A5%A8%E3%81%AE&type=14&shiftsId=4249" + val qrBean1 = QrBean.parse(qrInfo1) + println(qrBean1) + + val qrInfo0 = "orderNo=1878747772463988736&uid=4fda39cf-27a7-b49e-52ec-c566c3bc2fb8&type=shuttle&pipe=ehsafety&phone=13534015919" + val qrBean0 = QrBean.parse(qrInfo0) + println(qrBean0) + } + +} \ No newline at end of file diff --git a/OCH/shuttle/passenger_weaknet/src/main/java/com/mogo/och/shuttle/weaknet/passenger/model/TicketModel.kt b/OCH/shuttle/passenger_weaknet/src/main/java/com/mogo/och/shuttle/weaknet/passenger/model/TicketModel.kt index 4227ac0e66..ad328e60eb 100644 --- a/OCH/shuttle/passenger_weaknet/src/main/java/com/mogo/och/shuttle/weaknet/passenger/model/TicketModel.kt +++ b/OCH/shuttle/passenger_weaknet/src/main/java/com/mogo/och/shuttle/weaknet/passenger/model/TicketModel.kt @@ -4,10 +4,10 @@ import android.annotation.SuppressLint import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS_P import com.mogo.eagle.core.utilcode.util.GsonUtils -import com.mogo.eagle.core.utilcode.util.RegexUtils import com.mogo.och.common.module.manager.bluetooth.BleManager import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager import com.mogo.och.common.module.manager.loop.BizLoopManager +import com.mogo.och.common.module.manager.scnner.QrBean import com.mogo.och.common.module.manager.socket.lan.LanSocketManager import com.mogo.och.common.module.manager.scnner.ScannerManager import com.mogo.och.common.module.manager.scnner.StateChangeListener @@ -16,7 +16,6 @@ import com.mogo.och.common.module.manager.socket.lan.bean.DPMsgType import com.mogo.och.common.module.manager.socket.lan.bean.WriteOffDetialMsg import com.mogo.och.common.module.manager.socket.lan.bean.WriteOffResultMsg import com.mogo.och.common.module.utils.RxUtils -import java.net.URLDecoder object TicketModel : StateChangeListener { @@ -79,63 +78,23 @@ object TicketModel : StateChangeListener { LanSocketManager.unRegisterSocketMessageListener(DPMsgType.TYPE_WRITEOFF_INFO_RESULT.type,writeOffResultMsg) } - override fun parseData(params: MutableMap, payload: String?) { - val expiryTime = params["expiryTime"] - val bookingTime = params["bookingTime"] - val lineId = params["lineId"] - val availableTimes = params["availableTimes"] - val orderNo = params["orderNo"] - val uid = params["uid"] - val phone = params["phone"] - val ticketSize = params["ticketSize"] - val ticketName = params["ticketName"] - val type = params["type"] - val pipe = params["pipe"] - val startStationId = params["startStationId"] - val tenantId = params["tenantId"] - val shiftsId = params["shiftsId"] - - if(orderNo is String && uid is String){ - var phoneNum = "" - if(phone is String){ - if (RegexUtils.isMobileExact(phone)) { - phoneNum = phone - } - } + override fun parseData(qrBean: QrBean) { try { - var tempType = 0 - if (type is String) { - when (type) { - "shuttle" -> { - tempType = 11 - } - - "bus" -> { - tempType = 10 - } - - else -> { - tempType = type.toInt()?:0 - } - } - } else { - tempType = type?.toInt() ?: 0 - } val writeOffDetail = WriteOffDetialMsg(0,"", - expiryTime?.toLong()?:0, - bookingTime?.toLong()?:0, - lineId?.toLong()?:0, - availableTimes?.toInt()?:0, - orderNo, - uid, - phoneNum, - ticketSize?.toInt()?:0, - URLDecoder.decode(ticketName?:"","UTF-8"), - tempType, - shiftsId?.toLong()?:0, - pipe, - startStationId?.toLong()?:0, - tenantId?.toLong()?:0 + qrBean.expiryTime, + qrBean.bookingTime, + qrBean.lineId, + qrBean.availableTimes, + qrBean.orderNo, + qrBean.uid, + qrBean.phone, + qrBean.ticketSize, + qrBean.ticketName, + qrBean.bizType, + qrBean.shiftsId, + qrBean.pipe, + qrBean.startStationId, + qrBean.tenantId ) CallerLogger.d(M_BUS_P + TAG, "sendTaskDetailsToClients = " + GsonUtils.toJson(writeOffDetail)) LanSocketManager.sendMsgToServer(writeOffDetail) @@ -145,17 +104,11 @@ object TicketModel : StateChangeListener { CallerLogger.d(M_BUS_P + TAG, "") // 通知司机屏二维码错误 val writeOffDetail = WriteOffDetialMsg(code = 3001, msg = "出示错误二维码") - OchChainLogManager.writeChainLogWriteOff("核销失败","二维码错误+参数错误:${payload}") + OchChainLogManager.writeChainLogWriteOff("核销失败","二维码错误+参数错误") CallerLogger.d(M_BUS_P + TAG, "sendTaskDetailsToClients = " + GsonUtils.toJson(writeOffDetail)) LanSocketManager.sendMsgToServer(writeOffDetail) } - }else{ - // 通知司机屏二维码错误 - val writeOffDetail = WriteOffDetialMsg(code = 3001, msg = "出示错误二维码") - OchChainLogManager.writeChainLogWriteOff("核销失败","二维码错误+参数错误:${payload}") - CallerLogger.d(M_BUS_P + TAG, "sendTaskDetailsToClients = " + GsonUtils.toJson(writeOffDetail)) - LanSocketManager.sendMsgToServer(writeOffDetail) - } + } fun getBleName(phone: String):String{ diff --git a/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/mogo/AppIdentityModeUtils.kt b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/mogo/AppIdentityModeUtils.kt index 1373c412ce..bbb1fc93b2 100644 --- a/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/mogo/AppIdentityModeUtils.kt +++ b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/mogo/AppIdentityModeUtils.kt @@ -389,6 +389,17 @@ enum class Product(val code: Int) { SCHEDULED -> AppIdentityModeUtils.SCHEDULED } } + + fun getCodeFromWxQr(bizTypeCode: String): Int { + return when (bizTypeCode) { + "0" -> BUS.code + "1" -> SHUTTLE.code + "2" -> TAXI.code + "3" -> CHARTER.code + "4" -> SCHEDULED.code + else -> {0} + } + } } }