From a8751388c9a86ae95714a15279994d8aa426a26d Mon Sep 17 00:00:00 2001 From: zuoxiao <470321431@qq.com> Date: 星期五, 13 六月 2025 14:59:02 +0800 Subject: [PATCH] feat(generallibrary): 优化充值功能并添加水价获取- 在 activity_recharge_detail.xml 中移除了不必要的 bold 样式- 在 EditText 中添加了金额输入限制(数字和小数点)- 在 BaseApplication 中添加了水价信息存储 - 在 MainActivity 中实现了延时获取水价的功能- 优化了 RechargeDetailActivity 中的水价检查和使用逻辑 - 在 README.md 中添加了金额格式化和水价获取的最佳实践指南 --- generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt | 28 + generallibrary/src/main/res/layout/dialog_search.xml | 36 + generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt | 52 ++ generallibrary/src/main/java/com/dayu/general/activity/RechargeFragment.kt | 102 +++- generallibrary/src/main/java/com/dayu/general/BaseApplication.kt | 24 + generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt | 30 + generallibrary/src/main/java/com/dayu/general/tool/CardOperationType.kt | 2 generallibrary/src/main/res/layout/activity_recharge_detail.xml | 6 README.md | 583 +++++++++++++++++++++++++++ baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcReadHelper.java | 17 generallibrary/src/main/res/layout/fragment_recharge.xml | 12 baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java | 51 + generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt | 211 +++++++++ baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcReadAdapter.java | 17 generallibrary/src/main/java/com/dayu/general/bean/net/RechargeResult.kt | 14 generallibrary/src/main/java/com/dayu/general/bean/net/WaterPriceResult.kt | 10 generallibrary/src/main/java/com/dayu/general/bean/net/RechargeRequest.kt | 18 17 files changed, 1,120 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 10c21e2..dee3b50 100644 --- a/README.md +++ b/README.md @@ -741,6 +741,589 @@ - 閿欒淇℃伅浣跨敤甯︽爣棰樼殑Dialog锛屾彁渚涙竻鏅扮殑閿欒鍒嗙被 - 闀挎椂闂存搷浣滄樉绀哄姞杞紻ialog锛岄伩鍏嶇敤鎴疯鎿嶄綔 +### 閲戦鏍煎紡鍖栨渶浣冲疄璺� + +鍦ㄥ鐞嗛噾棰濈浉鍏崇殑鏁版嵁鏃讹紝搴旇缁熶竴浣跨敤涓や綅灏忔暟鏍煎紡锛岀‘淇濇樉绀虹殑涓�鑷存�у拰鍑嗙‘鎬с�� + +#### 閲戦鏍煎紡鍖栨柟娉� + +```kotlin +// 浣跨敤String.format鏍煎紡鍖栭噾棰濅负涓や綅灏忔暟 +val amount = 123.4 +val formattedAmount = String.format("%.2f", amount) +// 缁撴灉: "123.40" + +// 鍦ㄦ樉绀烘椂娣诲姞璐у竵鍗曚綅 +binding.balanceText.text = "${formattedAmount} 鍏�" +``` + +#### 閲戦杈撳叆楠岃瘉 + +```kotlin +private fun validateAmount(amountStr: String): Double? { + if (amountStr.isEmpty()) { + ToastUtil.show("璇疯緭鍏ラ噾棰�") + return null + } + + val amount = try { + amountStr.toDouble() + } catch (e: NumberFormatException) { + ToastUtil.show("璇疯緭鍏ユ湁鏁堢殑閲戦") + return null + } + + if (amount <= 0) { + ToastUtil.show("閲戦蹇呴』澶т簬0") + return null + } + + // 妫�鏌ュ皬鏁颁綅鏁颁笉瓒呰繃2浣� + val decimalPlaces = amountStr.substringAfter('.', "").length + if (decimalPlaces > 2) { + ToastUtil.show("閲戦鏈�澶氫繚鐣欎袱浣嶅皬鏁�") + return null + } + + return amount +} +``` + +#### 閲戦璁$畻鍜屾樉绀虹ず渚� + +```kotlin +private fun calculateAndDisplayAmounts() { + val rechargeAmount = validateAmount(binding.rechargeAmount.text.toString()) ?: return + val bonusAmount = validateAmount(binding.bonusAmount.text.toString()) ?: 0.0 + + // 璁$畻鎬婚噾棰� + val totalAmount = rechargeAmount + bonusAmount + + // 鏍煎紡鍖栨樉绀� + val formattedRecharge = String.format("%.2f", rechargeAmount) + val formattedBonus = String.format("%.2f", bonusAmount) + val formattedTotal = String.format("%.2f", totalAmount) + + // 鏇存柊UI鏄剧ず + binding.rechargeAmountText.text = "${formattedRecharge} 鍏�" + binding.bonusAmountText.text = "${formattedBonus} 鍏�" + binding.totalAmountText.text = "${formattedTotal} 鍏�" +} +``` + +#### EditText閲戦杈撳叆闄愬埗 + +鍦ㄥ竷灞�鏂囦欢涓缃噾棰濊緭鍏ョ殑闄愬埗锛� + +```xml +<EditText + android:id="@+id/amountEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:inputType="numberDecimal" + android:digits="0123456789." + android:maxLength="10" + android:hint="璇疯緭鍏ラ噾棰�" /> +``` + +#### TextWatcher瀹炵幇灏忔暟浣嶉檺鍒� + +浣跨敤TextWatcher鏉ラ檺鍒剁敤鎴峰彧鑳借緭鍏ユ渶澶氫袱浣嶅皬鏁帮細 + +```kotlin +/** + * 璁剧疆閲戦杈撳叆闄愬埗锛屾渶澶氫繚鐣欎袱浣嶅皬鏁� + */ +private fun setupAmountInputLimit(editText: EditText) { + editText.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + + override fun afterTextChanged(s: Editable?) { + val text = s.toString() + if (text.isEmpty()) return + + // 妫�鏌ユ槸鍚﹀寘鍚皬鏁扮偣 + if (text.contains(".")) { + val parts = text.split(".") + if (parts.size == 2) { + val decimalPart = parts[1] + // 濡傛灉灏忔暟浣嶈秴杩�2浣嶏紝鎴彇鍓嶄袱浣� + if (decimalPart.length > 2) { + val newText = "${parts[0]}.${decimalPart.substring(0, 2)}" + editText.removeTextChangedListener(this) + editText.setText(newText) + editText.setSelection(newText.length) + editText.addTextChangedListener(this) + } + } + } + + // 闃叉杈撳叆澶氫釜灏忔暟鐐� + val dotCount = text.count { it == '.' } + if (dotCount > 1) { + val newText = text.substring(0, text.lastIndexOf('.')) + editText.removeTextChangedListener(this) + editText.setText(newText) + editText.setSelection(newText.length) + editText.addTextChangedListener(this) + } + + // 闃叉浠ュ皬鏁扮偣寮�澶� + if (text.startsWith(".")) { + editText.removeTextChangedListener(this) + editText.setText("0$text") + editText.setSelection(editText.text.length) + editText.addTextChangedListener(this) + } + } + }) +} + +// 鍦╥nitView涓皟鐢� +setupAmountInputLimit(binding.rechargeAmount) +setupAmountInputLimit(binding.bonusAmount) +``` + +#### 閲戦鏍煎紡鍖栨敞鎰忎簨椤� + +1. **缁熶竴鏍煎紡**: 鎵�鏈夐噾棰濇樉绀洪兘浣跨敤涓や綅灏忔暟鏍煎紡 +2. **杈撳叆楠岃瘉**: 楠岃瘉鐢ㄦ埛杈撳叆鐨勯噾棰濇牸寮忓拰鑼冨洿 +3. **璁$畻绮惧害**: 浣跨敤Double绫诲瀷杩涜閲戦璁$畻锛岄伩鍏嶇簿搴︿涪澶� +4. **鏄剧ず鍗曚綅**: 閲戦鏄剧ず鏃剁粺涓�娣诲姞璐у竵鍗曚綅锛堝"鍏�"锛� +5. **杈圭晫妫�鏌�**: 妫�鏌ラ噾棰濈殑鏈�澶у�煎拰鏈�灏忓�奸檺鍒� + +## 鍏呭�兼帴鍙d娇鐢ㄨ鏄� + +椤圭洰涓疄鐜颁簡瀹屾暣鐨勫厖鍊煎姛鑳斤紝鍖呮嫭鍏呭�兼帴鍙h皟鐢ㄥ拰NFC鍐欏崱鎿嶄綔銆� + +### 鍏呭�兼帴鍙h鎯� + +**鎺ュ彛鍦板潃**: `/terminal/card/termRecharge` +**璇锋眰鏂瑰紡**: POST +**鎺ュ彛鎻忚堪**: 缁堢鍏呭�兼帴鍙o紝鐢ㄤ簬鍒涘缓鍏呭�艰鍗曞苟杩斿洖鍐欏崱鎵�闇�淇℃伅 + +#### 璇锋眰鍙傛暟 + +```kotlin +data class RechargeRequest( + val rechargeType: Int, // 鍏呭�肩被鍨� (鍥哄畾鍊�: 2) + val cardNum: String, // 鍗″彿 + val money: String, // 鍏呭�奸噾棰� (鏍煎紡: "300.0") + val amount: String, // 鍏呭�兼暟閲� + val gift: String, // 璧犻�侀噾棰� + val paymentId: String, // 鏀粯鏂瑰紡ID + val price: String, // 鍗曚环 (鏍煎紡: "0.90") + val remarks: String, // 澶囨敞 (榛樿: "鍏呭��") + val operator: Long // 鎿嶄綔鍛業D +) +``` + +#### 璇锋眰绀轰緥 + +```json +{ + "rechargeType": 2, + "cardNum": "53232810100600001", + "money": "300.0", + "amount": "50", + "gift": "5", + "paymentId": "1838466162264350722", + "price": "0.90", + "remarks": "鍏呭��", + "operator": 2024090516595200300 +} +``` + +#### 杩斿洖鍙傛暟 + +```kotlin +data class RechargeResult( + val projectNo: Int, // 椤圭洰缂栧彿 + val cardNum: String, // 鍗″彿 + val orderNo: String, // 璁㈠崟鍙� + val waterPrice: Double, // 姘翠环 + val time: String // 鏃堕棿 +) +``` + +#### 杩斿洖绀轰緥 + +```json +{ + "code": "0001", + "content": { + "projectNo": 10, + "cardNum": "53232810100600001", + "orderNo": "2506041414250065", + "waterPrice": 0.9, + "time": "2025-05-08 17:31:02" + }, + "msg": "璇锋眰鎴愬姛", + "success": true +} +``` + +### 鍏呭�煎姛鑳藉疄鐜� + +#### 1. 鍦ˋctivity涓皟鐢ㄥ厖鍊兼帴鍙� + +```kotlin +/** + * 璋冪敤鍏呭�兼帴鍙� + */ +private fun callRechargeApi(rechargeAmount: Double, bonusAmount: Double) { + val cardNum = cardInfo?.cardNum ?: cardAddress ?: "" + + // 鏋勫缓鍏呭�艰姹傚弬鏁� + val params = mapOf( + "rechargeType" to 2, + "cardNum" to cardNum, + "money" to String.format("%.1f", rechargeAmount), + "amount" to String.format("%.0f", bonusAmount), + "gift" to String.format("%.0f", bonusAmount), + "paymentId" to paymentId.toString(), + "price" to "0.90", + "remarks" to "鍏呭��", + "operator" to 2024090516595200300L + ) + + ApiManager.getInstance().requestPostLoading( + this, + "terminal/card/termRecharge", + RechargeResult::class.java, + params, + object : SubscriberListener<BaseResponse<RechargeResult>>() { + override fun onNext(response: BaseResponse<RechargeResult>) { + if (response.success && response.code == "0001") { + // 鍏呭�兼垚鍔燂紝璺宠浆鍒板啓鍗$晫闈� + response.content?.let { rechargeResult -> + startWriteCardActivity(rechargeResult, rechargeAmount, bonusAmount) + } + } else { + ToastUtil.show("鍏呭�煎け璐�: ${response.msg ?: "鏈煡閿欒"}") + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + ToastUtil.show("鍏呭�煎け璐�: ${e?.message ?: "缃戠粶寮傚父"}") + } + } + ) +} +``` + +#### 2. 璺宠浆鍒板啓鍗$晫闈� + +```kotlin +/** + * 鍚姩鍐欏崱鐣岄潰 + */ +private fun startWriteCardActivity(rechargeResult: RechargeResult, rechargeAmount: Double, bonusAmount: Double) { + // 鍒涘缓UserCard瀵硅薄鐢ㄤ簬鍐欏崱 + val userCard = UserCard().apply { + cardInfo?.let { info -> + userCode = info.cardNum ?: "" + balance = ((rechargeAmount + bonusAmount) * 100).toInt() // 杞崲涓哄垎 + } + + // 璁剧疆鍏朵粬蹇呰淇℃伅 + projectCode = rechargeResult.projectNo + waterPrice = rechargeResult.waterPrice.toFloat() + rechargeDate = java.util.Calendar.getInstance() + } + + // 鍚姩鍐欏崱Activity + val intent = Intent(this, NfcWreatActivity::class.java).apply { + putExtra("cardType", "USER_CARD") + putExtra("cardAddr", cardAddress) + putExtra("operationTypeCode", CardOperationType.Recharge.code) + putExtra("orderNumber", rechargeResult.orderNo) + putExtra("userCard", userCard) + } + + startActivity(intent) +} +``` + +#### 3. NFC鍐欏崱澶勭悊 + +鍦╜NfcWreatActivity`涓紝鍏呭�兼搷浣滀細琚嚜鍔ㄥ鐞嗭細 + +```kotlin +CardOperationType.Recharge -> { + nfcWreatHelper.writeUserDataAsync(userCard, object : NFCCallBack { + override fun isSusses(flag: Boolean, msg: String?) { + runOnUiThread { + if (flag) { + postCardData(cardType, cardAddr) + ToastUtil.show("鍏呭�煎啓鍗℃垚鍔�!") + } else { + ToastUtil.show("鍏呭�煎啓鍗″け璐�: ${msg ?: "鏈煡閿欒"}") + } + } + } + }) +} +``` + +### 鍏呭�兼祦绋嬭鏄� + +1. **鐢ㄦ埛杈撳叆**: 鐢ㄦ埛鍦ㄥ厖鍊肩晫闈㈣緭鍏ュ厖鍊奸噾棰濆拰璧犻�侀噾棰� +2. **鍙傛暟楠岃瘉**: 楠岃瘉杈撳叆鐨勯噾棰濇牸寮忓拰鏈夋晥鎬� +3. **鎺ュ彛璋冪敤**: 璋冪敤`/terminal/card/termRecharge`鎺ュ彛鍒涘缓鍏呭�艰鍗� +4. **璁㈠崟鍒涘缓**: 鏈嶅姟鍣ㄥ垱寤哄厖鍊艰鍗曞苟杩斿洖璁㈠崟淇℃伅 +5. **璺宠浆鍐欏崱**: 鎴愬姛鍚庤烦杞埌NFC鍐欏崱鐣岄潰 +6. **NFC鍐欏崱**: 鐢ㄦ埛璐村崱杩涜NFC鍐欏崱鎿嶄綔 +7. **鍐欏崱瀹屾垚**: 鍐欏崱鎴愬姛鍚庢洿鏂板崱鐗囦綑棰� + +### 娉ㄦ剰浜嬮」 + +1. **閲戦鏍煎紡**: 鍏呭�奸噾棰濅娇鐢ㄤ竴浣嶅皬鏁版牸寮忥紝濡�"300.0" +2. **鎿嶄綔鍛業D**: 闇�瑕佹牴鎹疄闄呯櫥褰曠敤鎴疯缃纭殑鎿嶄綔鍛業D +3. **鏀粯鏂瑰紡**: 鏀粯鏂瑰紡ID闇�瑕佷粠鏀粯鏂瑰紡鎺ュ彛鑾峰彇 +4. **閿欒澶勭悊**: 鍏呭�煎け璐ユ椂瑕佹彁渚涙槑纭殑閿欒淇℃伅 +5. **鍐欏崱楠岃瘉**: 鍐欏崱鍓嶈楠岃瘉鍗″彿涓�鑷存�� +6. **璁㈠崟璺熻釜**: 淇濆瓨璁㈠崟鍙风敤浜庡悗缁煡璇㈠拰璺熻釜 + +### 鐩稿叧鏁版嵁绫� + +```kotlin +// 鍏呭�艰姹傛暟鎹被 +data class RechargeRequest( + val rechargeType: Int, + val cardNum: String, + val money: String, + val amount: String, + val gift: String, + val paymentId: String, + val price: String, + val remarks: String, + val operator: Long +) + +// 鍏呭�肩粨鏋滄暟鎹被 +data class RechargeResult( + val projectNo: Int, + val cardNum: String, + val orderNo: String, + val waterPrice: Double, + val time: String +) +``` + +## 姘翠环鎺ュ彛浣跨敤璇存槑 + +椤圭洰涓疄鐜颁簡姘翠环鐨勫姩鎬佽幏鍙栧拰绠$悊鍔熻兘锛屾敮鎸佷粠鏈嶅姟鍣ㄨ幏鍙栨渶鏂版按浠峰苟鍦ㄥ叏灞�鑼冨洿鍐呬娇鐢ㄣ�� + +### 姘翠环鎺ュ彛璇︽儏 + +**鎺ュ彛鍦板潃**: `/terminal/client/getWaterPrice` +**璇锋眰鏂瑰紡**: GET +**鎺ュ彛鎻忚堪**: 鑾峰彇褰撳墠绯荤粺姘翠环淇℃伅 + +#### 杩斿洖鍙傛暟 + +```kotlin +data class WaterPriceResult( + val price: Double // 姘翠环 +) +``` + +#### 杩斿洖绀轰緥 + +```json +{ + "code": "0001", + "content": { + "price": 0.9 + }, + "msg": "璇锋眰鎴愬姛", + "success": true +} +``` + +### 姘翠环鍔熻兘瀹炵幇 + +#### 1. BaseApplication涓殑姘翠环瀛樺偍 + +```kotlin +class BaseApplication { + companion object { + // 姘翠环淇℃伅 + var waterPrice: Double = 0.0 + } +} +``` + +#### 2. MainActivity涓欢鏃惰幏鍙栨按浠� + +```kotlin +class MainActivity : BaseNfcActivity() { + private val handler = Handler(Looper.getMainLooper()) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // ... 鍏朵粬鍒濆鍖栦唬鐮� ... + + // 寤舵椂20绉掑悗鑾峰彇姘翠环锛岄伩鍏嶅奖鍝嶅惎鍔ㄦ�ц兘 + handler.postDelayed({ + getWaterPrice() + }, 20000) // 20绉掑欢鏃� + } + + /** + * 鑾峰彇姘翠环淇℃伅 + */ + private fun getWaterPrice() { + ApiManager.getInstance().requestGetLoading( + this, + "terminal/client/getWaterPrice", + WaterPriceResult::class.java, + null, + object : SubscriberListener<BaseResponse<WaterPriceResult>>() { + override fun onNext(response: BaseResponse<WaterPriceResult>) { + if (response.success && response.code == "0001") { + // 鑾峰彇姘翠环鎴愬姛锛屼繚瀛樺埌BaseApplication + response.content?.let { waterPriceResult -> + BaseApplication.waterPrice = waterPriceResult.price + } + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + // 缃戠粶寮傚父鏃朵笉鏄剧ず閿欒淇℃伅锛岄伩鍏嶅奖鍝嶇敤鎴蜂綋楠� + } + } + ) + } + + override fun onDestroy() { + super.onDestroy() + // 娓呯悊Handler鍥炶皟锛岄槻姝㈠唴瀛樻硠婕� + handler.removeCallbacksAndMessages(null) + } +} +``` + +#### 3. RechargeDetailActivity涓殑姘翠环妫�鏌ュ拰浣跨敤 + +```kotlin +class RechargeDetailActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // ... 鍏朵粬鍒濆鍖栦唬鐮� ... + + // 妫�鏌ュ苟鑾峰彇姘翠环 + checkAndGetWaterPrice() + } + + /** + * 妫�鏌ュ苟鑾峰彇姘翠环 + */ + private fun checkAndGetWaterPrice() { + // 濡傛灉BaseApplication涓殑姘翠环涓虹┖鎴栦负0锛屽垯閲嶆柊鑾峰彇 + if (BaseApplication.waterPrice <= 0.0) { + getWaterPrice() + } + } + + /** + * 鑾峰彇姘翠环淇℃伅 + */ + private fun getWaterPrice() { + ApiManager.getInstance().requestGetLoading( + this, + "terminal/client/getWaterPrice", + WaterPriceResult::class.java, + null, + object : SubscriberListener<BaseResponse<WaterPriceResult>>() { + override fun onNext(response: BaseResponse<WaterPriceResult>) { + if (response.success && response.code == "0001") { + // 鑾峰彇姘翠环鎴愬姛锛屼繚瀛樺埌BaseApplication + response.content?.let { waterPriceResult -> + BaseApplication.waterPrice = waterPriceResult.price + } + } else { + // 鑾峰彇姘翠环澶辫触锛屼娇鐢ㄩ粯璁ゅ�� + if (BaseApplication.waterPrice <= 0.0) { + BaseApplication.waterPrice = 0.9 // 璁剧疆榛樿姘翠环 + } + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + // 缃戠粶寮傚父锛屼娇鐢ㄩ粯璁ゅ�� + if (BaseApplication.waterPrice <= 0.0) { + BaseApplication.waterPrice = 0.9 // 璁剧疆榛樿姘翠环 + } + } + } + ) + } + + /** + * 鍦ㄥ厖鍊兼帴鍙d腑浣跨敤姘翠环 + */ + private fun callRechargeApi(rechargeAmount: Double, bonusAmount: Double) { + // 鑾峰彇褰撳墠姘翠环锛屽鏋滀负0鍒欎娇鐢ㄩ粯璁ゅ�� + val currentWaterPrice = if (BaseApplication.waterPrice > 0.0) { + BaseApplication.waterPrice + } else { + 0.9 // 榛樿姘翠环 + } + + // 鏋勫缓鍏呭�艰姹傚弬鏁� + val params = mapOf( + // ... 鍏朵粬鍙傛暟 ... + "price" to String.format("%.2f", currentWaterPrice), // 浣跨敤鑾峰彇鍒扮殑姘翠环 + // ... 鍏朵粬鍙傛暟 ... + ) + + // ... 鎺ュ彛璋冪敤浠g爜 ... + } +} +``` + +### 姘翠环绠$悊娴佺▼ + +1. **搴旂敤鍚姩**: MainActivity鍚姩鍚庡欢鏃�20绉掕幏鍙栨按浠凤紝閬垮厤褰卞搷鍚姩鎬ц兘 +2. **鍏ㄥ眬瀛樺偍**: 鑾峰彇鍒扮殑姘翠环瀛樺偍鍦˙aseApplication.waterPrice涓� +3. **鎸夐渶鑾峰彇**: 鍦ㄩ渶瑕佷娇鐢ㄦ按浠风殑鐣岄潰锛堝鍏呭�肩晫闈級妫�鏌ユ按浠锋槸鍚︿负绌� +4. **閲嶆柊鑾峰彇**: 濡傛灉姘翠环涓虹┖鎴栦负0锛屽垯閲嶆柊璋冪敤鎺ュ彛鑾峰彇 +5. **榛樿澶勭悊**: 濡傛灉鑾峰彇澶辫触锛屼娇鐢ㄩ粯璁ゆ按浠�0.9鍏� +6. **瀹炴椂浣跨敤**: 鍦ㄥ厖鍊肩瓑涓氬姟涓娇鐢ㄦ渶鏂扮殑姘翠环淇℃伅 + +### 鎶�鏈壒鐐� + +1. **鎬ц兘浼樺寲**: 寤舵椂鑾峰彇閬垮厤褰卞搷搴旂敤鍚姩閫熷害 +2. **鍏ㄥ眬鍏变韩**: 姘翠环淇℃伅鍦˙aseApplication涓叏灞�鍏变韩 +3. **鎸夐渶鍒锋柊**: 鍦ㄩ渶瑕佹椂妫�鏌ュ苟閲嶆柊鑾峰彇姘翠环 +4. **瀹归敊澶勭悊**: 鑾峰彇澶辫触鏃朵娇鐢ㄩ粯璁ゆ按浠凤紝纭繚涓氬姟姝e父杩涜 +5. **鍐呭瓨绠$悊**: 姝g‘澶勭悊Handler鍥炶皟锛岄槻姝㈠唴瀛樻硠婕� + +### 浣跨敤娉ㄦ剰浜嬮」 + +1. **寤舵椂璁剧疆**: MainActivity涓殑20绉掑欢鏃跺彲鏍规嵁瀹為檯闇�姹傝皟鏁� +2. **榛樿姘翠环**: 榛樿姘翠环0.9鍏冨彲鏍规嵁瀹為檯涓氬姟闇�姹備慨鏀� +3. **閿欒澶勭悊**: 姘翠环鑾峰彇澶辫触鏃朵笉鏄剧ず閿欒淇℃伅锛岄伩鍏嶅奖鍝嶇敤鎴蜂綋楠� +4. **鏁版嵁鏍煎紡**: 姘翠环浣跨敤Double绫诲瀷瀛樺偍锛屼娇鐢ㄦ椂鏍煎紡鍖栦负涓や綅灏忔暟 +5. **鐢熷懡鍛ㄦ湡**: 娉ㄦ剰鍦ˋctivity閿�姣佹椂娓呯悊鐩稿叧璧勬簮 + +### 鐩稿叧鏁版嵁绫� + +```kotlin +// 姘翠环缁撴灉鏁版嵁绫� +data class WaterPriceResult( + val price: Double // 姘翠环 +) +``` + ## 璐$尞鎸囧崡 1. Fork 椤圭洰 diff --git a/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcReadHelper.java b/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcReadHelper.java index 331512d..177e0d2 100644 --- a/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcReadHelper.java +++ b/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/BaseNfcReadHelper.java @@ -5,6 +5,8 @@ import com.dayu.baselibrary.bean.BaseManagerToUserCard; import com.dayu.baselibrary.bean.BaseUserCardCard; +import org.jetbrains.annotations.NotNull; + import java.util.List; import java.util.Map; @@ -49,7 +51,18 @@ * * @return */ - public abstract String getCradTypeAndCardNumber(); + public String getCradTypeAndCardNumber(){ + return getCradTypeAndCardNumber(1); + }; + + /** + * 鑾峰彇鍗$墖绫诲瀷鍜屽崱鍙� + * + * @return + */ + public String getCradTypeAndCardNumber(int sectorIndex){ + return null; + }; /** * 璇诲彇NFC鍗$殑鐗瑰畾鎵囧尯淇℃伅 @@ -81,6 +94,8 @@ return null; } + + /** * 杩斿洖鐩戝惉绫� */ diff --git a/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java b/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java index ef74114..cb24575 100644 --- a/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java +++ b/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java @@ -7,6 +7,8 @@ import android.nfc.tech.MifareClassic; import android.util.Log; +import androidx.annotation.NonNull; + import com.dayu.baselibrary.bean.BaseManagerToUserCard; import com.dayu.baselibrary.bean.BaseUserCardCard; import com.dayu.baselibrary.tools.HexUtil; @@ -29,8 +31,6 @@ private Tag tag; // private NFCCallback callback; private static NativeNfcReadHelper helper; - - @Override @@ -435,9 +435,6 @@ } - - - public String getCardNumberNoClose() { if (tag == null) { return ""; @@ -483,13 +480,19 @@ return ""; } + @Override + public String getCradTypeAndCardNumber() { + return getCradTypeAndCardNumber(1); + } + + /** * 鑾峰彇鍗$墖绫诲瀷鍜屽崱鍙� * * @return */ - @Override - public String getCradTypeAndCardNumber() { + + public String getCradTypeAndCardNumber(int sectorIndex) { MifareClassic mfc = MifareClassic.get(tag); if (null != mfc) { @@ -498,10 +501,18 @@ StringBuilder strData = new StringBuilder(); //鑾峰彇褰撳墠鍗″彿 boolean isOpen = false; - for (int i = 0; i < listKeyA.size(); i++) { - if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) { + if (!listKeyA.isEmpty()) { + for (int i = 0; i < listKeyA.size(); i++) { + if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) { + isOpen = true; + break; + } + } + } else if (!listA_PS.isEmpty()) { + if (mfc.authenticateSectorWithKeyA(0, listA_PS.get(0))) { isOpen = true; - break; + } else if (mfc.authenticateSectorWithKeyA(0, defauleKey)) { + isOpen = true; } } if (isOpen) { @@ -517,15 +528,23 @@ } } //鑾峰彇鍗$墖绫诲瀷 - for (int i = 0; i < listKeyA.size(); i++) { - if (mfc.authenticateSectorWithKeyA(1, listKeyA.get(i))) { + if (!listKeyA.isEmpty()) { + for (int i = 0; i < listKeyA.size(); i++) { + if (mfc.authenticateSectorWithKeyA(sectorIndex, listKeyA.get(i))) { + isOpen = true; + break; + } + } + } else if (!listA_PS.isEmpty()) { + if (mfc.authenticateSectorWithKeyA(sectorIndex, listA_PS.get(sectorIndex))) { isOpen = true; - break; + } else if (mfc.authenticateSectorWithKeyA(sectorIndex, defauleKey)) { + isOpen = true; } } if (isOpen) { - int bIndex = mfc.sectorToBlock(1); - byte[] data = mfc.readBlock(bIndex + 0); + int bIndex = mfc.sectorToBlock(sectorIndex); + byte[] data = mfc.readBlock(bIndex + sectorIndex); if (data != null && data.length > 0) { String hex = HexUtil.byteToHex(data[0]); strData.append(hex); @@ -676,4 +695,6 @@ } + + } diff --git a/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcReadAdapter.java b/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcReadAdapter.java index 9d9df56..515b27a 100644 --- a/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcReadAdapter.java +++ b/baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NfcReadAdapter.java @@ -3,9 +3,13 @@ import android.app.Activity; import android.content.Intent; +import androidx.annotation.NonNull; + import com.dayu.baselibrary.activity.BaseNfcActivity; import com.dayu.baselibrary.bean.BaseUserCardCard; import com.dayu.baselibrary.utils.ModelUtils; + +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -92,8 +96,15 @@ switch (BaseNfcActivity.adapterType) { case ModelUtils.defaultType: return nativeNfcReadHelper.getCradTypeAndCardNumber(); + } + return ""; + } - + @Override + public String getCradTypeAndCardNumber(int sectorIndex) { + switch (BaseNfcActivity.adapterType) { + case ModelUtils.defaultType: + return nativeNfcReadHelper.getCradTypeAndCardNumber(sectorIndex); } return ""; } @@ -126,4 +137,8 @@ } return null; } + + + + } diff --git a/generallibrary/src/main/java/com/dayu/general/BaseApplication.kt b/generallibrary/src/main/java/com/dayu/general/BaseApplication.kt index facf186..dd81a63 100644 --- a/generallibrary/src/main/java/com/dayu/general/BaseApplication.kt +++ b/generallibrary/src/main/java/com/dayu/general/BaseApplication.kt @@ -27,6 +27,11 @@ var blockId:String="" var blockName:String="" + // 姘翠环淇℃伅 + var waterPrice: Double = 0.0 + + // MainActivity鐨勫紩鐢紝鐢ㄤ簬璋冪敤姘翠环鑾峰彇鏂规硶 + private var mainActivityInstance: com.dayu.general.activity.MainActivity? = null var projectDataDao: ProjectDataDao? = null @@ -42,6 +47,25 @@ return myApplication as BaseApplication } + /** + * 璁剧疆MainActivity瀹炰緥 + */ + fun setMainActivity(activity: com.dayu.general.activity.MainActivity?) { + mainActivityInstance = activity + } + + /** + * 璇锋眰鑾峰彇姘翠环锛屽鏋滀负绌哄垯璋冪敤MainActivity鐨勮幏鍙栨柟娉� + */ + fun requestWaterPrice(): Double { + if (waterPrice <= 0.0) { + // 濡傛灉姘翠环涓虹┖涓擬ainActivity瀹炰緥瀛樺湪锛屽垯璋冪敤鑾峰彇鏂规硶 + mainActivityInstance?.getWaterPriceFromActivity() + } + // 濡傛灉姘翠环浠嶄负0锛岃繑鍥為粯璁ゅ�� + return if (waterPrice > 0.0) waterPrice else 0.9 + } + diff --git a/generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt b/generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt index 87af8d5..81b20a0 100644 --- a/generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt +++ b/generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt @@ -2,6 +2,8 @@ import android.content.Intent import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.view.KeyEvent import android.view.LayoutInflater import android.widget.Toast @@ -13,6 +15,7 @@ import com.dayu.general.R import com.dayu.general.adapter.TabAdapter import com.dayu.general.bean.net.UserInfoResult +import com.dayu.general.bean.net.WaterPriceResult import com.dayu.general.databinding.ActivityMainBinding import com.dayu.general.net.ApiManager import com.dayu.general.net.BaseResponse @@ -22,15 +25,33 @@ var binding: ActivityMainBinding? = null private val fragments: ArrayList<Fragment> = ArrayList() var mExitTime: Long = 0 + private val handler = Handler(Looper.getMainLooper()) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(LayoutInflater.from(this)) setContentView(binding?.root) + + // 娉ㄥ唽MainActivity瀹炰緥鍒癇aseApplication + BaseApplication.setMainActivity(this) + setupFragments() initView() initTab() getUserInfo() + + // 寤舵椂20绉掑悗鑾峰彇姘翠环 + handler.postDelayed({ + getWaterPriceFromActivity() + }, 20000) // 20绉掑欢鏃� + } + + override fun onDestroy() { + super.onDestroy() + // 娓呯悊Handler鍥炶皟锛岄槻姝㈠唴瀛樻硠婕� + handler.removeCallbacksAndMessages(null) + // 娓呯悊BaseApplication涓殑MainActivity寮曠敤 + BaseApplication.setMainActivity(null) } override fun onNfcBack(intent: Intent) { @@ -45,6 +66,37 @@ } } + /** + * 鑾峰彇姘翠环淇℃伅 - 鍏紑鏂规硶渚涘叾浠栧湴鏂硅皟鐢� + */ + fun getWaterPriceFromActivity() { + // 濡傛灉姘翠环宸插瓨鍦ㄤ笖澶т簬0锛屽垯涓嶉噸澶嶈幏鍙� + if (BaseApplication.waterPrice > 0.0) { + return + } + + ApiManager.getInstance().requestGetHideLoading( + this, + "terminal/client/getWaterPrice", + WaterPriceResult::class.java, + null, + object : SubscriberListener<BaseResponse<WaterPriceResult>>() { + override fun onNext(response: BaseResponse<WaterPriceResult>) { + if (response.success && response.code == "0001") { + // 鑾峰彇姘翠环鎴愬姛锛屼繚瀛樺埌BaseApplication + response.content?.let { waterPriceResult -> + BaseApplication.waterPrice = waterPriceResult.price + } + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + // 缃戠粶寮傚父鏃朵笉鏄剧ず閿欒淇℃伅锛岄伩鍏嶅奖鍝嶇敤鎴蜂綋楠� + } + } + ) + } private fun getUserInfo() { // 浣跨敤姝g‘鐨勭被鍨嬪弬鏁� diff --git a/generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt b/generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt index e21fe66..dbdc7ff 100644 --- a/generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt +++ b/generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt @@ -83,10 +83,21 @@ binding?.cardData?.text = textData.toString() } + CardOperationType.Recharge -> { + var textData = StringBuilder() + textData.append("鐢ㄦ埛鍏呭�糪n") + textData.append("璁㈠崟鍙凤細" + orderNumber + "\n") + if (userCard.balance != 0) { + val balanceInYuan = userCard.balance / 100.0 // 杞崲涓哄厓 + textData.append("鍏呭�奸噾棰濓細" + String.format("%.2f", balanceInYuan) + "鍏�") + } + + binding?.cardData?.text = textData.toString() + } + CardOperationType.CancelCard -> TODO() CardOperationType.CheckCard -> TODO() CardOperationType.DeductCard -> TODO() - CardOperationType.Recharge -> TODO() CardOperationType.ReplaceCard -> TODO() null -> TODO() } @@ -136,10 +147,25 @@ } + CardOperationType.Recharge -> { + nfcWreatHelper.writeUserDataAsync(userCard, object : NFCCallBack { + override fun isSusses(flag: Boolean, msg: String?) { + // 纭繚Toast鍦ㄤ富绾跨▼涓皟鐢� + runOnUiThread { + if (flag) { + postCardData(cardType, cardAddr) + ToastUtil.show("鍏呭�煎啓鍗℃垚鍔�!") + } else { + ToastUtil.show("鍏呭�煎啓鍗″け璐�: ${msg ?: "鏈煡閿欒"}") + } + } + } + }) + } + CardOperationType.CancelCard -> TODO() CardOperationType.CheckCard -> TODO() CardOperationType.DeductCard -> TODO() - CardOperationType.Recharge -> TODO() CardOperationType.ReplaceCard -> TODO() null -> TODO() } diff --git a/generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt b/generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt index 3d1a949..d8d053a 100644 --- a/generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt +++ b/generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt @@ -3,27 +3,36 @@ import android.content.Context import android.content.Intent import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher import android.util.TypedValue import android.view.View +import android.widget.EditText import android.widget.RadioButton import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.dayu.baselibrary.net.subscribers.SubscriberListener import com.dayu.baselibrary.utils.ToastUtil import com.dayu.baselibrary.view.TitleBar +import com.dayu.general.BaseApplication import com.dayu.general.R import com.dayu.general.bean.net.CardInfoResult import com.dayu.general.bean.net.PaymentMethod import com.dayu.general.bean.net.PaymentMethodResponse +import com.dayu.general.bean.net.RechargeRequest +import com.dayu.general.bean.net.RechargeResult +import com.dayu.general.bean.card.UserCard import com.dayu.general.databinding.ActivityRechargeDetailBinding import com.dayu.general.net.ApiManager import com.dayu.general.net.BaseResponse +import com.dayu.general.tool.CardOperationType class RechargeDetailActivity : AppCompatActivity() { private lateinit var binding: ActivityRechargeDetailBinding private var cardInfo: CardInfoResult? = null private var cardAddress: String? = null + private var userCard: UserCard? = null // 鏀粯鏂瑰紡鐩稿叧灞炴�� private var paymentMethod: String = "鐜伴噾" @@ -33,11 +42,13 @@ companion object { private const val EXTRA_CARD_INFO = "extra_card_info" private const val EXTRA_CARD_ADDRESS = "extra_card_address" + private const val EXTRA_USER_CARD = "extra_user_card" - fun start(context: Context, cardInfo: CardInfoResult?, cardAddress: String?) { + fun start(context: Context, cardInfo: CardInfoResult?, cardAddress: String?, userCard: UserCard?) { val intent = Intent(context, RechargeDetailActivity::class.java) intent.putExtra(EXTRA_CARD_INFO, cardInfo) intent.putExtra(EXTRA_CARD_ADDRESS, cardAddress) + intent.putExtra(EXTRA_USER_CARD, userCard) context.startActivity(intent) } } @@ -53,11 +64,14 @@ // 鑾峰彇浼犻�掔殑鏁版嵁 cardInfo = intent.getSerializableExtra(EXTRA_CARD_INFO) as? CardInfoResult cardAddress = intent.getStringExtra(EXTRA_CARD_ADDRESS) + userCard = intent.getSerializableExtra(EXTRA_USER_CARD) as? UserCard initView() displayCardInfo() // 鑾峰彇鏀粯鏂瑰紡 getPaymentMethods() + // 纭繚姘翠环鍙敤锛堝鏋滀负绌轰細鑷姩瑙﹀彂MainActivity鑾峰彇锛� + BaseApplication.requestWaterPrice() } private fun initView() { @@ -68,9 +82,63 @@ // 璁剧疆鎸夐挳鐐瑰嚮浜嬩欢 binding.rechargeRegistBtn.setOnClickListener { - // 澶勭悊鍐欏崱閫昏緫 - handleWriteCard() + // 澶勭悊鍏呭�奸�昏緫 + handleRecharge() } + + // 璁剧疆閲戦杈撳叆闄愬埗 + setupAmountInputLimit(binding.rechargeMorny) + setupAmountInputLimit(binding.rechargeWater) + } + + /** + * 璁剧疆閲戦杈撳叆闄愬埗锛屾渶澶氫繚鐣欎袱浣嶅皬鏁� + */ + private fun setupAmountInputLimit(editText: EditText) { + editText.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} + + override fun afterTextChanged(s: Editable?) { + val text = s.toString() + if (text.isEmpty()) return + + // 妫�鏌ユ槸鍚﹀寘鍚皬鏁扮偣 + if (text.contains(".")) { + val parts = text.split(".") + if (parts.size == 2) { + val decimalPart = parts[1] + // 濡傛灉灏忔暟浣嶈秴杩�2浣嶏紝鎴彇鍓嶄袱浣� + if (decimalPart.length > 2) { + val newText = "${parts[0]}.${decimalPart.substring(0, 2)}" + editText.removeTextChangedListener(this) + editText.setText(newText) + editText.setSelection(newText.length) + editText.addTextChangedListener(this) + } + } + } + + // 闃叉杈撳叆澶氫釜灏忔暟鐐� + val dotCount = text.count { it == '.' } + if (dotCount > 1) { + val newText = text.substring(0, text.lastIndexOf('.')) + editText.removeTextChangedListener(this) + editText.setText(newText) + editText.setSelection(newText.length) + editText.addTextChangedListener(this) + } + + // 闃叉浠ュ皬鏁扮偣寮�澶� + if (text.startsWith(".")) { + editText.removeTextChangedListener(this) + editText.setText("0$text") + editText.setSelection(editText.text.length) + editText.addTextChangedListener(this) + } + } + }) } /** @@ -180,7 +248,16 @@ binding.redInitCode.text = cardAddress ?: "" binding.userName.text = info.userName ?: "" binding.redCardNum.text = info.cardNum ?: "" - binding.redRemainderBlance.text = "${info.balance ?: 0} 鍏�" + + // 浣跨敤鐢ㄦ埛鍗′腑鐨勪綑棰濇樉绀� + val balance = userCard?.let { + // 灏嗗垎杞崲涓哄厓锛屼繚鐣欎袱浣嶅皬鏁� + String.format("%.2f", it.balance / 100.0) + } ?: run { + // 濡傛灉鐢ㄦ埛鍗′负绌猴紝鍒欎娇鐢ㄦ湇鍔″櫒杩斿洖鐨勪綑棰� + String.format("%.2f", info.balance ?: 0.0) + } + binding.redRemainderBlance.text = "$balance 鍏�" // 璁剧疆鍗$姸鎬佸拰瀵瑰簲棰滆壊 val cardStatus = when (info.status) { @@ -203,7 +280,10 @@ } } - private fun handleWriteCard() { + /** + * 澶勭悊鍏呭�奸�昏緫 + */ + private fun handleRecharge() { // 楠岃瘉鍏呭�奸噾棰� val rechargeAmountStr = binding.rechargeMorny.text.toString().trim() if (rechargeAmountStr.isEmpty()) { @@ -235,20 +315,115 @@ 0.0 } - // 鏄剧ず纭淇℃伅 - val totalAmount = rechargeAmount + bonusAmount - val confirmMessage = """ - 纭鍏呭�间俊鎭細 - 鍗″彿锛�${cardAddress} - 鍏呭�奸噾棰濓細${rechargeAmount}鍏� - 璧犻�侀噾棰濓細${bonusAmount}鍏� - 鎬婚噾棰濓細${totalAmount}鍏� - 鏀粯鏂瑰紡锛�${paymentMethod} - """.trimIndent() + // 璋冪敤鍏呭�兼帴鍙� + callRechargeApi(rechargeAmount, bonusAmount) + } - ToastUtil.show(confirmMessage) + /** + * 璋冪敤鍏呭�兼帴鍙� + */ + private fun callRechargeApi(rechargeAmount: Double, bonusAmount: Double) { + val cardNum = cardInfo?.cardNum ?: cardAddress ?: "" + if (cardNum.isEmpty()) { + ToastUtil.show("鍗″彿淇℃伅缂哄け") + return + } - // TODO: 璋冪敤鍐欏崱API - // 杩欓噷鍙互娣诲姞瀹為檯鐨勫啓鍗¢�昏緫 + // 鑾峰彇姘翠环锛堝鏋滀负绌轰細鑷姩瑙﹀彂MainActivity鑾峰彇锛� + val currentWaterPrice = BaseApplication.requestWaterPrice() + + // 鏋勫缓鍏呭�艰姹傚弬鏁� + val rechargeRequest = RechargeRequest( + rechargeType = 2, + cardNum = cardNum, + money = String.format("%.0f", rechargeAmount), + amount = String.format("%.0f", bonusAmount), + gift = String.format("%.0f", bonusAmount), + paymentId = paymentId.toString(), + price = String.format("%.2f", currentWaterPrice), // 浣跨敤缁熶竴鑾峰彇鐨勬按浠� + remarks = "鍏呭��", + operator = BaseApplication.userId // 榛樿鎿嶄綔鍛業D锛屽彲浠ユ牴鎹疄闄呮儏鍐佃皟鏁� + ) + + // 杞崲涓篗ap鏍煎紡 + val params = mapOf( + "rechargeType" to rechargeRequest.rechargeType, + "cardNum" to rechargeRequest.cardNum, + "money" to rechargeRequest.money, + "amount" to rechargeRequest.amount, + "gift" to rechargeRequest.gift, + "paymentId" to rechargeRequest.paymentId, + "price" to rechargeRequest.price, + "remarks" to rechargeRequest.remarks, + "operator" to rechargeRequest.operator + ) + + ApiManager.getInstance().requestPostLoading( + this, + "terminal/card/termRecharge", + RechargeResult::class.java, + params, + object : SubscriberListener<BaseResponse<RechargeResult>>() { + override fun onNext(response: BaseResponse<RechargeResult>) { + if (response.success && response.code == "0001") { + // 鍏呭�兼垚鍔燂紝璺宠浆鍒板啓鍗$晫闈� + response.content?.let { rechargeResult -> + startWriteCardActivity(rechargeResult, rechargeAmount, bonusAmount) + } ?: run { + ToastUtil.show("鍏呭�兼垚鍔熶絾杩斿洖鏁版嵁涓虹┖") + } + } else { + ToastUtil.show("鍏呭�煎け璐�: ${response.msg ?: "鏈煡閿欒"}") + } + } + + override fun onError(e: Throwable?) { + super.onError(e) + ToastUtil.show("鍏呭�煎け璐�: ${e?.message ?: "缃戠粶寮傚父"}") + } + } + ) + } + + /** + * 鍚姩鍐欏崱鐣岄潰 + */ + private fun startWriteCardActivity(rechargeResult: RechargeResult, rechargeAmount: Double, bonusAmount: Double) { + try { + // 鍒涘缓UserCard瀵硅薄鐢ㄤ簬鍐欏崱 + val userCard = UserCard().apply { + // 璁剧疆鐢ㄦ埛鍗′俊鎭� + cardInfo?.let { info -> + userCode = info.cardNum ?: "" + balance = ((rechargeAmount + bonusAmount) * 100).toInt() // 杞崲涓哄垎 + } + + // 璁剧疆鍏朵粬蹇呰淇℃伅 + projectCode = rechargeResult.projectNo + waterPrice = rechargeResult.waterPrice.toFloat() + rechargeDate = java.util.Calendar.getInstance() + } + + // 鍚姩鍐欏崱Activity + val intent = Intent(this, NfcWreatActivity::class.java).apply { + putExtra("cardType", "USER_CARD") // 鐢ㄦ埛鍗$被鍨� + putExtra("cardAddr", cardAddress) + putExtra("operationTypeCode", CardOperationType.Recharge.code) + putExtra("orderNumber", rechargeResult.orderNo) + putExtra("userCard", userCard) + } + + startActivity(intent) + + // 鏄剧ず鎴愬姛淇℃伅 + val formattedRecharge = String.format("%.2f", rechargeAmount) + val formattedBonus = String.format("%.2f", bonusAmount) + val formattedTotal = String.format("%.2f", rechargeAmount + bonusAmount) + + ToastUtil.show("鍏呭�艰鍗曞垱寤烘垚鍔焅n璁㈠崟鍙�: ${rechargeResult.orderNo}\n鍏呭�奸噾棰�: ${formattedRecharge}鍏僜n璧犻�侀噾棰�: ${formattedBonus}鍏僜n鎬婚噾棰�: ${formattedTotal}鍏僜n璇疯创鍗¤繘琛屽啓鍗℃搷浣�") + + } catch (e: Exception) { + ToastUtil.show("鍚姩鍐欏崱鐣岄潰澶辫触: ${e.message}") + } } } \ No newline at end of file diff --git a/generallibrary/src/main/java/com/dayu/general/activity/RechargeFragment.kt b/generallibrary/src/main/java/com/dayu/general/activity/RechargeFragment.kt index 79c9fbd..51136ba 100644 --- a/generallibrary/src/main/java/com/dayu/general/activity/RechargeFragment.kt +++ b/generallibrary/src/main/java/com/dayu/general/activity/RechargeFragment.kt @@ -10,11 +10,14 @@ import com.dayu.baselibrary.tools.nfc.NfcReadAdapter import com.dayu.baselibrary.utils.ToastUtil import com.dayu.baselibrary.view.ConfirmDialog +import com.dayu.baselibrary.view.TipDialog import com.dayu.general.bean.net.CardInfoResult import com.dayu.general.databinding.FragmentRechargeBinding import com.dayu.general.net.ApiManager import com.dayu.general.net.BaseResponse import com.dayu.general.tool.NfcReadHelper +import com.dayu.general.bean.card.UserCard +import com.dayu.general.tool.CardCommon class RechargeFragment : Fragment() { var binding: FragmentRechargeBinding? = null @@ -28,25 +31,25 @@ binding = FragmentRechargeBinding.inflate(inflater, container, false) return binding?.root } - + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initView() } - - private fun initView() { - // 鍒濆鍖栫晫闈㈡樉绀鸿鍗$姸鎬� - binding?.rechargeReadLL?.visibility = View.VISIBLE - } - - - private fun resetView() { - // 閲嶇疆鐣岄潰鏄剧ず璇诲崱鐘舵�� - binding?.rechargeReadLL?.visibility = View.VISIBLE + + /** + * 鏄剧ず纭瀵硅瘽妗� + */ + private fun showConfirmDialog(message: String, onConfirm: () -> Unit) { + activity?.let { activity -> + val confirmDialog = TipDialog(activity, message) { + onConfirm() + } + confirmDialog.show() + } } - + /** * 澶勭悊NFC鍒峰崱淇℃伅 * 璇ユ柟娉曠敱MainActivity璋冪敤 @@ -56,32 +59,60 @@ try { // 妫�鏌ntent涓槸鍚﹀寘鍚玁FC Tag if (intent.getParcelableExtra<android.nfc.Tag>(android.nfc.NfcAdapter.EXTRA_TAG) == null) { - ToastUtil.show("鏈娴嬪埌NFC鍗$墖锛岃纭繚鍗$墖宸叉纭斁缃�") + showConfirmDialog("鏈娴嬪埌NFC鍗$墖锛岃纭繚鍗$墖宸叉纭斁缃�") { + } return } - - // 浣跨敤NfcReadAdapter璇诲彇鍗″彿 + val nfcAdapter = NfcReadHelper.getInstance(intent, activity) - cardNumber = nfcAdapter.getCardNumber() - - if (cardNumber.isNullOrEmpty()) { - ToastUtil.show("璇诲崱澶辫触锛岃閲嶆柊鍒峰崱") + val cardTypeAndCardNumber = nfcAdapter.getCardTypeAndCardNumber() + if (cardTypeAndCardNumber.isNullOrBlank() || !cardTypeAndCardNumber.contains(",")) { + showConfirmDialog("鍗$墖淇℃伅璇诲彇澶辫触锛岃閲嶆柊鍒峰崱") { + } + return + } + val parts = cardTypeAndCardNumber.split(",") + if (parts.size < 2) { + showConfirmDialog("鍗$墖淇℃伅鏍煎紡寮傚父锛岃閲嶆柊鍒峰崱") { + } + return + } + val cardNumber = parts[0] + val cardType = parts[1] + this.cardNumber = cardNumber + if (cardNumber.isBlank()) { + showConfirmDialog("鍗″彿涓虹┖锛屾棤娉曡繘琛屽厖鍊硷紝璇烽噸鏂板埛鍗�") { + } + return + } + if (cardType != CardCommon.USER_CARD_TYPE_1) { + showConfirmDialog("璇ュ崱鐗囦笉鏄敤鎴峰崱锛岃浣跨敤姝g‘鐨勭敤鎴峰崱杩涜鍏呭�兼搷浣溿��") { + } + return + } + + // 瑙f瀽鐢ㄦ埛鍗℃暟鎹� + val userCard = nfcAdapter.getUserCardData() + if (userCard == null) { + showConfirmDialog("瑙f瀽鍗$墖鏁版嵁澶辫触锛岃閲嶆柊鍒峰崱") { + } return } // 鏍规嵁鍗″彿鑾峰彇鍗$墖璇︾粏淇℃伅 - getCardInfo(cardNumber!!) + getCardInfo(cardNumber, userCard) } catch (e: Exception) { - ToastUtil.show("璇诲崱寮傚父锛�${e.message}") + showConfirmDialog("璇诲崱寮傚父锛�${e.message}") { + } e.printStackTrace() } } } - + /** * 鑾峰彇鍗$墖璇︾粏淇℃伅 */ - private fun getCardInfo(cardNumber: String) { + private fun getCardInfo(cardNumber: String, userCard: UserCard) { activity?.let { activity -> val map = mutableMapOf<String, Any>() map["cardAddr"] = cardNumber @@ -93,8 +124,8 @@ object : SubscriberListener<BaseResponse<CardInfoResult>>() { override fun onNext(t: BaseResponse<CardInfoResult>) { if (t.success) { - // 璺宠浆鍒板厖鍊艰鎯呴〉闈� - RechargeDetailActivity.start(activity, t.content, cardNumber) + // 璺宠浆鍒板厖鍊艰鎯呴〉闈紝浼犻�掔敤鎴峰崱淇℃伅 + RechargeDetailActivity.start(activity, t.content, cardNumber, userCard) } else { // 澶勭悊鑾峰彇澶辫触鐨勬儏鍐� handleCardInfoError(t.code, t.msg) @@ -103,28 +134,28 @@ override fun onError(e: Throwable?) { super.onError(e) - ToastUtil.show("鑾峰彇鍗′俊鎭け璐�: ${e?.message ?: "缃戠粶寮傚父锛岃妫�鏌ョ綉缁滆繛鎺�"}") - // 閲嶇疆鐣岄潰鐘舵�� - resetView() + showConfirmDialog("鑾峰彇鍗′俊鎭け璐�: ${e?.message ?: "缃戠粶寮傚父锛岃妫�鏌ョ綉缁滆繛鎺�"}") { + } } } ) } } - + /** * 澶勭悊鍗′俊鎭幏鍙栭敊璇� */ private fun handleCardInfoError(code: String?, msg: String?) { val errorTitle: String val errorMessage: String - + when (code) { "1001" -> { // 鏁版嵁涓嶅瓨鍦ㄧ殑鐗规畩澶勭悊 errorTitle = "鍗$墖鏈敞鍐�" errorMessage = "璇ュ崱鐗囨湭鍦ㄧ郴缁熶腑娉ㄥ唽锛岃鍏堣繘琛屽紑鍗℃搷浣滃悗鍐嶅厖鍊笺��" } + else -> { // 鍏朵粬閿欒鐨勯�氱敤澶勭悊 errorTitle = "鑾峰彇鍗′俊鎭け璐�" @@ -137,14 +168,9 @@ } } } - + // 鏄剧ず纭瀵硅瘽妗� - activity?.let { activity -> - val confirmDialog = ConfirmDialog(activity, errorTitle, errorMessage) { - // 鐐瑰嚮纭鎸夐挳鍚庡叧闂璇濇骞堕噸缃晫闈� - resetView() - } - confirmDialog.show() + showConfirmDialog(errorMessage) { } } } \ No newline at end of file diff --git a/generallibrary/src/main/java/com/dayu/general/bean/net/RechargeRequest.kt b/generallibrary/src/main/java/com/dayu/general/bean/net/RechargeRequest.kt new file mode 100644 index 0000000..9232db4 --- /dev/null +++ b/generallibrary/src/main/java/com/dayu/general/bean/net/RechargeRequest.kt @@ -0,0 +1,18 @@ +package com.dayu.general.bean.net + +import java.io.Serializable + +/** + * 鍏呭�艰姹傚弬鏁� + */ +data class RechargeRequest( + val rechargeType: Int, // 鍏呭�肩被鍨� + val cardNum: String, // 鍗″彿 + val money: String, // 鍏呭�奸噾棰� + val amount: String, // 鍏呭�兼暟閲� + val gift: String, // 璧犻�侀噾棰� + val paymentId: String, // 鏀粯鏂瑰紡ID + val price: String, // 鍗曚环 + val remarks: String, // 澶囨敞 + val operator: String // 鎿嶄綔鍛業D +) : Serializable \ No newline at end of file diff --git a/generallibrary/src/main/java/com/dayu/general/bean/net/RechargeResult.kt b/generallibrary/src/main/java/com/dayu/general/bean/net/RechargeResult.kt new file mode 100644 index 0000000..d6507a3 --- /dev/null +++ b/generallibrary/src/main/java/com/dayu/general/bean/net/RechargeResult.kt @@ -0,0 +1,14 @@ +package com.dayu.general.bean.net + +import java.io.Serializable + +/** + * 鍏呭�兼帴鍙h繑鍥炵粨鏋� + */ +data class RechargeResult( + val projectNo: Int, // 椤圭洰缂栧彿 + val cardNum: String, // 鍗″彿 + val orderNo: String, // 璁㈠崟鍙� + val waterPrice: Double, // 姘翠环 + val time: String // 鏃堕棿 +) : Serializable \ No newline at end of file diff --git a/generallibrary/src/main/java/com/dayu/general/bean/net/WaterPriceResult.kt b/generallibrary/src/main/java/com/dayu/general/bean/net/WaterPriceResult.kt new file mode 100644 index 0000000..c21d13d --- /dev/null +++ b/generallibrary/src/main/java/com/dayu/general/bean/net/WaterPriceResult.kt @@ -0,0 +1,10 @@ +package com.dayu.general.bean.net + +import java.io.Serializable + +/** + * 姘翠环鎺ュ彛杩斿洖缁撴灉 + */ +data class WaterPriceResult( + val price: Double // 姘翠环 +) : Serializable \ No newline at end of file diff --git a/generallibrary/src/main/java/com/dayu/general/tool/CardOperationType.kt b/generallibrary/src/main/java/com/dayu/general/tool/CardOperationType.kt index aee7aa4..7e665e6 100644 --- a/generallibrary/src/main/java/com/dayu/general/tool/CardOperationType.kt +++ b/generallibrary/src/main/java/com/dayu/general/tool/CardOperationType.kt @@ -21,6 +21,8 @@ 3 -> CancelCard 4 -> ReplaceCard 5 -> DeductCard + 6 -> CleanCard + 7 -> CheckCard else -> null } } diff --git a/generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt b/generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt index 84d7111..7fc95f2 100644 --- a/generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt +++ b/generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt @@ -6,6 +6,7 @@ import android.widget.RelativeLayout import com.dayu.baselibrary.tools.nfc.BaseNfcReadHelper import com.dayu.baselibrary.tools.nfc.NfcReadAdapter +import com.dayu.general.bean.card.UserCard import com.pnikosis.materialishprogress.ProgressWheel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Observable @@ -165,7 +166,7 @@ */ fun getCardTypeAndCardNumber(): String { return try { - adapter.cradTypeAndCardNumber + adapter.getCradTypeAndCardNumber(7) } catch (e: Exception) { e.printStackTrace() "" @@ -315,4 +316,27 @@ fun clearDisposables() { compositeDisposable.clear() } -} \ No newline at end of file + + /** + * 璇诲彇鐢ㄦ埛鍗℃暟鎹� + * @return UserCard瀵硅薄锛屽鏋滆鍙栧け璐ュ垯杩斿洖null + */ + fun getUserCardData(): UserCard? { + return try { + // 鑾峰彇鍩虹鍗℃暟鎹� + val baseCard = adapter.getUserCardData(UserCard()) + // 濡傛灉鑾峰彇鎴愬姛涓旀槸UserCard绫诲瀷锛屽垯杩斿洖 + if (baseCard is UserCard) { + baseCard + } else { + null + } + } catch (e: Exception) { + e.printStackTrace() + null + } + } + + +} + diff --git a/generallibrary/src/main/res/layout/activity_recharge_detail.xml b/generallibrary/src/main/res/layout/activity_recharge_detail.xml index 19dad3f..c51e7ae 100644 --- a/generallibrary/src/main/res/layout/activity_recharge_detail.xml +++ b/generallibrary/src/main/res/layout/activity_recharge_detail.xml @@ -133,7 +133,7 @@ android:text="" android:textColor="#333333" android:textSize="14sp" - android:textStyle="bold" /> + /> </LinearLayout> <!-- 鍗$姸鎬� --> @@ -266,6 +266,8 @@ android:background="@drawable/edit_text_bg" android:hint="璇疯緭鍏ュ厖鍊奸噾棰�" android:inputType="numberDecimal" + android:digits="0123456789." + android:maxLength="10" android:padding="12dp" android:textSize="14sp" android:maxLines="1" /> @@ -293,6 +295,8 @@ android:background="@drawable/edit_text_bg" android:hint="璧犻�侀噾棰�(閫夊~)" android:inputType="numberDecimal" + android:digits="0123456789." + android:maxLength="10" android:padding="12dp" android:textSize="14sp" android:maxLines="1" /> diff --git a/generallibrary/src/main/res/layout/dialog_search.xml b/generallibrary/src/main/res/layout/dialog_search.xml index 5c4382a..e1e81c0 100644 --- a/generallibrary/src/main/res/layout/dialog_search.xml +++ b/generallibrary/src/main/res/layout/dialog_search.xml @@ -29,7 +29,7 @@ android:id="@+id/tv_farmer_name_label" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="16dp" + android:layout_marginTop="20dp" android:text="鍐滄埛鍚嶇О" android:textColor="#666666" android:textSize="14sp" @@ -39,11 +39,15 @@ <EditText android:id="@+id/et_farmer_name" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="6dp" + android:layout_height="48dp" + android:layout_marginTop="8dp" android:background="@drawable/edit_text_bg" android:hint="璇疯緭鍏ュ啘鎴峰悕绉帮紙閫夊~锛�" android:inputType="text" + android:paddingStart="16dp" + android:paddingTop="12dp" + android:paddingEnd="16dp" + android:paddingBottom="12dp" android:singleLine="true" android:textColorHint="#BBBBBB" android:textSize="15sp" @@ -53,7 +57,7 @@ android:id="@+id/tv_farmer_id_label" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="14dp" + android:layout_marginTop="18dp" android:text="鍐滄埛缂栧彿" android:textColor="#666666" android:textSize="14sp" @@ -63,11 +67,15 @@ <EditText android:id="@+id/et_farmer_id" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="6dp" + android:layout_height="48dp" + android:layout_marginTop="8dp" android:background="@drawable/edit_text_bg" android:hint="璇疯緭鍏ュ啘鎴风紪鍙凤紙閫夊~锛�" android:inputType="text" + android:paddingStart="16dp" + android:paddingTop="12dp" + android:paddingEnd="16dp" + android:paddingBottom="12dp" android:singleLine="true" android:textColorHint="#BBBBBB" android:textSize="15sp" @@ -77,7 +85,7 @@ android:id="@+id/tv_card_number_label" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="14dp" + android:layout_marginTop="18dp" android:text="鍗″彿" android:textColor="#666666" android:textSize="14sp" @@ -87,11 +95,15 @@ <EditText android:id="@+id/et_card_number" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="6dp" + android:layout_height="48dp" + android:layout_marginTop="8dp" android:background="@drawable/edit_text_bg" android:hint="璇疯緭鍏ュ崱鍙凤紙閫夊~锛�" android:inputType="text" + android:paddingStart="16dp" + android:paddingTop="12dp" + android:paddingEnd="16dp" + android:paddingBottom="12dp" android:singleLine="true" android:textColorHint="#BBBBBB" android:textSize="15sp" @@ -101,13 +113,13 @@ android:id="@+id/tv_cancel" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginTop="24dp" + android:layout_marginTop="28dp" android:layout_marginEnd="6dp" android:background="@drawable/cancel_button_ripple" android:clickable="true" android:focusable="true" - android:paddingTop="10dp" - android:paddingBottom="10dp" + android:paddingTop="12dp" + android:paddingBottom="12dp" android:stateListAnimator="@null" android:text="鍙栨秷" android:textColor="#666666" diff --git a/generallibrary/src/main/res/layout/fragment_recharge.xml b/generallibrary/src/main/res/layout/fragment_recharge.xml index 0edf2a1..8d8c8fe 100644 --- a/generallibrary/src/main/res/layout/fragment_recharge.xml +++ b/generallibrary/src/main/res/layout/fragment_recharge.xml @@ -4,12 +4,19 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/base_green_bg"> - + <com.dayu.baselibrary.view.TitleBar + android:id="@+id/titleBar" + android:layout_width="match_parent" + android:layout_height="@dimen/dimen_title_height" + android:background="@color/title_bar_bg" + android:elevation="4dp" + app:centerText="鍏呭��" /> <LinearLayout android:id="@+id/recharge_read_LL" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" + android:layout_below="@+id/titleBar" android:orientation="vertical" android:visibility="visible"> @@ -65,14 +72,13 @@ android:scaleType="fitCenter" android:src="@mipmap/nfc_write" /> - <!-- 鏄剧ず璇诲埌鐨勫崱鍙� --> <TextView android:id="@+id/red_initCode" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:gravity="center" - android:text="" + android:text="璇蜂繚鎸佹墜鎸佹満鍜屽崱鐗囦笉瑕佺Щ鍔�" android:textColor="#333333" android:textSize="@dimen/new_card_size" android:textStyle="bold" /> -- Gitblit v1.8.0