左晓为主开发手持机充值管理机
zuoxiao
16 小时以前 ec09d4bcd191496272099c2ab31d097ad630ee78
feat(card): 添加销卡功能并优化卡片信息展示

- 新增 CardCancelActivity 用于销卡操作
- 更新 CardInfoResult 数据结构,将 status 字段改为 state- 修改 CardReadActivity 和 RechargeDetailActivity 以使用新的 state 字段
- 优化卡片信息展示逻辑,统一卡状态显示和颜色处理
- 新增 item_bg_selector.xml 作为列表项背景选择器
- 在 strings.xml 中添加 SmartRefreshLayout 底部 Footer 相关文本
6个文件已修改
4个文件已添加
774 ■■■■■ 已修改文件
generallibrary/src/main/AndroidManifest.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/CardCancelActivity.kt 357 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/CardReadActivity.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/adapter/SearchUserListAdapter.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/net/CardInfoResult.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/drawable/item_bg_selector.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/activity_card_cancel.xml 365 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/activity_card_read.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/values/strings.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/AndroidManifest.xml
@@ -105,6 +105,18 @@
            </intent-filter>
        </activity>
        <!-- 销卡页面 -->
        <activity
            android:name=".activity.CardCancelActivity"
            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"
            android:value="7.1" />
generallibrary/src/main/java/com/dayu/general/activity/CardCancelActivity.kt
New file
@@ -0,0 +1,357 @@
package com.dayu.general.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import com.dayu.baselibrary.net.subscribers.SubscriberListener
import com.dayu.baselibrary.utils.ToastUtil
import com.dayu.baselibrary.view.TipDialog
import com.dayu.baselibrary.view.TitleBar
import com.dayu.general.bean.net.CardInfoResult
import com.dayu.general.databinding.ActivityCardCancelBinding
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
/**
 * @author: zuo
 * @desc: 销卡Activity
 * @since: 2025/3/6
 */
class CardCancelActivity : BaseNfcActivity() {
    private lateinit var binding: ActivityCardCancelBinding
    private var cardNumber: String? = null
    private var cardInfo: CardInfoResult? = null
    companion object {
        /**
         * 启动销卡Activity
         */
        fun start(context: Context) {
            val intent = Intent(context, CardCancelActivity::class.java)
            context.startActivity(intent)
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityCardCancelBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initView()
    }
    private fun initView() {
        // 设置TitleBar的返回按钮点击事件
        binding.titleBar.setOnItemclickListner(TitleBar.ClickType_LEFT_IMAGE) {
            finish()
        }
        // 设置销卡按钮点击事件
        binding.btnCancelCard.setOnClickListener {
            performCardCancel()
        }
    }
    /**
     * 重置到读卡状态
     */
    private fun resetToReadingState() {
        binding.cardReadLL.visibility = android.view.View.VISIBLE
        binding.cardInfoContainer.visibility = android.view.View.GONE
        cardNumber = null
        cardInfo = null
        binding.etRefundAmount.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("CardCancelActivity", "=== 用户卡信息 ===")
        android.util.Log.d("CardCancelActivity", "卡号: $cardNumber")
        android.util.Log.d("CardCancelActivity", "卡片类型: $cardType")
        android.util.Log.d("CardCancelActivity", "卡内余额: ${userCard.balance}")
        android.util.Log.d("CardCancelActivity", "==================")
        // 根据卡号获取卡片详细信息
        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.cardReadLL.visibility = android.view.View.GONE
        binding.cardInfoContainer.visibility = android.view.View.VISIBLE
        this.cardInfo = cardInfo
        binding.tvCardNumber.text = cardNumber
        userCard.let { card ->
            // 余额转换为元(原始数据可能是分)
            val balanceInYuan = if (card.balance > 1000) {
                String.format("%.2f", card.balance / 100.0)
            } else {
                card.balance.toString()
            }
            binding.tvCardBalance.text = "${balanceInYuan}元"
            // 默认退款金额设置为卡内余额
            binding.etRefundAmount.setText(balanceInYuan)
            // 卡片状态
            binding.tvCardStatus.text = "正常"
            binding.tvCardStatus.setTextColor(android.graphics.Color.parseColor("#4CAF50"))
        }
        // 显示服务器数据
        cardInfo?.let { info ->
            binding.tvUserName.text = info.userName ?: "未知"
            binding.tvPhone.text = info.phone ?: "未绑定"
            // 根据status字段显示状态
            val statusText = when (info.state) {
                1 -> "正常"
                2 -> "挂失"
                3 -> "锁定"
                else -> "未知"
            }
        }
    }
    /**
     * 处理卡信息获取错误
     */
    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 performCardCancel() {
        // 验证输入
        val refundAmountStr = binding.etRefundAmount.text.toString().trim()
        val remarks = binding.etRemarks.text.toString().trim()
        if (TextUtils.isEmpty(refundAmountStr)) {
            ToastUtil.showToast("请输入退款金额")
            return
        }
        val refundAmount = try {
            refundAmountStr.toDouble()
        } catch (e: NumberFormatException) {
            ToastUtil.showToast("请输入有效的退款金额")
            return
        }
        if (refundAmount < 0) {
            ToastUtil.showToast("退款金额不能为负数")
            return
        }
        if (TextUtils.isEmpty(remarks)) {
            ToastUtil.showToast("请输入备注信息")
            return
        }
        // 确认销卡
        showConfirmDialog(
            "确认要销卡吗?\n\n卡号:${cardNumber}\n退款金额:${refundAmount}元\n备注:${remarks}\n\n销卡后此卡将无法再次使用!"
        ) {
            callCancelCardApi(refundAmount, remarks)
        }
    }
    /**
     * 调用销卡API接口
     */
    private fun callCancelCardApi(refundAmount: Double, remarks: String) {
        if (cardNumber.isNullOrBlank()) {
            ToastUtil.showToast("卡号信息异常,请重新刷卡")
            return
        }
        val map = mutableMapOf<String, Any>()
        map["cardNum"] = cardNumber!!
        map["refund"] = (refundAmount * 100).toInt() // 转换为分
        map["refundType"] = 1838466162264350700L
        map["remarks"] = remarks
        map["operator"] = 2024090516595200300L
        ApiManager.getInstance().requestPostLoading(
            this,
            "terminal/card/termCancel",
            Boolean::class.java,
            map,
            object : SubscriberListener<BaseResponse<Boolean>>() {
                override fun onNext(t: BaseResponse<Boolean>) {
                    if (t.success && t.content == true) {
                        // 销卡成功
                        showConfirmDialog("销卡成功!\n\n退款金额:${refundAmount}元已退还") {
                            finish()
                        }
                    } else {
                        // 销卡失败
                        val errorMsg = if (t.msg.isNullOrBlank()) "销卡失败,请重试" else t.msg
                        showConfirmDialog("销卡失败:$errorMsg") {
                        }
                    }
                }
                override fun onError(e: Throwable?) {
                    super.onError(e)
                    showConfirmDialog("销卡请求失败: ${e?.message ?: "网络异常,请检查网络连接"}") {
                    }
                }
            }
        )
    }
}
generallibrary/src/main/java/com/dayu/general/activity/CardReadActivity.kt
@@ -307,7 +307,7 @@
            binding.tvIdCard.text = info.userCode ?: "未录入"  // 使用userCode作为身份证号的替代
            // 根据status字段显示状态
            val statusText = when (info.status) {
            val statusText = when (info.state) {
                1 -> "正常"
                2 -> "挂失"
                3 -> "锁定"
generallibrary/src/main/java/com/dayu/general/activity/RechargeDetailActivity.kt
@@ -267,7 +267,7 @@
            binding.redRemainderBlance.text = "$balance 元"
            // 设置卡状态和对应颜色
            val cardStatus = when (info.status) {
            val cardStatus = when (info.state) {
                1 -> "正常"
                2 -> "挂失"
                3 -> "锁定"
@@ -277,7 +277,7 @@
            binding.redStatu.text = cardStatus
            // 根据卡状态设置不同颜色
            val statusColor = when (info.status) {
            val statusColor = when (info.state) {
                1 -> android.graphics.Color.parseColor("#4CAF50") // 绿色-正常
                2 -> android.graphics.Color.parseColor("#FF9800") // 橙色-挂失
                3 -> android.graphics.Color.parseColor("#F44336") // 红色-锁定
@@ -433,7 +433,7 @@
                putExtra("bonusAmount", bonusAmount) // 传递赠送金额
            }
            startActivity(intent)
            finish()
        } catch (e: Exception) {
            ToastUtil.show("启动写卡界面失败: ${e.message}")
        }
generallibrary/src/main/java/com/dayu/general/adapter/SearchUserListAdapter.kt
@@ -107,7 +107,7 @@
                val end = idCard.substring(idCard.length - 4)
                "$start****$end"
            } else {
                idCard ?: "无"
                "未录入"
            }
        }
        
generallibrary/src/main/java/com/dayu/general/bean/net/CardInfoResult.kt
@@ -12,7 +12,7 @@
    val phone: String? = null,        // 手机号
    val address: String? = null,      // 地址
    val balance: Double? = 0.0,       // 余额
    val status: Int? = 0,             // 卡状态: 1-正常, 2-挂失, 3-锁定
    val state: Int? = 0,             // 卡状态: 1-正常, 2-挂失, 3-锁定
    val createTime: String? = null,   // 创建时间
    val updateTime: String? = null    // 更新时间
) : Serializable 
generallibrary/src/main/res/drawable/item_bg_selector.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5" />
            <corners android:radius="8dp" />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#fafafa" />
            <corners android:radius="8dp" />
        </shape>
    </item>
</selector>
generallibrary/src/main/res/layout/activity_card_cancel.xml
New file
@@ -0,0 +1,365 @@
<?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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/titleBar"
        android:fillViewport="true">
        <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"
                android:visibility="visible">
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginBottom="16dp"
                    app:cardCornerRadius="8dp"
                    app:cardElevation="2dp">
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:gravity="center"
                        android:orientation="vertical"
                        android:padding="16dp">
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="16dp"
                            android:gravity="center"
                            android:text="销卡操作"
                            android:textColor="@color/base_blue_bg"
                            android:textSize="@dimen/big_text_size"
                            android:textStyle="bold" />
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="20dp"
                            android:gravity="center"
                            android:text="请将需要销卡的卡片贴在设备上进行读取"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size"
                            android:textStyle="bold" />
                        <ImageView
                            android:layout_width="120dp"
                            android:layout_height="120dp"
                            android:layout_gravity="center"
                            android:layout_marginBottom="20dp"
                            android:scaleType="fitCenter"
                            android:src="@mipmap/nfc_write" />
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center"
                            android:text="请保持手持机和卡片不要移动"
                            android:textColor="#666666"
                            android:textSize="@dimen/new_card_size" />
                    </LinearLayout>
                </androidx.cardview.widget.CardView>
            </LinearLayout>
            <!-- 卡片信息显示区域 -->
            <LinearLayout
                android:id="@+id/card_info_container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:visibility="gone">
                <!-- 卡内数据区域 -->
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="16dp"
                    app:cardCornerRadius="8dp"
                    app:cardElevation="2dp">
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:padding="16dp">
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="12dp"
                            android:gravity="center"
                            android:text="卡片信息"
                            android:textColor="@color/base_blue_bg"
                            android:textSize="@dimen/big_text_size"
                            android:textStyle="bold" />
                        <!-- 持卡人 -->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="2dp"
                            android:background="#F8F9FA"
                            android:gravity="center_vertical"
                            android:orientation="horizontal"
                            android:padding="12dp">
                            <TextView
                                android:layout_width="105dp"
                                android:layout_height="wrap_content"
                                android:text="持卡人:"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size" />
                            <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="@dimen/text_size" />
                        </LinearLayout>
                        <!-- 卡号 -->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="2dp"
                            android:background="#FFFFFF"
                            android:gravity="center_vertical"
                            android:orientation="horizontal"
                            android:padding="12dp">
                            <TextView
                                android:layout_width="105dp"
                                android:layout_height="wrap_content"
                                android:text="卡地址:"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size" />
                            <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="@dimen/text_size" />
                        </LinearLayout>
                        <!-- 卡片状态 -->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="2dp"
                            android:background="#F8F9FA"
                            android:gravity="center_vertical"
                            android:orientation="horizontal"
                            android:padding="12dp">
                            <TextView
                                android:layout_width="105dp"
                                android:layout_height="wrap_content"
                                android:text="卡片状态:"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size" />
                            <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="@dimen/text_size" />
                        </LinearLayout>
                        <!-- 卡内余额 -->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="2dp"
                            android:background="#FFFFFF"
                            android:gravity="center_vertical"
                            android:orientation="horizontal"
                            android:padding="12dp">
                            <TextView
                                android:layout_width="105dp"
                                android:layout_height="wrap_content"
                                android:text="卡余额:"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size" />
                            <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="@dimen/text_size"
                                android:textStyle="bold" />
                        </LinearLayout>
                        <!-- 手机号 -->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="2dp"
                            android:background="#F8F9FA"
                            android:gravity="center_vertical"
                            android:orientation="horizontal"
                            android:padding="12dp">
                            <TextView
                                android:layout_width="105dp"
                                android:layout_height="wrap_content"
                                android:text="手机号:"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size" />
                            <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="@dimen/text_size" />
                        </LinearLayout>
                    </LinearLayout>
                </androidx.cardview.widget.CardView>
                <!-- 销卡操作区域 -->
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="16dp"
                    app:cardCornerRadius="8dp"
                    app:cardElevation="2dp">
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:padding="16dp">
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="16dp"
                            android:gravity="center"
                            android:text="销卡操作"
                            android:textColor="@color/base_blue_bg"
                            android:textSize="@dimen/big_text_size"
                            android:textStyle="bold" />
                        <!-- 退款金额输入 -->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="16dp"
                            android:orientation="vertical">
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_marginBottom="8dp"
                                android:text="退款金额(元):"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size"
                                android:textStyle="bold" />
                            <EditText
                                android:id="@+id/et_refund_amount"
                                android:layout_width="match_parent"
                                android:layout_height="48dp"
                                android:background="@drawable/edit_text_bg"
                                android:hint="请输入退款金额"
                                android:inputType="numberDecimal"
                                android:padding="12dp"
                                android:textColor="#333333"
                                android:textColorHint="#999999"
                                android:textSize="@dimen/text_size" />
                        </LinearLayout>
                        <!-- 备注输入 -->
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginBottom="24dp"
                            android:orientation="vertical">
                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_marginBottom="8dp"
                                android:text="备注:"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size"
                                android:textStyle="bold" />
                            <EditText
                                android:id="@+id/et_remarks"
                                android:layout_width="match_parent"
                                android:layout_height="80dp"
                                android:background="@drawable/edit_text_bg"
                                android:gravity="top|start"
                                android:hint="请输入销卡备注信息"
                                android:inputType="textMultiLine"
                                android:padding="12dp"
                                android:textColor="#333333"
                                android:textColorHint="#999999"
                                android:textSize="@dimen/text_size" />
                        </LinearLayout>
                        <!-- 销卡按钮 -->
                        <Button
                            android:id="@+id/btn_cancel_card"
                            android:layout_width="match_parent"
                            android:layout_height="48dp"
                            android:background="@drawable/button_red_bg"
                            android:text="确认销卡"
                            android:textColor="#FFFFFF"
                            android:textSize="@dimen/big_text_size"
                            android:textStyle="bold" />
                    </LinearLayout>
                </androidx.cardview.widget.CardView>
            </LinearLayout>
        </LinearLayout>
    </ScrollView>
</RelativeLayout>
generallibrary/src/main/res/layout/activity_card_read.xml
@@ -250,7 +250,7 @@
                                android:textStyle="bold" />
                        </LinearLayout>
                        <!-- 用户编号 -->
                        <!-- 卡编号 -->
                        <LinearLayout
                            android:id="@+id/ll_user_number"
                            android:layout_width="match_parent"
@@ -265,7 +265,7 @@
                            <TextView
                                android:layout_width="105dp"
                                android:layout_height="wrap_content"
                                android:text="用户编号:"
                                android:text="卡编号:"
                                android:textColor="#333333"
                                android:textSize="@dimen/text_size" />
generallibrary/src/main/res/values/strings.xml
New file
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- SmartRefreshLayout底部Footer相关文本 -->
    <string name="srl_footer_nothing">已到底</string>
    <string name="srl_footer_pulling">上拉加载更多</string>
    <string name="srl_footer_release">释放立即加载</string>
    <string name="srl_footer_loading">正在加载…</string>
    <string name="srl_footer_refreshing">等待头部刷新完成…</string>
</resources>