feat(nfc): 新增用户卡写入功能并优化开卡流程
- 新增用户卡写入功能,支持异步写卡- 优化开卡流程,增加订单号和用户信息传递
- 修复部分数据类型不匹配问题
- 优化异常处理和日志记录
 
	
	
	
	
	
	
	
	
	
	
	
	
	
 |  |  | 
 |  |  |  | 
 |  |  |     private static NativeNfcWriteHelper helper; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     public void setIntent(Intent intent) { | 
 |  |  |         this.tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); | 
 |  |  |     } | 
 |  |  | 
 |  |  |         return helper; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 写卡 | 
 |  |  |      * | 
 |  |  | 
 |  |  |                 MifareClassic mfc = MifareClassic.get(tag); | 
 |  |  |                 if (null != mfc) { | 
 |  |  |                     try { | 
 |  |  |                         //连接NFC | 
 |  |  |                         // 连接NFC | 
 |  |  |                         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); | 
 |  |  |                                 } | 
 |  |  |                                 break; | 
 |  |  | 
 |  |  |                                     data = userCard.getTwoBytes(); | 
 |  |  |                                 } | 
 |  |  |                                 int bIndex = mfc.sectorToBlock(a); | 
 |  |  |                                 //写卡 | 
 |  |  |                                 // 写卡 | 
 |  |  |                                 mfc.writeBlock(bIndex + b, data); | 
 |  |  |                             } | 
 |  |  |                             return true; | 
 |  |  | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 写卡(带回调) | 
 |  |  |      * | 
 |  |  |      * @param userCard 用户卡内容 | 
 |  |  |      * @param sector   扇区 | 
 |  |  |      * @param callBack 回调接口 | 
 |  |  |      */ | 
 |  |  |     public boolean writeUserData(BaseUserCardCard userCard, int sector, NFCCallBack callBack) { | 
 |  |  |         if (userCard != null) { | 
 |  |  |             int a = sector; | 
 |  |  |             try { | 
 |  |  |                 MifareClassic mfc = MifareClassic.get(tag); | 
 |  |  |                 if (null != mfc) { | 
 |  |  |                     try { | 
 |  |  |                         // 连接NFC | 
 |  |  |                         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); | 
 |  |  |                                 } | 
 |  |  |                                 break; | 
 |  |  |                             } | 
 |  |  |                         } | 
 |  |  |                         if (isOpen) { | 
 |  |  |                             for (int b = 0; b < 3; b++) { | 
 |  |  |                                 byte[] data; | 
 |  |  |                                 if (b == 0) { | 
 |  |  |                                     data = userCard.getZeroBytes(); | 
 |  |  |                                 } else if (b == 1) { | 
 |  |  |                                     data = userCard.getOneBytes(); | 
 |  |  |                                 } else { | 
 |  |  |                                     data = userCard.getTwoBytes(); | 
 |  |  |                                 } | 
 |  |  |                                 int bIndex = mfc.sectorToBlock(a); | 
 |  |  |                                 // 写卡 | 
 |  |  |                                 mfc.writeBlock(bIndex + b, data); | 
 |  |  |                             } | 
 |  |  |                             if (callBack != null) { | 
 |  |  |                                 callBack.isSusses(true, "用户数据写入成功"); | 
 |  |  |                             } | 
 |  |  |                             return true; | 
 |  |  |                         } | 
 |  |  |                         if (callBack != null) { | 
 |  |  |                             callBack.isSusses(false, "扇区" + a + "密码验证失败"); | 
 |  |  |                         } | 
 |  |  |                         return false; | 
 |  |  |                     } catch (Exception e) { | 
 |  |  |                         e.printStackTrace(); | 
 |  |  |                         if (callBack != null) { | 
 |  |  |                             callBack.isSusses(false, "扇区" + a + "写卡异常: " + e.getMessage()); | 
 |  |  |                         } | 
 |  |  |                         return false; | 
 |  |  |                     } finally { | 
 |  |  |                         try { | 
 |  |  |                             mfc.close(); | 
 |  |  |                         } catch (IOException e) { | 
 |  |  |                             e.printStackTrace(); | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |             } catch (Exception e) { | 
 |  |  |                 e.printStackTrace(); | 
 |  |  |                 if (callBack != null) { | 
 |  |  |                     callBack.isSusses(false, "写卡异常: " + e.getMessage()); | 
 |  |  |                 } | 
 |  |  |                 return false; | 
 |  |  |             } | 
 |  |  |         } else { | 
 |  |  |             if (callBack != null) { | 
 |  |  |                 callBack.isSusses(false, "用户卡数据为空"); | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 写卡 | 
 |  |  | 
 |  |  |                 MifareClassic mfc = MifareClassic.get(tag); | 
 |  |  |                 if (null != mfc) { | 
 |  |  |                     try { | 
 |  |  |                         //连接NFC | 
 |  |  |                         // 连接NFC | 
 |  |  |                         if (isConnect) { | 
 |  |  |                             mfc.connect(); | 
 |  |  |                         } | 
 |  |  |                         //获取扇区数量 | 
 |  |  |                         // 获取扇区数量 | 
 |  |  |                         int count = mfc.getSectorCount(); | 
 |  |  |                         //如果传进来的扇区大了或者小了直接退出方法 | 
 |  |  |                         // 如果传进来的扇区大了或者小了直接退出方法 | 
 |  |  |                         if (a > count - 1 || a < 0) { | 
 |  |  |                             if (callBack != null) { | 
 |  |  |                                 callBack.isSusses(false, "扇区错误--" + a); | 
 |  |  |                             } | 
 |  |  |                             return false; | 
 |  |  |                         } | 
 |  |  |                         //获取写的扇区的块的数量 | 
 |  |  |                         // 获取写的扇区的块的数量 | 
 |  |  |                         int bCount = mfc.getBlockCountInSector(a); | 
 |  |  |                         //如果输入的块大了或者小了也是直接退出 | 
 |  |  |                         // 如果输入的块大了或者小了也是直接退出 | 
 |  |  |                         if (b > bCount - 1 || b < 0) { | 
 |  |  |                             if (callBack != null) { | 
 |  |  |                                 callBack.isSusses(false, "块区错误--" + b); | 
 |  |  |                             } | 
 |  |  |                             return false; | 
 |  |  |                         } | 
 |  |  |                         //验证扇区密码 | 
 |  |  |                         // 验证扇区密码 | 
 |  |  |                         boolean isOpen = false; | 
 |  |  |                         if (listKeyA.size() != 0) { | 
 |  |  |                             for (int i = 0; i < listKeyA.size(); i++) { | 
 |  |  |                                 if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) { | 
 |  |  |                                     isOpen = true; | 
 |  |  |                                     if (listKeyA.get(i).equals(defauleKey)) { | 
 |  |  |                                         //当前为默认白卡密码时写卡时修改密码 | 
 |  |  |                                         // 当前为默认白卡密码时写卡时修改密码 | 
 |  |  |                                         changePasword(a, mfc); | 
 |  |  |                                     } | 
 |  |  |                                     break; | 
 |  |  | 
 |  |  |                         } | 
 |  |  |                         if (isOpen) { | 
 |  |  |                             int bIndex = mfc.sectorToBlock(a); | 
 |  |  |                             //写卡 | 
 |  |  |                             // 写卡 | 
 |  |  |                             mfc.writeBlock(bIndex + b, str); | 
 |  |  |                             // 校验写入数据是否正确 | 
 |  |  |                             boolean isVerified = true; | 
 |  |  | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 修改密码 | 
 |  |  |      * | 
 |  |  |      * @param         书写的扇区 | 
 |  |  |      * @param 书写的扇区 | 
 |  |  |      * @param passWord 密码 | 
 |  |  |      * @return | 
 |  |  |      */ | 
 |  |  |     public boolean changePasword( List<byte[]> passWord, boolean isConnect, boolean isClose, NFCCallBack callBack) { | 
 |  |  |         if (passWord == null || passWord.size()!=16) { | 
 |  |  |     public boolean changePasword(List<byte[]> passWord, boolean isConnect, boolean isClose, NFCCallBack callBack) { | 
 |  |  |         if (passWord == null || passWord.size() != 16) { | 
 |  |  |             if (callBack != null) { | 
 |  |  |                 callBack.isSusses(false, "密码数组为空或长度不为16"); | 
 |  |  |             } | 
 |  |  | 
 |  |  |                     mfc.connect(); | 
 |  |  |                 } | 
 |  |  |                 for (int i = 0; i < passWord.size(); i++) { | 
 |  |  |                     byte [] passWordItem = passWord.get(i); | 
 |  |  |                     byte[] passWordItem = passWord.get(i); | 
 |  |  |                     // 验证扇区密码 | 
 |  |  |                     boolean isAuthenticated = false; | 
 |  |  |  | 
 |  |  | 
 |  |  |     /** | 
 |  |  |      * 修改密码 | 
 |  |  |      * | 
 |  |  |      * @param a  扇区 | 
 |  |  |      * @param a   扇区 | 
 |  |  |      * @param mfc MifareClassic实例 | 
 |  |  |      * @return | 
 |  |  |      */ | 
 |  |  | 
 |  |  |         byte[] data = new byte[16]; | 
 |  |  |         if (null != mfc) { | 
 |  |  |             try { | 
 |  |  |                 //将密码转换为keyA | 
 |  |  |                 // 将密码转换为keyA | 
 |  |  |                 byte[] dataA = HexUtil.hexToByteArray(companyKeyA); | 
 |  |  |                 for (int i = 0; i < dataA.length; i++) { | 
 |  |  |                     data[i] = dataA[i]; | 
 |  |  |                 } | 
 |  |  |                 //输入控制位 | 
 |  |  |                 // 输入控制位 | 
 |  |  |                 data[6] = (byte) 0xFF; | 
 |  |  |                 data[7] = (byte) 0x07; | 
 |  |  |                 data[8] = (byte) 0x80; | 
 |  |  |                 data[9] = (byte) 0x69; | 
 |  |  |                 byte[] dataB = HexUtil.hexToByteArray(companyKeyB); | 
 |  |  |                 //将密码转换为KeyB | 
 |  |  |                 // 将密码转换为KeyB | 
 |  |  |                 for (int i = 0; i < dataB.length; i++) { | 
 |  |  |                     data[i + 10] = dataB[i]; | 
 |  |  |                 } | 
 |  |  |                 int bIndex = mfc.sectorToBlock(a); | 
 |  |  |                 int bCount = mfc.getBlockCountInSector(a); | 
 |  |  |                 //写到扇区的最后一个块 | 
 |  |  |                 // 写到扇区的最后一个块 | 
 |  |  |                 mfc.writeBlock(bIndex + bCount - 1, data); | 
 |  |  |  | 
 |  |  |                 return true; | 
 |  |  | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 初始化卡 | 
 |  |  |      * | 
 |  |  | 
 |  |  |             MifareClassic mfc = MifareClassic.get(tag); | 
 |  |  |             if (null != mfc) { | 
 |  |  |                 try { | 
 |  |  |                     //连接NFC | 
 |  |  |                     // 连接NFC | 
 |  |  |                     mfc.connect(); | 
 |  |  |                     //获取扇区数量 | 
 |  |  |                     // 获取扇区数量 | 
 |  |  |                     int count = mfc.getSectorCount(); | 
 |  |  |                     byte[] data = new byte[16]; | 
 |  |  |                     String initData = "FFFFFFFFFFFFFF078069FFFFFFFFFFFF"; | 
 |  |  |                     byte[] initDataBytes = HexUtil.hexToByteArray(initData); | 
 |  |  |                     for (int sector = 0; sector < count; sector++) { | 
 |  |  |                         //验证扇区密码 | 
 |  |  |                         // 验证扇区密码 | 
 |  |  |                         boolean isOpen = false; | 
 |  |  |                         for (int i = 0; i < listKeyA.size(); i++) { | 
 |  |  |                             if (mfc.authenticateSectorWithKeyA(sector, listKeyA.get(i))) { | 
 |  |  | 
 |  |  |                             } | 
 |  |  |                         } | 
 |  |  |                         if (isOpen) { | 
 |  |  |                             //获取写的扇区的块的数量 | 
 |  |  |                             // 获取写的扇区的块的数量 | 
 |  |  |                             int blockCount = mfc.getBlockCountInSector(sector); | 
 |  |  |                             int blockIndex = mfc.sectorToBlock(sector); | 
 |  |  |                             for (int block = 0; block < blockCount; block++) { | 
 |  |  | 
 |  |  |                                 } else { | 
 |  |  |                                     mfc.writeBlock(blockIndex, initDataBytes); | 
 |  |  |                                 } | 
 |  |  |                                 //写卡 | 
 |  |  |                                 // 写卡 | 
 |  |  |                                 blockIndex++; | 
 |  |  |                             } | 
 |  |  |                         } | 
 |  |  | 
 |  |  |         } | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  | } | 
 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Override | 
 |  |  |     public boolean writeUserData(BaseUserCardCard userCard,int sector) { | 
 |  |  |     public boolean writeUserData(BaseUserCardCard userCard, int sector) { | 
 |  |  |         switch (BaseNfcActivity.adapterType) { | 
 |  |  |             case ModelUtils.defaultType: | 
 |  |  |                 return nativeNfcWriteHelper.writeUserData(userCard, sector); | 
 |  |  |  | 
 |  |  |         } | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 写用户数据(带回调) | 
 |  |  |      * | 
 |  |  |      * @param userCard 用户卡数据 | 
 |  |  |      * @param sector   扇区 | 
 |  |  |      * @param callBack 回调接口 | 
 |  |  |      * @return 是否成功 | 
 |  |  |      */ | 
 |  |  |     public boolean writeUserData(BaseUserCardCard userCard, int sector, NFCCallBack callBack) { | 
 |  |  |         switch (BaseNfcActivity.adapterType) { | 
 |  |  |             case ModelUtils.defaultType: | 
 |  |  |                 return nativeNfcWriteHelper.writeUserData(userCard, sector, callBack); | 
 |  |  |         } | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  | 
 |  |  |     public boolean writeData(byte[] str, int a, int b, NFCCallBack callBack) { | 
 |  |  |         switch (BaseNfcActivity.adapterType) { | 
 |  |  |             case ModelUtils.defaultType: | 
 |  |  |                 return nativeNfcWriteHelper.writeData(str, a, b,callBack); | 
 |  |  |                 return nativeNfcWriteHelper.writeData(str, a, b, callBack); | 
 |  |  |  | 
 |  |  |         } | 
 |  |  |         return false; | 
 |  |  | 
 |  |  |     public boolean writeData(byte[] str, int a, int b, boolean isConnect, NFCCallBack callBack) { | 
 |  |  |         switch (BaseNfcActivity.adapterType) { | 
 |  |  |             case ModelUtils.defaultType: | 
 |  |  |                 return nativeNfcWriteHelper.writeData(str, a, b,isConnect,callBack); | 
 |  |  |                 return nativeNfcWriteHelper.writeData(str, a, b, isConnect, callBack); | 
 |  |  |  | 
 |  |  |         } | 
 |  |  |         return false; | 
 |  |  | 
 |  |  |         return false; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public boolean changePasword( List<byte[]> passWord, boolean isConnect, boolean isClose, NFCCallBack callBack) { | 
 |  |  |     public boolean changePasword(List<byte[]> passWord, boolean isConnect, boolean isClose, NFCCallBack callBack) { | 
 |  |  |         switch (BaseNfcActivity.adapterType) { | 
 |  |  |             case ModelUtils.defaultType: | 
 |  |  |                 return nativeNfcWriteHelper.changePasword(passWord,isConnect, isClose,callBack); | 
 |  |  |                 return nativeNfcWriteHelper.changePasword(passWord, isConnect, isClose, callBack); | 
 |  |  |         } | 
 |  |  |         return false; | 
 |  |  |     } | 
 
 |  |  | 
 |  |  | import com.dayu.baselibrary.view.TitleBar.ClickType_LEFT_IMAGE | 
 |  |  | import com.dayu.general.BaseApplication | 
 |  |  | import com.dayu.general.R | 
 |  |  | import com.dayu.general.bean.card.UserCard | 
 |  |  | import com.dayu.general.bean.db.CardRegistrationBean | 
 |  |  | import com.dayu.general.bean.net.ClientInfo | 
 |  |  | import com.dayu.general.bean.net.NewCardDataResult | 
 |  |  | import com.dayu.general.bean.net.PaymentMethod | 
 |  |  | import com.dayu.general.bean.net.PaymentMethodResponse | 
 |  |  | import com.dayu.general.dao.BaseDaoSingleton | 
 |  |  | import com.dayu.general.databinding.ActivityNewCardGeBinding | 
 |  |  | 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.NfcReadHelper | 
 |  |  | import com.dayu.general.tool.NfcWreatHelper | 
 |  |  | import com.dayu.general.utils.DateUtils | 
 |  |  | import com.tencent.bugly.crashreport.CrashReport | 
 |  |  | import kotlinx.coroutines.launch | 
 |  |  | import java.util.Calendar | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * Description: 用户开卡界面(同步修改白卡密码) | 
 |  |  | 
 |  |  |     // 客户ID | 
 |  |  |     private var clientId: String = "" | 
 |  |  |  | 
 |  |  |     private lateinit var clientInfo : ClientInfo | 
 |  |  |  | 
 |  |  |     // 是否已读卡 | 
 |  |  |     private var isReadCard: Boolean = false | 
 |  |  |  | 
 |  |  |     private var orderId:String="" | 
 |  |  |  | 
 |  |  |     companion object { | 
 |  |  |         private const val TAG = "NewCard2Activity" | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     // 支付方式数据类 | 
 |  |  |     data class PaymentMethod( | 
 |  |  |         val id: Long, | 
 |  |  |         val name: String, | 
 |  |  |         val remarks: String, | 
 |  |  |         val deleted: Int | 
 |  |  |     ) | 
 |  |  |  | 
 |  |  |     // 支付方式接口返回数据类 | 
 |  |  |     data class PaymentMethodResponse( | 
 |  |  |         val itemTotal: Any?, | 
 |  |  |         val obj: List<PaymentMethod>, | 
 |  |  |         val pageCurr: Any?, | 
 |  |  |         val pageSize: Any?, | 
 |  |  |         val pageTotal: Any? | 
 |  |  |     ) | 
 |  |  |  | 
 |  |  |     // 用户信息数据类 | 
 |  |  |     data class ClientInfo( | 
 |  |  |         val clientId: String, | 
 |  |  |         val clientNum: String, | 
 |  |  |         val name: String, | 
 |  |  |         val districtNum: String, | 
 |  |  |         val phone: String, | 
 |  |  |         val idCard: String, | 
 |  |  |         val villageName: String, | 
 |  |  |         val address: String, | 
 |  |  |         val cardCount: Int, | 
 |  |  |         val operateDt: String | 
 |  |  |     ) | 
 |  |  |  | 
 |  |  |     override fun onCreate(savedInstanceState: Bundle?) { | 
 |  |  |         super.onCreate(savedInstanceState) | 
 |  |  | 
 |  |  |             object : SubscriberListener<BaseResponse<ClientInfo>>() { | 
 |  |  |                 override fun onNext(response: BaseResponse<ClientInfo>) { | 
 |  |  |                     if (response.success) { | 
 |  |  |                         val clientInfo = response.content | 
 |  |  |                         clientInfo = response.content!! | 
 |  |  |                         if (clientInfo != null) { | 
 |  |  |                             // 显示客户信息到界面 | 
 |  |  |                             displayClientInfo(clientInfo) | 
 |  |  | 
 |  |  |         // 构建请求参数 | 
 |  |  |         val params = HashMap<String, Any>() | 
 |  |  |         params["cardAddr"] = cardPhysicalId // 水卡地址(物理ID) | 
 |  |  |         params["clientNum"] = binding.newCardFarmerCode.text.toString() // 农户编号 | 
 |  |  |         params["cardCost"] = (cardFee * 100).toInt() // 购卡金额(工本费)转为分 | 
 |  |  |         params["amount"] = (rechargeAmount * 100).toInt() // 充值金额转为分 | 
 |  |  |         params["clientId"] = clientId // 农户ID | 
 |  |  |         params["cardCost"] = cardFee  // 购卡金额(工本费)(元) | 
 |  |  |         params["amount"] = rechargeAmount  // 充值金额(元) | 
 |  |  |         params["paymentId"] = paymentId // 支付方式ID | 
 |  |  |         params["remarks"] = remark // 备注 | 
 |  |  |         params["protocol"] = "p206V1_0_1" // 协议 | 
 |  |  |         params["operator"] = BaseApplication.userId // 操作人ID | 
 |  |  |  | 
 |  |  |         // 执行卡片激活API请求 | 
 |  |  |         ApiManager.getInstance().requestPostLoading( | 
 |  |  |             this, | 
 |  |  |             "sell/card/active", | 
 |  |  |             String::class.java, | 
 |  |  |             "terminal/card/termActiveCard", | 
 |  |  |             NewCardDataResult::class.java, | 
 |  |  |             params, | 
 |  |  |             object : SubscriberListener<BaseResponse<String>>() { | 
 |  |  |                 override fun onNext(response: BaseResponse<String>) { | 
 |  |  |             object : SubscriberListener<BaseResponse<NewCardDataResult>>() { | 
 |  |  |                 override fun onNext(response: BaseResponse<NewCardDataResult>) { | 
 |  |  |                     if (response.success) { | 
 |  |  |                         orderId=response.content?.orderNo.toString() | 
 |  |  |                         // 保存开卡信息到数据库 | 
 |  |  |                         val cardRegistration = CardRegistrationBean( | 
 |  |  |                             cardNumber = cardPhysicalId, | 
 |  |  |                             userName = binding.newCardUserName.text.toString(), | 
 |  |  |                             idCard = binding.newCardIdCard.text.toString(), | 
 |  |  |                             farmerCode = binding.newCardFarmerCode.text.toString(), | 
 |  |  |                             clientId = clientId, | 
 |  |  |                             cardFee = cardFee, | 
 |  |  |                             remark = binding.newCardRemark.text.toString(), | 
 |  |  |                             paymentMethod = paymentId.toInt(), | 
 |  |  |                             isReported = true, | 
 |  |  |                             isCardWritten = true | 
 |  |  |                         ) | 
 |  |  |                             isCardWritten = true, | 
 |  |  |                             operatorId = orderId, | 
 |  |  |  | 
 |  |  |                             ) | 
 |  |  |  | 
 |  |  |                         // 使用协程在后台线程中保存数据 | 
 |  |  |                         lifecycleScope.launch { | 
 |  |  |                             try { | 
 |  |  |                                 BaseDaoSingleton.getInstance(this@NewCard2Activity) | 
 |  |  |                                     .cardRegistrationDao().insert(cardRegistration) | 
 |  |  |  | 
 |  |  |                                 Toast.makeText( | 
 |  |  |                                     this@NewCard2Activity, | 
 |  |  |                                     "开卡成功", | 
 |  |  |                                     Toast.LENGTH_SHORT | 
 |  |  |                                 ).show() | 
 |  |  |                                 setResult(RESULT_OK) | 
 |  |  |                                 finish() | 
 |  |  |                                 Intent(this@NewCard2Activity, NfcWreatActivity::class.java).apply { | 
 |  |  |                                     putExtra("cardType", USER_CARD_TYPE_1) | 
 |  |  |                                     putExtra("orderId", orderId) | 
 |  |  |                                     putExtra("cardAddr", cardPhysicalId) | 
 |  |  |                                     var userCard = UserCard() | 
 |  |  |                                     userCard.areaNumber =clientInfo.districtNum | 
 |  |  |                                     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.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) | 
 |  |  |                                     startActivity(this) | 
 |  |  |                                 } | 
 |  |  |                             } catch (e: Exception) { | 
 |  |  |                                 CrashReport.postCatchedException(e) | 
 |  |  |                                 Toast.makeText( | 
 
 |  |  | 
 |  |  |     package com.dayu.general.activity | 
 |  |  | package com.dayu.general.activity | 
 |  |  |  | 
 |  |  | import android.content.Intent | 
 |  |  | import android.os.Bundle | 
 |  |  | import com.dayu.baselibrary.net.subscribers.SubscriberListener | 
 |  |  | import com.dayu.baselibrary.utils.ToastUtil | 
 |  |  | import com.dayu.general.bean.card.ClearCard | 
 |  |  | import com.dayu.general.bean.card.UserCard | 
 |  |  | import com.dayu.general.tool.CardCommon | 
 |  |  | import com.dayu.general.databinding.ActivityNfcWriteGeBinding | 
 |  |  | import com.dayu.general.net.ApiManager | 
 |  |  | 
 |  |  |     var cardType = "" | 
 |  |  |     var orderId = "" | 
 |  |  |     var cardAddr = "" | 
 |  |  |     private lateinit var userCard: UserCard | 
 |  |  |  | 
 |  |  |     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)!! | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |         if (cardType.isNotEmpty()) { | 
 |  |  |             when (cardType) { | 
 |  |  |                 CardCommon.CLEAN_CARD_TYPE -> { | 
 |  |  | 
 |  |  |                         } | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 CardCommon.USER_CARD_TYPE_1 -> { | 
 |  |  |                     binding?.cardData?.text = "写用户卡" | 
 |  |  |                     nfcWreatHelper.writeUserData(userCard) | 
 |  |  |  | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } else { | 
 |  |  |             ToastUtil.show("卡片错误,当前刷的卡与刚刚的卡不一致") | 
 
 |  |  | 
 |  |  |  */ | 
 |  |  | class UserCard : BaseUserCardCard(), Serializable { | 
 |  |  |     var cardType: String = USER_CARD_TYPE_1 // 卡类型:A1终端写卡 A8刷卡开泵后值 A2叠加充值 | 
 |  |  |     var areaNumber: Int = 0 // 国家行政区域号(12位BCD,精确到村) | 
 |  |  |     var areaNumber: String = "" // 国家行政区域号(12位BCD,精确到村) | 
 |  |  |     var userCode: String = "" // 用户编号BCD | 
 |  |  |     var userCodeNumber: Int = 0 // 用户卡编号(HEX) | 
 |  |  |     var phoneNumber: String = "" // 手机号(BCD) | 
 |  |  | 
 |  |  |             userCard.apply { | 
 |  |  |                 // 解析国家行政区域号(0-5位) | 
 |  |  |                 val areaCodeBytes = zero.copyOfRange(0, 6) | 
 |  |  |                 areaNumber = BcdUtil.bcdToStr(areaCodeBytes).toInt() | 
 |  |  |                 areaNumber = BcdUtil.bcdToStr(areaCodeBytes) | 
 |  |  |  | 
 |  |  |                 // 解析用户卡编号(6-7位) | 
 |  |  |                 val userCodeNumberBytes = zero.copyOfRange(6, 8) | 
 
 |  |  | 
 |  |  |     val cardNumber: String, // IC卡卡号 | 
 |  |  |     val userName: String, // 姓名 | 
 |  |  |     val idCard: String, // 身份证号 | 
 |  |  |     val farmerCode: String, // 农户编号 | 
 |  |  |     val clientId: String, // 农户Id | 
 |  |  |     val cardFee: Double, // 工本费 | 
 |  |  |     val remark: String, // 备注 | 
 |  |  |     val paymentMethod: Int, // 支付方式 | 
 
| New file | 
 |  |  | 
 |  |  | package com.dayu.general.bean.net | 
 |  |  |  | 
 |  |  | // 支付方式数据类 | 
 |  |  | data class PaymentMethod( | 
 |  |  |     val id: Long, | 
 |  |  |     val name: String, | 
 |  |  |     val remarks: String, | 
 |  |  |     val deleted: Int | 
 |  |  | ) | 
 |  |  |  | 
 |  |  | // 支付方式接口返回数据类 | 
 |  |  | data class PaymentMethodResponse( | 
 |  |  |     val itemTotal: Any?, | 
 |  |  |     val obj: List<PaymentMethod>, | 
 |  |  |     val pageCurr: Any?, | 
 |  |  |     val pageSize: Any?, | 
 |  |  |     val pageTotal: Any? | 
 |  |  | ) | 
 |  |  |  | 
 |  |  | // 用户信息数据类 | 
 |  |  | data class ClientInfo( | 
 |  |  |     val clientId: String, | 
 |  |  |     val clientNum: String, | 
 |  |  |     val name: String, | 
 |  |  |     val districtNum: String, | 
 |  |  |     val phone: String, | 
 |  |  |     val idCard: String, | 
 |  |  |     val villageName: String, | 
 |  |  |     val address: String, | 
 |  |  |     val cardCount: Int, | 
 |  |  |     val operateDt: String | 
 |  |  | ) | 
 
| New file | 
 |  |  | 
 |  |  | package com.dayu.general.bean.net | 
 |  |  |  | 
 |  |  | data class NewCardDataResult( | 
 |  |  |     var projectNo: String, | 
 |  |  |     var cardNum: String, | 
 |  |  |     var balance: String, | 
 |  |  |     var waterPrice: String, | 
 |  |  |     var time: String, | 
 |  |  |     var orderNo: String | 
 |  |  | ) | 
 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 写卡(异步) | 
 |  |  |      * | 
 |  |  |      * @param userCard 用户卡内容 | 
 |  |  |      * @param callBack 操作结果和消息回调 | 
 |  |  |      */ | 
 |  |  |     fun writeUserDataAsync(userCard: UserCard, callBack: NFCCallBack): Disposable { | 
 |  |  |         showLoading() | 
 |  |  |         val disposable = Observable.fromCallable { | 
 |  |  |             writeUserData(userCard, callBack) | 
 |  |  |         } | 
 |  |  |         .subscribeOn(Schedulers.io()) | 
 |  |  |         .observeOn(AndroidSchedulers.mainThread()) | 
 |  |  |         .subscribe({ result -> | 
 |  |  |             hideLoading() | 
 |  |  |             // 结果已经在writeUserData中通过callBack回调了 | 
 |  |  |         }, { error -> | 
 |  |  |             hideLoading() | 
 |  |  |             error.printStackTrace() | 
 |  |  |             callBack.isSusses(false, "异步写卡异常: ${error.message}") | 
 |  |  |         }) | 
 |  |  |          | 
 |  |  |         compositeDisposable.add(disposable) | 
 |  |  |         return disposable | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 写卡 | 
 |  |  |      * | 
 |  |  |      * @param userCard 用户卡内容 | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 写卡 | 
 |  |  |      * | 
 |  |  |      * @param userCard 用户卡内容 | 
 |  |  |      * @param callBack 回调接口 | 
 |  |  |      */ | 
 |  |  |     fun writeUserData(userCard: UserCard, callBack: NFCCallBack): Boolean { | 
 |  |  |         try { | 
 |  |  |             return adapter.writeUserData(userCard, 7, callBack) | 
 |  |  |         } catch (e: java.lang.Exception) { | 
 |  |  |             e.printStackTrace() | 
 |  |  |             callBack.isSusses(false, "写卡异常: ${e.message}") | 
 |  |  |         } | 
 |  |  |         return false | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 修改密码(异步) | 
 |  |  |      * | 
 |  |  |      * @param ps 密码列表 | 
 
| New file | 
 |  |  | 
 |  |  | package com.dayu.general.utils | 
 |  |  |  | 
 |  |  | import java.text.SimpleDateFormat | 
 |  |  | import java.util.Calendar | 
 |  |  | import java.util.Locale | 
 |  |  |  | 
 |  |  | object DateUtils { | 
 |  |  |  | 
 |  |  |     private const val DATE_PATTERN = "yyyy-MM-dd HH:mm:ss" | 
 |  |  |     private val sdf by lazy { SimpleDateFormat(DATE_PATTERN, Locale.getDefault()) } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 将字符串转换为 Calendar 对象 | 
 |  |  |      * @param dateStr 时间字符串,格式:yyyy-MM-dd HH:mm:ss | 
 |  |  |      * @return 解析后的 Calendar 对象,失败返回 null | 
 |  |  |      */ | 
 |  |  |     fun parseStringToCalendar(dateStr: String?): Calendar? { | 
 |  |  |         if (dateStr.isNullOrEmpty()) return null | 
 |  |  |         return try { | 
 |  |  |             val date = sdf.parse(dateStr) | 
 |  |  |             val calendar = Calendar.getInstance() | 
 |  |  |             calendar.time = date ?: return null | 
 |  |  |             calendar | 
 |  |  |         } catch (e: Exception) { | 
 |  |  |             e.printStackTrace() | 
 |  |  |             null | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  | } |