feat(general): 新增卡片操作类型并优化写卡逻辑
- 新增 CardOperationType 密封类,用于区分不同的卡片操作类型
- 修改工本费输入类型为整数,提高用户体验
- 优化用户卡数据写入逻辑,确保数据长度正确
-修复清零卡和开卡的写卡流程,增加订单号和操作类型支持
- 优化数据传输格式,提高系统稳定性
| | |
| | | mfc.connect(); |
| | | // 验证扇区密码 |
| | | boolean isOpen = false; |
| | | for (int i = 0; i < listKeyA.size(); i++) { |
| | | if (mfc.authenticateSectorWithKeyA(a, listKeyA.get(i))) { |
| | | isOpen = true; |
| | | if (listKeyA.get(i).equals(defauleKey)) { |
| | | // 当前为默认白卡密码时写卡时修改密码 |
| | | changePasword(a, mfc); |
| | | |
| | | if (listKeyA.size() != 0) { |
| | | for (int i = 0; i < listKeyA.size(); i++) { |
| | | if (mfc.authenticateSectorWithKeyA(a, listKeyA.get(i))) { |
| | | isOpen = true; |
| | | if (listKeyA.get(i).equals(defauleKey)) { |
| | | // 当前为默认白卡密码时写卡时修改密码 |
| | | changePasword(a, mfc); |
| | | } |
| | | break; |
| | | } |
| | | break; |
| | | } |
| | | } else if (listA_PS.size() != 0 && listA_PS.size() > a) { |
| | | if (mfc.authenticateSectorWithKeyA(a, defauleKey)) { |
| | | isOpen = true; |
| | | |
| | | } else if (mfc.authenticateSectorWithKeyA(a, listA_PS.get(a))) { |
| | | isOpen = true; |
| | | } |
| | | } |
| | | if (isOpen) { |
| | |
| | | boolean isOpen = false; |
| | | if (listKeyA.size() != 0) { |
| | | for (int i = 0; i < listKeyA.size(); i++) { |
| | | if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) { |
| | | if (mfc.authenticateSectorWithKeyA(a, listKeyA.get(i))) { |
| | | isOpen = true; |
| | | if (listKeyA.get(i).equals(defauleKey)) { |
| | | // 当前为默认白卡密码时写卡时修改密码 |
| | |
| | | /** |
| | | * 修改密码 |
| | | * |
| | | * @param 书写的扇区 |
| | | * @param passWord 密码 |
| | | * @return |
| | | */ |
| | |
| | | import com.dayu.baselibrary.view.TitleBar.ClickType_LEFT_IMAGE |
| | | import com.dayu.general.databinding.ActivityManageListGeBinding |
| | | import com.dayu.general.tool.CardCommon |
| | | import com.dayu.general.tool.CardOperationType |
| | | |
| | | class ManageListActivity : BaseActivity() { |
| | | |
| | |
| | | binding?.tvCleanCard?.setOnClickListener { |
| | | var intent = Intent(this, ManagerReadActivity::class.java).apply { |
| | | putExtra("cardType", CardCommon.CLEAN_CARD_TYPE) |
| | | putExtra("operationTypeCode", CardOperationType.CleanCard.code) |
| | | } |
| | | |
| | | startActivity(intent) |
| | | } |
| | | binding?.tvCheckCard?.setOnClickListener { |
| | | var intent = Intent(this, ManagerReadActivity::class.java).apply { |
| | | putExtra("cardType", CardCommon.CHECK_CARD) |
| | | putExtra("operationTypeCode", CardCommon.CHECK_CARD) |
| | | putExtra("operationTypeCode", CardOperationType.CheckCard.code) |
| | | } |
| | | startActivity(intent) |
| | | } |
| | |
| | | import android.widget.Toast |
| | | import androidx.lifecycle.lifecycleScope |
| | | import com.dayu.baselibrary.net.subscribers.SubscriberListener |
| | | import com.dayu.baselibrary.utils.MornyUtil |
| | | import com.dayu.baselibrary.view.TitleBar.ClickType_LEFT_IMAGE |
| | | import com.dayu.general.BaseApplication |
| | | import com.dayu.general.R |
| | |
| | | import com.dayu.general.net.ApiManager |
| | | import com.dayu.general.net.BaseResponse |
| | | import com.dayu.general.tool.CardCommon.Companion.USER_CARD_TYPE_1 |
| | | import com.dayu.general.tool.CardOperationType |
| | | import com.dayu.general.tool.NfcReadHelper |
| | | import com.dayu.general.tool.NfcWreatHelper |
| | | import com.dayu.general.utils.DateUtils |
| | |
| | | |
| | | // 获取工本费 |
| | | val cardFeeStr = binding.newCardCardFee.text.toString() |
| | | val cardFee = if (cardFeeStr.isEmpty()) 0.0 else cardFeeStr.toDouble() |
| | | |
| | | // 格式化金额为两位小数 |
| | | val formattedRechargeAmount = String.format("%.2f", rechargeAmount) |
| | | val formattedCardFee = String.format("%.2f", cardFee) |
| | | val cardFee = if (cardFeeStr.isEmpty()) 0 else cardFeeStr.toInt() |
| | | |
| | | val remark = binding.newCardRemark.text.toString() |
| | | |
| | |
| | | putExtra("orderId", orderId) |
| | | putExtra("cardAddr", cardPhysicalId) |
| | | var userCard = UserCard() |
| | | userCard.areaNumber =clientInfo.districtNum |
| | | userCard.areaNumber = response.content?.cardNum?.substring(0, 12).toString() |
| | | userCard.userCode =clientInfo.clientNum |
| | | userCard.phoneNumber =clientInfo.phone |
| | | userCard.userCodeNumber = response.content?.cardNum?.toInt()!! |
| | | userCard.projectCode = response.content?.projectNo?.toInt()!! |
| | | userCard.balance = response.content?.balance?.toInt()!! |
| | | userCard.userCodeNumber = response.content?.cardNum?.substring(12)?.toInt()!! |
| | | userCard.projectCode = response.content?.projectNo!! |
| | | userCard.balance = MornyUtil.changeY2F(response.content?.balance) |
| | | // userCard.surplusWater = response.content?.surplusWater?.toInt()!! |
| | | userCard.waterPrice = response.content?.waterPrice?.toFloat()!! |
| | | // userCard.electricPrice = response.content?.electricPrice?.toFloat()!! |
| | | userCard.rechargeDate = DateUtils.parseStringToCalendar(response.content?.time) |
| | | putExtra("userCard", userCard) |
| | | putExtra("operationTypeCode", CardOperationType.OpenCard.code) |
| | | putExtra("orderNumber", response.content?.orderNo) |
| | | putExtra("cardFee", cardFee) |
| | | startActivity(this) |
| | | } |
| | | } catch (e: Exception) { |
| | |
| | | import com.dayu.general.bean.card.ClearCard |
| | | import com.dayu.general.bean.card.UserCard |
| | | import com.dayu.general.tool.CardCommon |
| | | import com.dayu.general.tool.CardOperationType |
| | | import com.dayu.general.databinding.ActivityNfcWriteGeBinding |
| | | import com.dayu.general.net.ApiManager |
| | | import com.dayu.general.net.BaseResponse |
| | |
| | | import com.dayu.general.dao.BaseDaoSingleton |
| | | import com.tencent.bugly.crashreport.CrashReport |
| | | import kotlinx.coroutines.launch |
| | | import java.lang.StringBuilder |
| | | |
| | | /** |
| | | * @author: zuo |
| | |
| | | var cardType = "" |
| | | var orderId = "" |
| | | var cardAddr = "" |
| | | var cardFee = 0 |
| | | |
| | | //订单编号 |
| | | var orderNumber = "" |
| | | private lateinit var userCard: UserCard |
| | | private var operationTypeCode = -1; |
| | | private var operationType: CardOperationType? = null |
| | | |
| | | override fun onCreate(savedInstanceState: Bundle?) { |
| | | super.onCreate(savedInstanceState) |
| | |
| | | cardType = intent?.getStringExtra("cardType") ?: "" |
| | | orderId = intent?.getStringExtra("orderId") ?: "" |
| | | cardAddr = intent?.getStringExtra("cardAddr") ?: "" |
| | | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) { |
| | | userCard = intent?.getSerializableExtra("userCard", UserCard::class.java)!! |
| | | } else { |
| | | userCard = (intent?.getSerializableExtra("userCard") as? UserCard)!! |
| | | operationTypeCode = intent?.getIntExtra("operationTypeCode", -1) ?: -1 |
| | | operationType = CardOperationType.fromCode(operationTypeCode) |
| | | if (intent?.hasExtra("cardFee") == true) { |
| | | cardFee = intent?.getIntExtra("cardFee", 0) ?: 0 |
| | | } |
| | | if (intent?.hasExtra("userCard") == true) { |
| | | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) { |
| | | userCard = intent?.getSerializableExtra("userCard", UserCard::class.java)!! |
| | | } else { |
| | | userCard = (intent?.getSerializableExtra("userCard") as? UserCard)!! |
| | | } |
| | | |
| | | if (cardType.isNotEmpty()) { |
| | | when (cardType) { |
| | | CardCommon.CLEAN_CARD_TYPE -> { |
| | | } |
| | | if (operationTypeCode != -1) { |
| | | when (operationType) { |
| | | CardOperationType.CleanCard -> { |
| | | binding?.cardData?.text = "清零卡写卡" |
| | | } |
| | | |
| | | CardOperationType.OpenCard -> { |
| | | var textData = StringBuilder() |
| | | textData.append("用户开卡\n") |
| | | if (cardFee != 0) { |
| | | textData.append("工本费:" + cardFee + "元\n") |
| | | } |
| | | if (userCard.balance != 0) { |
| | | textData.append("充值金额:" + userCard.balance + "元") |
| | | } |
| | | |
| | | binding?.cardData?.text = textData.toString() |
| | | } |
| | | |
| | | CardOperationType.CancelCard -> TODO() |
| | | CardOperationType.CheckCard -> TODO() |
| | | CardOperationType.DeductCard -> TODO() |
| | | CardOperationType.Recharge -> TODO() |
| | | CardOperationType.ReplaceCard -> TODO() |
| | | null -> TODO() |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | override fun onNfcBack(intent: Intent) { |
| | | val nfcReadHelper = NfcReadHelper.getInstance(intent, this) |
| | | val cardNumber = nfcReadHelper.getCardNumberNoClose() |
| | | // 使用正常的getCardNumber()方法,它会自动关闭连接 |
| | | val cardNumber = nfcReadHelper.getCardNumber() |
| | | |
| | | if (cardNumber.isNotEmpty() && cardNumber == cardAddr) { |
| | | val nfcWreatHelper = NfcWreatHelper.getInstance(intent, this) |
| | | when (cardType) { |
| | | CardCommon.CLEAN_CARD_TYPE -> { |
| | | when (operationType) { |
| | | CardOperationType.CleanCard -> { |
| | | var clearCard = ClearCard() |
| | | nfcWreatHelper.writeData(clearCard.getZeroBytes(), 7, 0) { success, message -> |
| | | if (success) { |
| | | postCardData(cardType, cardAddr, "") |
| | | // 写卡成功后更新数据库中的isCardWritten状态 |
| | | updateCardWrittenStatus(cardAddr) |
| | | ToastUtil.show("写卡成功!") |
| | | // 处理写卡成功的情况 |
| | | } else { |
| | | // 处理写卡失败的情况 |
| | | ToastUtil.show(message) |
| | | // 确保Toast在主线程中调用 |
| | | runOnUiThread { |
| | | if (success) { |
| | | postCardData(cardType, cardAddr) |
| | | // 写卡成功后更新数据库中的isCardWritten状态 |
| | | updateCardWrittenStatus(cardAddr) |
| | | ToastUtil.show("写卡成功!") |
| | | // 处理写卡成功的情况 |
| | | } else { |
| | | // 处理写卡失败的情况 |
| | | ToastUtil.show(message) |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | CardCommon.USER_CARD_TYPE_1 -> { |
| | | binding?.cardData?.text = "写用户卡" |
| | | CardOperationType.OpenCard -> { |
| | | nfcWreatHelper.writeUserDataAsync(userCard, object : NFCCallBack { |
| | | override fun isSusses(flag: Boolean, msg: String?) { |
| | | if (flag) { |
| | | // 写卡成功后更新数据库中的isCardWritten状态 |
| | | updateCardWrittenStatus(cardAddr) |
| | | ToastUtil.show("写卡成功!") |
| | | } else { |
| | | ToastUtil.show("写卡失败: ${msg ?: "未知错误"}") |
| | | // 确保Toast在主线程中调用 |
| | | runOnUiThread { |
| | | if (flag) { |
| | | // 写卡成功后更新数据库中的isCardWritten状态 |
| | | updateCardWrittenStatus(cardAddr) |
| | | ToastUtil.show("写卡成功!") |
| | | } else { |
| | | ToastUtil.show("写卡失败: ${msg ?: "未知错误"}") |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | |
| | | } |
| | | |
| | | CardOperationType.CancelCard -> TODO() |
| | | CardOperationType.CheckCard -> TODO() |
| | | CardOperationType.DeductCard -> TODO() |
| | | CardOperationType.Recharge -> TODO() |
| | | CardOperationType.ReplaceCard -> TODO() |
| | | null -> TODO() |
| | | } |
| | | } else { |
| | | ToastUtil.show("卡片错误,当前刷的卡与刚刚的卡不一致") |
| | |
| | | try { |
| | | val cardRegistrationDao = BaseDaoSingleton.getInstance(this@NfcWreatActivity) |
| | | .cardRegistrationDao() |
| | | |
| | | |
| | | // 根据卡号查找CardRegistrationBean记录 |
| | | val cardRegistration = cardRegistrationDao.getByCardNumber(cardNumber) |
| | | if (cardRegistration != null) { |
| | |
| | | } |
| | | } |
| | | |
| | | fun postCardData(cardType: String, cardAddr: String, remark: String) { |
| | | fun postCardData(cardType: String, cardAddr: String) { |
| | | when (cardType) { |
| | | CardCommon.CHECK_CARD -> { |
| | | binding?.cardData?.text = "写用户卡" |
| | |
| | | map["cardAddr"] = cardAddr |
| | | } |
| | | |
| | | if (cardType.isNotEmpty()) { |
| | | // map["cardType"] = cardType |
| | | map["operateType"] = "1" |
| | | } |
| | | if (remark.isNotEmpty()) { |
| | | map["remarks"] = remark |
| | | map["operateType"] = operationTypeCode |
| | | if (orderNumber.isNotEmpty()) { |
| | | map["orderNumber"] = orderNumber |
| | | } |
| | | // 使用正确的类型参数 |
| | | ApiManager.getInstance().requestPostLoading( |
| | | this, |
| | | "/sell/card/call_back", |
| | | "terminal/card/termCallBack", |
| | | String::class.java, |
| | | map, |
| | | object : SubscriberListener<BaseResponse<String>>() { |
| | |
| | | val data = ByteArray(16) |
| | | try { |
| | | // 设置国家行政区域号(BCD格式,6字节,0-5位) |
| | | val areaCodeBytes = BcdUtil.strToBcd(String.format("%012d", areaNumber)) |
| | | System.arraycopy(areaCodeBytes, 0, data, 0, 6) |
| | | val areaNumberStr = if (areaNumber.isBlank() || !areaNumber.all { it.isDigit() }) { |
| | | "000000000000" |
| | | } else { |
| | | areaNumber.padStart(12, '0') |
| | | } |
| | | val areaCodeBytes = BcdUtil.strToBcd(areaNumberStr) |
| | | System.arraycopy(areaCodeBytes, 0, data, 0, minOf(areaCodeBytes.size, 6)) |
| | | |
| | | // 设置用户卡编号(HEX格式,2字节,6-7位) |
| | | // 设置用户卡编号(HEX格式,2字节,6-7位) - 修复:确保数组长度正确 |
| | | val userCodeBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(userCodeNumber)) |
| | | System.arraycopy(userCodeBytes, 0, data, 6, 2) |
| | | val userCodePadded = ByteArray(2) |
| | | System.arraycopy(userCodeBytes, 0, userCodePadded, 0, minOf(userCodeBytes.size, 2)) |
| | | System.arraycopy(userCodePadded, 0, data, 6, 2) |
| | | |
| | | // 设置卡类型(8位) |
| | | data[8] = HexUtil.hexToByte(cardType) |
| | | |
| | | // 设置手机号(BCD格式,6字节,9-14位) |
| | | val phoneBytes = BcdUtil.strToBcd(phoneNumber.padStart(12, '0')) |
| | | System.arraycopy(phoneBytes, 0, data, 9, 6) |
| | | System.arraycopy(phoneBytes, 0, data, 9, minOf(phoneBytes.size, 6)) |
| | | |
| | | // 设置校验和(15位) |
| | | data[15] = getByteSum(data) |
| | |
| | | try { |
| | | data[0] = projectCode.toByte() |
| | | |
| | | // 设置余额 |
| | | val balanceBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(balance)) |
| | | System.arraycopy(balanceBytes, 0, data, 1, 4) |
| | | // 设置余额 - 修复:确保数组长度正确 |
| | | val balanceHex = HexUtil.get10To16LowHigh(balance) |
| | | val balanceBytes = HexUtil.hexToByteArray(balanceHex) |
| | | val balancePadded = ByteArray(4) |
| | | System.arraycopy(balanceBytes, 0, balancePadded, 0, minOf(balanceBytes.size, 4)) |
| | | System.arraycopy(balancePadded, 0, data, 1, 4) |
| | | |
| | | // 设置剩余水量 |
| | | val waterBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(surplusWater)) |
| | | System.arraycopy(waterBytes, 0, data, 5, 4) |
| | | // 设置剩余水量 - 修复:确保数组长度正确 |
| | | val waterHex = HexUtil.get10To16LowHigh(surplusWater) |
| | | val waterBytes = HexUtil.hexToByteArray(waterHex) |
| | | val waterPadded = ByteArray(4) |
| | | System.arraycopy(waterBytes, 0, waterPadded, 0, minOf(waterBytes.size, 4)) |
| | | System.arraycopy(waterPadded, 0, data, 5, 4) |
| | | |
| | | // 设置电价 |
| | | // 设置电价 - 修复:确保数组长度正确 |
| | | val priceBytes = HexUtil.hexToByteArray(HexUtil.floatToHexLowHigh(electricPrice)) |
| | | System.arraycopy(priceBytes, 0, data, 9, 2) |
| | | val pricePadded = ByteArray(2) |
| | | System.arraycopy(priceBytes, 0, pricePadded, 0, minOf(priceBytes.size, 2)) |
| | | System.arraycopy(pricePadded, 0, data, 9, 2) |
| | | |
| | | // 设置充值时间 |
| | | rechargeDate?.let { |
| | |
| | | fun toBytes(): ByteArray { |
| | | val data = ByteArray(16) |
| | | try { |
| | | // 备份余额和水量数据 |
| | | val balanceBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(balance)) |
| | | System.arraycopy(balanceBytes, 0, data, 1, 4) |
| | | // 备份余额和水量数据 - 修复:确保数组长度正确 |
| | | val balanceHex = HexUtil.get10To16LowHigh(balance) |
| | | val balanceBytes = HexUtil.hexToByteArray(balanceHex) |
| | | val balancePadded = ByteArray(4) |
| | | System.arraycopy(balanceBytes, 0, balancePadded, 0, minOf(balanceBytes.size, 4)) |
| | | System.arraycopy(balancePadded, 0, data, 1, 4) |
| | | |
| | | val waterBytes = HexUtil.hexToByteArray(HexUtil.get10To16LowHigh(surplusWater)) |
| | | System.arraycopy(waterBytes, 0, data, 5, 4) |
| | | val waterHex = HexUtil.get10To16LowHigh(surplusWater) |
| | | val waterBytes = HexUtil.hexToByteArray(waterHex) |
| | | val waterPadded = ByteArray(4) |
| | | System.arraycopy(waterBytes, 0, waterPadded, 0, minOf(waterBytes.size, 4)) |
| | | System.arraycopy(waterPadded, 0, data, 5, 4) |
| | | |
| | | // 设置水价 |
| | | // 设置水价 - 修复:确保数组长度正确 |
| | | val priceBytes = HexUtil.hexToByteArray(HexUtil.floatToHexLowHigh(waterPrice)) |
| | | System.arraycopy(priceBytes, 0, data, 9, 2) |
| | | val pricePadded = ByteArray(2) |
| | | System.arraycopy(priceBytes, 0, pricePadded, 0, minOf(priceBytes.size, 2)) |
| | | System.arraycopy(pricePadded, 0, data, 9, 2) |
| | | |
| | | // 设置充值时间 |
| | | rechargeDate?.let { |
| | |
| | | val userName: String, // 姓名 |
| | | val idCard: String, // 身份证号 |
| | | val clientId: String, // 农户Id |
| | | val cardFee: Double, // 工本费 |
| | | val cardFee: Int, // 工本费 |
| | | val remark: String, // 备注 |
| | | val paymentMethod: Int, // 支付方式 |
| | | val orderId: String? = null, // 订单id,初始为null,后续更新 |
| | |
| | | package com.dayu.general.bean.net |
| | | |
| | | data class NewCardDataResult( |
| | | var projectNo: String, |
| | | var projectNo: Int, |
| | | var cardNum: String, |
| | | var balance: String, |
| | | var waterPrice: String, |
New file |
| | |
| | | package com.dayu.general.tool |
| | | |
| | | /** |
| | | * 卡片操作类型 |
| | | * 用于区分不同的卡片操作 |
| | | */ |
| | | sealed class CardOperationType(val code: Int, val description: String) { |
| | | object OpenCard : CardOperationType(1, "开卡") |
| | | object Recharge : CardOperationType(2, "充值") |
| | | object CancelCard : CardOperationType(3, "销卡") |
| | | object ReplaceCard : CardOperationType(4, "补卡") |
| | | object DeductCard : CardOperationType(5, "补扣") |
| | | object CleanCard : CardOperationType(6, "清零卡") |
| | | object CheckCard : CardOperationType(7, "检查卡") |
| | | |
| | | companion object { |
| | | fun fromCode(code: Int): CardOperationType? { |
| | | return when (code) { |
| | | 1 -> OpenCard |
| | | 2 -> Recharge |
| | | 3 -> CancelCard |
| | | 4 -> ReplaceCard |
| | | 5 -> DeductCard |
| | | else -> null |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | android:layout_height="wrap_content" |
| | | android:background="@null" |
| | | android:hint="请输入工本费(选填)" |
| | | android:inputType="numberDecimal" |
| | | android:inputType="number" |
| | | android:textColor="#333333" |
| | | android:textColorHint="#BBBBBB" |
| | | android:textSize="@dimen/new_card_size" /> |