generallibrary/src/main/AndroidManifest.xml
@@ -126,6 +126,15 @@ <data android:mimeType="text/plain" /> </intent-filter> </activity> <activity android:name=".activity.CardDeductActivity" android:exported="false" android:launchMode="singleTop"> <intent-filter> <action android:name="android.nfc.action.ACTION_NDEF_DISCOVERED" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity> <meta-data android:name="BUGLY_APP_VERSION" generallibrary/src/main/java/com/dayu/general/activity/BSCardFragment.kt
@@ -60,6 +60,9 @@ binding.homeCancelCard.setOnClickListener { context?.let { CardCancelActivity.start(it) } } binding.homeDeduction.setOnClickListener { context?.let { CardDeductActivity.start(it) } } } } generallibrary/src/main/java/com/dayu/general/activity/CardCancelActivity.kt
@@ -244,12 +244,20 @@ binding.tvUserName.text = info.userName ?: "未知" binding.tvPhone.text = info.phone ?: "未绑定" // 根据status字段显示状态 val statusText = when (info.state) { 1 -> "正常" 2 -> "挂失" 3 -> "锁定" else -> "未知" // 根据state字段显示状态 val (statusText, statusColor) = when (info.state) { 1 -> Pair("正常", android.graphics.Color.parseColor("#4CAF50")) // 绿色 2 -> Pair("已注销", android.graphics.Color.parseColor("#FF5722")) // 深橙色 3 -> Pair("已挂失", android.graphics.Color.parseColor("#FF9800")) // 橙色 4 -> Pair("无效卡片", android.graphics.Color.parseColor("#F44336")) // 红色 else -> Pair("未知状态", android.graphics.Color.parseColor("#9E9E9E")) // 灰色 } binding.tvCardStatus.text = statusText binding.tvCardStatus.setTextColor(statusColor) if (info.state == 3) { binding.btnCancelCard.visibility = android.view.View.GONE } else { binding.btnCancelCard.visibility = android.view.View.VISIBLE } } } generallibrary/src/main/java/com/dayu/general/activity/CardDeductActivity.kt
New file @@ -0,0 +1,391 @@ package com.dayu.general.activity import android.content.Context import android.content.Intent import android.os.Bundle import com.dayu.baselibrary.net.subscribers.SubscriberListener import com.dayu.baselibrary.utils.MornyUtil import com.dayu.baselibrary.utils.ToastUtil import com.dayu.baselibrary.view.TipDialog import com.dayu.baselibrary.view.TitleBar import com.dayu.general.BaseApplication import com.dayu.general.bean.card.UserCard import com.dayu.general.bean.net.CardInfoResult import com.dayu.general.bean.net.CardDeductResult import com.dayu.general.databinding.ActivityCardDeductBinding import com.dayu.general.net.ApiManager import com.dayu.general.net.BaseResponse import com.dayu.general.tool.CardCommon import com.dayu.general.tool.CardOperationType import com.dayu.general.tool.NfcReadHelper /** * @author: AI Assistant * @desc: 补扣Activity * @since: 2025/6/17 */ class CardDeductActivity : BaseNfcActivity() { private lateinit var binding: ActivityCardDeductBinding private var cardNumber: String? = null private var cardInfo: CardInfoResult? = null private var userCard: UserCard? = null companion object { /** * 启动补扣Activity */ fun start(context: Context) { val intent = Intent(context, CardDeductActivity::class.java) context.startActivity(intent) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityCardDeductBinding.inflate(layoutInflater) setContentView(binding.root) initView() } private fun initView() { // 设置TitleBar的返回按钮点击事件 binding.titleBar.setOnItemclickListner(TitleBar.ClickType_LEFT_IMAGE) { finish() } // 设置补扣按钮点击事件 binding.btnDeduct.setOnClickListener { performCardDeduct() } } /** * 重置到读卡状态 */ private fun resetToReadingState() { binding.scrollReadCard.visibility = android.view.View.VISIBLE binding.cardInfoContainer.visibility = android.view.View.GONE binding.bottomButtonContainer.visibility = android.view.View.GONE cardNumber = null cardInfo = null binding.etDeductAmount.setText("") binding.etRemarks.setText("") } /** * 显示确认对话框 */ private fun showConfirmDialog(message: String, onConfirm: () -> Unit) { val confirmDialog = TipDialog(this, message) { onConfirm() } confirmDialog.show() } override fun onNfcBack(intent: Intent?) { intent?.let { // 处理正常的读卡操作 handleNfcIntent(it) } ?: run { showConfirmDialog("NFC数据异常,请重新刷卡") { } } } /** * 处理NFC刷卡信息 */ private fun handleNfcIntent(intent: Intent) { try { // 检查intent中是否包含NFC Tag if (intent.getParcelableExtra<android.nfc.Tag>(android.nfc.NfcAdapter.EXTRA_TAG) == null) { showConfirmDialog("未检测到NFC卡片,请确保卡片已正确放置") { } return } val nfcAdapter = NfcReadHelper.getInstance(intent, this) 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 } // 根据卡片类型进行不同处理 when (cardType) { CardCommon.USER_CARD_TYPE_1, CardCommon.USER_CARD_TYPE_2, CardCommon.USER_CARD_TYPE_3 -> { // 用户卡:解析卡内数据并调用接口 handleUserCard(cardNumber, cardType, nfcAdapter) } else -> { // 管理类卡不支持补扣 showConfirmDialog("该卡片类型不支持补扣操作") { resetToReadingState() } } } } catch (e: Exception) { showConfirmDialog("读卡异常:${e.message}") { } e.printStackTrace() } } /** * 处理用户卡 */ private fun handleUserCard(cardNumber: String, cardType: String, nfcAdapter: NfcReadHelper) { // 解析用户卡数据 val userCard = nfcAdapter.getUserCardData() if (userCard == null) { showConfirmDialog("解析卡片数据失败,请重新刷卡") { } return } // 输出用户卡内所有信息到日志 android.util.Log.d("CardDeductActivity", "=== 用户卡信息 ===") android.util.Log.d("CardDeductActivity", "卡号: $cardNumber") android.util.Log.d("CardDeductActivity", "卡片类型: $cardType") android.util.Log.d("CardDeductActivity", "卡内余额: ${userCard.balance}") android.util.Log.d("CardDeductActivity", "==================") this.userCard = userCard // 根据卡号获取卡片详细信息 getCardInfo(cardNumber, cardType, userCard) } /** * 获取卡片详细信息(用户卡专用) */ private fun getCardInfo(cardNumber: String, cardType: String, userCard: UserCard) { val map = mutableMapOf<String, Any>() map["cardAddr"] = cardNumber ApiManager.getInstance().requestGetLoading( this, "terminal/card/readCard", CardInfoResult::class.java, map, object : SubscriberListener<BaseResponse<CardInfoResult>>() { override fun onNext(t: BaseResponse<CardInfoResult>) { if (t.success) { // 读卡成功,显示用户卡详细信息 showUserCardInfo(t.content, cardNumber, cardType, userCard) } else { // 处理获取失败的情况 handleCardInfoError(t.code, t.msg) } } override fun onError(e: Throwable?) { super.onError(e) showConfirmDialog("获取卡信息失败: ${e?.message ?: "网络异常,请检查网络连接"}") { } } } ) } /** * 显示用户卡片信息(包含卡内数据和接口返回数据) */ private fun showUserCardInfo( cardInfo: CardInfoResult?, cardNumber: String, cardType: String, userCard: UserCard ) { // 隐藏读卡提示,显示信息区域和底部按钮 binding.scrollReadCard.visibility = android.view.View.GONE binding.cardInfoContainer.visibility = android.view.View.VISIBLE binding.bottomButtonContainer.visibility = android.view.View.VISIBLE this.cardInfo = cardInfo binding.tvCardNumber.text = cardNumber userCard.let { card -> // 余额转换为元(原始数据可能是分) binding.tvCardBalance.text = MornyUtil.changeF2Y(card.balance) + "元" } // 显示服务器数据 cardInfo?.let { info -> binding.tvUserName.text = info.userName ?: "未知" binding.tvPhone.text = info.phone ?: "未绑定" // 根据state字段显示状态 val (statusText, statusColor) = when (info.state) { 1 -> Pair("正常", android.graphics.Color.parseColor("#4CAF50")) // 绿色 2 -> Pair("已注销", android.graphics.Color.parseColor("#FF5722")) // 深橙色 3 -> Pair("已挂失", android.graphics.Color.parseColor("#FF9800")) // 橙色 4 -> Pair("无效卡片", android.graphics.Color.parseColor("#F44336")) // 红色 else -> Pair("未知状态", android.graphics.Color.parseColor("#9E9E9E")) // 灰色 } binding.tvCardStatus.text = statusText binding.tvCardStatus.setTextColor(statusColor) } } /** * 处理卡信息获取错误 */ private fun handleCardInfoError(code: String?, msg: String?) { val errorMessage: String = when (code) { "1001" -> { "该卡片未在系统中注册,无法进行补扣操作。" } else -> { when { msg.isNullOrBlank() -> "获取卡信息失败,请重新刷卡重试。" msg.contains("数据不存在") -> "该卡片未在系统中注册,无法进行补扣操作。" msg.contains("网络") -> "网络连接异常,请检查网络连接后重新刷卡。" msg.contains("超时") -> "网络请求超时,请重新刷卡重试。" else -> "获取卡信息失败:$msg\n\n请重新刷卡重试。" } } } // 显示错误信息的对话框 showConfirmDialog(errorMessage) { resetToReadingState() } } /** * 执行补扣操作 */ private fun performCardDeduct() { // 验证输入 val deductAmountStr = binding.etDeductAmount.text.toString().trim() val remarks = binding.etRemarks.text.toString().trim() // 补扣金额验证(必填) if (deductAmountStr.isEmpty()) { ToastUtil.show("请输入补扣金额") return } val deductAmount = try { val amount = deductAmountStr.toDouble() if (amount <= 0) { ToastUtil.show("补扣金额必须大于0") return } amount } catch (e: NumberFormatException) { ToastUtil.show("请输入有效的补扣金额") return } // 备注处理(非必填) val finalRemarks = if (remarks.isEmpty()) { "补扣" // 如果未输入备注,使用默认值 } else { remarks } callDeductCardApi(deductAmount, finalRemarks) } /** * 调用补扣API接口 */ private fun callDeductCardApi(deductAmount: Double, finalRemarks: String) { if (cardNumber.isNullOrBlank()) { ToastUtil.show("卡号信息异常,请重新刷卡") return } // 获取当前卡内余额(以分为单位) val currentBalance = userCard?.balance?.let { MornyUtil.changeF2Y(it) } ?: 0 val map = mutableMapOf<String, Any>() map["cardNum"] = cardInfo?.cardNum.toString() map["repayMorny"] = deductAmount.toString() map["balance"] = currentBalance.toString() map["remarks"] = finalRemarks map["operator"] = BaseApplication.userId ApiManager.getInstance().requestPostLoading( this, "terminal/card/termRepay", CardDeductResult::class.java, map, object : SubscriberListener<BaseResponse<CardDeductResult>>() { override fun onNext(t: BaseResponse<CardDeductResult>) { if (t.success && t.content != null) { // 补扣成功,跳转到写卡界面 startWriteCardActivity(t.content!!, deductAmount, userCard!!) } else { // 补扣失败 val errorMsg = if (t.msg.isNullOrBlank()) "补扣失败,请重试" else t.msg showConfirmDialog("补扣失败:$errorMsg") { } } } override fun onError(e: Throwable?) { super.onError(e) showConfirmDialog("补扣请求失败: ${e?.message ?: "网络异常,请检查网络连接"}") { } } } ) } /** * 跳转到写卡界面进行卡内容更新 */ private fun startWriteCardActivity( deductResult: CardDeductResult, deductAmount: Double, userCard: UserCard ) { // 创建更新后的用户卡数据 val updatedUserCard = UserCard().apply { // 复制原有属性 cardType = userCard.cardType areaNumber = userCard.areaNumber userCode = userCard.userCode userCodeNumber = userCard.userCodeNumber phoneNumber = userCard.phoneNumber projectCode = userCard.projectCode surplusWater = userCard.surplusWater waterPrice = userCard.waterPrice electricPrice = userCard.electricPrice rechargeDate = userCard.rechargeDate // 使用返回的新余额 balance = MornyUtil.changeY2F(deductResult.balance.toString()) } val intent = Intent(this, NfcWreatActivity::class.java).apply { putExtra("cardAddr", cardNumber) putExtra("operationTypeCode", CardOperationType.DeductCard.code) // 使用补扣类型进行写卡 putExtra("orderNumber", deductResult.orderNo) putExtra("deductAmount", deductAmount) putExtra("userCard", updatedUserCard as java.io.Serializable) } startActivity(intent) finish() } } generallibrary/src/main/java/com/dayu/general/activity/CardWriteSuccessActivity.kt
@@ -64,6 +64,22 @@ binding.successMessage.text = message } CardOperationType.DeductCard -> { // 设置标题 binding.titleBar.setCenterText("补扣成功") // 设置成功信息 binding.successTitle.text = "补扣成功" // 设置详细信息 val message = if (cardNumber.isNullOrBlank()) { "卡片补扣操作已成功完成\n卡内余额已更新" } else { "卡片补扣操作已成功完成\n卡号:$cardNumber\n卡内余额已更新" } binding.successMessage.text = message } else -> { // 默认显示写卡成功 binding.titleBar.setCenterText("写卡成功") generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt
@@ -41,6 +41,9 @@ // 返还相关信息 private var returnAmount = 0.0 // 补扣相关信息 private var deductAmount = 0.0 //订单编号 var orderNumber = "" private lateinit var userCard: UserCard @@ -74,6 +77,9 @@ // 获取返还相关信息 returnAmount = intent?.getDoubleExtra("returnAmount", 0.0) ?: 0.0 // 获取补扣相关信息 deductAmount = intent?.getDoubleExtra("deductAmount", 0.0) ?: 0.0 if (intent?.hasExtra("cardFee") == true) { cardFee = intent?.getIntExtra("cardFee", 0) ?: 0 @@ -174,8 +180,15 @@ binding?.cardData?.text = textData.toString() } CardOperationType.DeductCard -> { var textData = StringBuilder() textData.append("补扣\n") textData.append("卡内余额:" + MornyUtil.changeF2Y(userCard.balance) + "元\n") textData.append("补扣金额:" + deductAmount + "元") binding?.cardData?.text = textData.toString() } CardOperationType.CheckCard -> TODO() CardOperationType.DeductCard -> TODO() CardOperationType.ReplaceCard -> TODO() null -> TODO() } @@ -272,8 +285,22 @@ }) } CardOperationType.DeductCard -> { nfcWreatHelper.writeUserDataAsync(userCard, object : NFCCallBack { override fun isSusses(flag: Boolean, msg: String?) { // 确保Toast在主线程中调用 runOnUiThread { if (flag) { postCardData(cardAddr) } else { ToastUtil.show("补扣写卡失败: ${msg ?: "未知错误"}") } } } }) } CardOperationType.CheckCard -> TODO() CardOperationType.DeductCard -> TODO() CardOperationType.ReplaceCard -> TODO() null -> TODO() } generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt
@@ -405,15 +405,7 @@ val userCard = UserCard().apply { // 设置用户卡信息 cardInfo?.let { info -> userCode = info.cardNum ?: "" // 计算新余额:原有余额 + 充值金额 + 赠送金额 val originalBalance = this@RechargeDetailActivity.userCard?.balance ?: 0 // 原有余额(分) val rechargeAmountInCents = (rechargeAmount * 100).toInt() // 充值金额转分 val bonusAmountInCents = (bonusAmount * 100).toInt() // 赠送金额转分 balance = originalBalance + rechargeAmountInCents + bonusAmountInCents balance = MornyUtil.changeY2F(rechargeResult.balance) } // 设置其他必要信息 generallibrary/src/main/java/com/dayu/general/bean/net/CardCancelResult.kt
New file @@ -0,0 +1,13 @@ package com.dayu.general.bean.net /** * 销卡结果数据类 * @author: zuo * @date: 2025/01/17 * @description: 销卡接口返回数据 */ data class CardCancelResult( val projectNo: Int, // 项目编号 val cardNum: String, // 卡号 val orderNo: String // 订单号 ) generallibrary/src/main/java/com/dayu/general/bean/net/CardDeductResult.kt
New file @@ -0,0 +1,33 @@ /** * @author: AI Assistant * @desc: 补扣接口返回结果 * @since: 2025/6/17 */ package com.dayu.general.bean.net import java.io.Serializable /** * 补扣操作的API返回结果 */ data class CardDeductResult( /** * 补扣后的余额 */ val balance: Float = 0f, /** * 水价 */ val waterPrice: Double = 0.0, /** * 时间 */ val time: String = "", /** * 订单号 */ val orderNo: String = "" ) : Serializable generallibrary/src/main/java/com/dayu/general/bean/net/CardReturnResult.kt
New file @@ -0,0 +1,33 @@ /** * @author: zuo * @desc: 返还接口返回结果 * @since: 2025/6/17 */ package com.dayu.general.bean.net import java.io.Serializable /** * 返还操作的API返回结果 */ data class CardReturnResult( /** * 返还后的余额 */ val balance: Float = 0f, /** * 水价 */ val waterPrice: Double = 0.0, /** * 时间 */ val time: String = "", /** * 订单号 */ val orderNo: String = "" ) : Serializable generallibrary/src/main/java/com/dayu/general/bean/net/RechargeResult.kt
@@ -10,5 +10,6 @@ val cardNum: String, // 卡号 val orderNo: String, // 订单号 val waterPrice: Double, // 水价 val time: String // 时间 val time: String, // 时间 val balance: String // 余额 ) : Serializable generallibrary/src/main/res/drawable/button_green_bg.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@color/button_select_text_color" /> <corners android:radius="6dp" /> </shape> generallibrary/src/main/res/layout/activity_card_deduct.xml
New file @@ -0,0 +1,412 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" 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="补扣" app:leftImage="@mipmap/icon_back" /> <!-- 读卡提示区域 - 全屏显示 --> <ScrollView android:id="@+id/scroll_read_card" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/titleBar" android:fillViewport="true" android:visibility="visible"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <LinearLayout android:id="@+id/card_read_LL" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="16dp" app:cardCornerRadius="8dp" app:cardElevation="2dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp"> <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="100dp" android:gravity="center" android:text="补扣操作" android:layout_marginTop="20dp" android:textColor="@color/base_blue_bg" android:textSize="@dimen/big_text_size" android:textStyle="bold" /> <TextView android:id="@+id/tv_subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/tv_title" android:layout_marginBottom="20dp" android:gravity="center" android:text="请将需要补扣的卡片贴在设备上进行读取" android:textColor="#333333" android:textSize="@dimen/text_size" android:textStyle="bold" /> <ImageView android:id="@+id/iv_nfc" android:layout_width="120dp" android:layout_height="120dp" android:layout_below="@+id/tv_subtitle" android:layout_centerHorizontal="true" android:layout_marginBottom="20dp" android:scaleType="fitCenter" android:src="@mipmap/nfc_write" /> <TextView android:id="@+id/tv_tip" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/iv_nfc" android:gravity="center" android:text="请保持手持机和卡片不要移动" android:textColor="#666666" android:textSize="@dimen/new_card_size" /> </RelativeLayout> </androidx.cardview.widget.CardView> </LinearLayout> </LinearLayout> </ScrollView> <!-- 卡片信息显示区域 - 带固定底部按钮 --> <LinearLayout android:id="@+id/card_info_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/bottom_button_container" android:layout_below="@+id/titleBar" android:orientation="vertical" android:visibility="gone"> <ScrollView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:fillViewport="true" android:padding="12dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- 卡片信息区域 --> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="12dp" app:cardCornerRadius="8dp" app:cardElevation="2dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="12dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:gravity="" android:text="卡片信息" android:textColor="@color/base_blue_bg" android:textSize="16sp" android:textStyle="bold" /> <!-- 持卡人 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="1dp" android:background="#F8F9FA" android:gravity="center_vertical" android:orientation="horizontal" android:padding="8dp"> <TextView android:layout_width="80dp" android:layout_height="wrap_content" android:text="持卡人:" android:textColor="#333333" android:textSize="14sp" /> <TextView android:id="@+id/tv_user_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="--" android:textColor="#666666" android:textSize="14sp" /> </LinearLayout> <!-- 卡号 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="1dp" android:background="#FFFFFF" android:gravity="center_vertical" android:orientation="horizontal" android:padding="8dp"> <TextView android:layout_width="80dp" android:layout_height="wrap_content" android:text="卡地址:" android:textColor="#333333" android:textSize="14sp" /> <TextView android:id="@+id/tv_card_number" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="--" android:textColor="#666666" android:textSize="14sp" /> </LinearLayout> <!-- 卡片状态 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="1dp" android:background="#F8F9FA" android:gravity="center_vertical" android:orientation="horizontal" android:padding="8dp"> <TextView android:layout_width="80dp" android:layout_height="wrap_content" android:text="卡片状态:" android:textColor="#333333" android:textSize="14sp" /> <TextView android:id="@+id/tv_card_status" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="正常" android:textColor="#4CAF50" android:textSize="14sp" /> </LinearLayout> <!-- 卡内余额 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="1dp" android:background="#FFFFFF" android:gravity="center_vertical" android:orientation="horizontal" android:padding="8dp"> <TextView android:layout_width="80dp" android:layout_height="wrap_content" android:text="卡内余额:" android:textColor="#333333" android:textSize="14sp" /> <TextView android:id="@+id/tv_card_balance" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="0.00元" android:textColor="#FF6B35" android:textSize="14sp" android:textStyle="bold" /> </LinearLayout> <!-- 手机号 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#F8F9FA" android:gravity="center_vertical" android:orientation="horizontal" android:padding="8dp"> <TextView android:layout_width="80dp" android:layout_height="wrap_content" android:text="手机号:" android:textColor="#333333" android:textSize="14sp" /> <TextView android:id="@+id/tv_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="--" android:textColor="#666666" android:textSize="14sp" /> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> <!-- 补扣操作区域 --> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="8dp" app:cardElevation="2dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="12dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="12dp" android:gravity="" android:text="补扣操作" android:textColor="@color/base_blue_bg" android:textSize="16sp" android:textStyle="bold" /> <!-- 补扣金额和备注并排显示 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <!-- 补扣金额输入 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="6dp" android:layout_weight="1" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="6dp" android:text="补扣金额(元): *" android:textColor="#333333" android:textSize="14sp" android:textStyle="bold" /> <EditText android:id="@+id/et_deduct_amount" android:layout_width="match_parent" android:layout_height="40dp" android:layout_marginTop="5dp" android:background="@drawable/edit_text_bg" android:hint="请输入补扣金额" android:inputType="numberDecimal" android:padding="8dp" android:textColor="#333333" android:textColorHint="#999999" android:textSize="14sp" /> </LinearLayout> <!-- 备注输入 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:layout_weight="1" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="6dp" android:text="备注:" android:textColor="#333333" android:textSize="14sp" android:textStyle="bold" /> <EditText android:id="@+id/et_remarks" android:layout_width="match_parent" android:layout_height="80dp" android:layout_marginTop="5dp" android:background="@drawable/edit_text_bg" android:hint="请输入补扣备注" android:inputType="text" android:minLines="2" android:padding="8dp" android:textColor="#333333" android:textColorHint="#999999" android:textSize="14sp" /> </LinearLayout> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> </LinearLayout> </ScrollView> </LinearLayout> <!-- 底部按钮区域 --> <LinearLayout android:id="@+id/bottom_button_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="#FFFFFF" android:elevation="4dp" android:orientation="vertical" android:padding="16dp" android:visibility="gone"> <!-- 补扣按钮 --> <Button android:id="@+id/btn_deduct" android:layout_width="match_parent" android:layout_height="48dp" android:background="@drawable/button_green_bg" android:text="确认补扣" android:textColor="#FFFFFF" android:textSize="@dimen/big_text_size" android:textStyle="bold" /> </LinearLayout> </RelativeLayout>