[fea]
[二维码压缩升级]
This commit is contained in:
yangyakun
2025-02-12 17:21:47 +08:00
parent 1f340820bf
commit 57e21e13aa
7 changed files with 391 additions and 77 deletions

View File

@@ -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<String, String>): 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<String, String> {
val params: MutableMap<String, String> = 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
}
}
}

View File

@@ -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
}
}

View File

@@ -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<String, String>()
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 {

View File

@@ -2,5 +2,5 @@ package com.mogo.och.common.module.manager.scnner
interface StateChangeListener {
fun stateChange(newBindValue: BindStatus, newOpentValue: OpenStatus){}
fun parseData(params: MutableMap<String, String>, payload: String?){}
fun parseData(qrBean: QrBean){}
}

View File

@@ -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)
}
}

View File

@@ -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<String, String>, 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{

View File

@@ -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}
}
}
}
}