Compare commits

...

5 Commits

Binary file not shown.

@ -1,51 +0,0 @@
# 个人周工作计划 -第四周
**姓名:** 王家伟
**角色:** 后端开发工程师
**团队:** 菜鸟队
**周期:** 2025-10-13 至 2025-10-19
---
## 本周个人目标
1. **环境就绪:** 完成本地后端SpringBoot开发、测试及数据库环境的搭建与验证。
2. **架构奠基:** 主导并完成后端系统分层架构的设计与文档化。
3. **数据建模:** 主导核心数据库的ER图设计与核心表结构定义。
4. **接口契约:** 主导完成用户认证模块的API接口设计文档与前端/APP端达成一致。
5. **团队协作:** 积极参与所有会议和讨论,确保后端设计与整体业务逻辑和前端/APP需求无缝对接。
---
## 具体任务与时间安排
| 日期 | 任务内容 | 详细说明与输出物 | 状态 |
| :--- | :--- | :--- | :--- |
| **周一 (10-13)** | **1. 参与项目启动会**<br>**2. 搭建本地开发环境** | **会议:** 明确项目范围、个人角色。理解业务核心流程,特别是支付和认证。<br>**环境:** 安装并配置JDK、Maven、IDE、Git、MySQL。成功运行一个SpringBoot Demo项目并提交到团队Git仓库。 | 计划中 |
| **周二 (10-14)** | **1. 主导后端架构设计**<br>**2. 环境搭建收尾与标准确认** | **架构设计:** 绘制并文档化后端分层架构图。明确各层职责规划公共组件。输出《后端架构设计文档》v1.0。<br>**环境:** 完成环境搭建,协助未完成的队友。与团队确认依赖版本,并更新至《开发环境搭建指南》。 | 计划中 |
| **周三 (10-15)** | **主导数据库设计** | 基于业务流程识别核心实体用户、银行卡、交易记录等。绘制详细的ER图定义表结构。输出《数据库设计文档》v1.0。 | 计划中 |
| **周四 (10-16)** | **主导用户认证API设计** | 设计用户注册、登录、登出等接口。使用Swagger或Postman编写API文档明确接口契约。输出《API接口文档用户认证模块》。 | 计划中 |
| **周五 (10-17)** | **1. 内部评审与修订**<br>**2. 准备周末汇总** | **评审:** 组织或参与数据库设计和API设计的内部评审会收集反馈并修订文档。<br>**汇总:** 整理个人本周的所有输出物,确保它们是最新且一致的。 | 计划中 |
| **周末 (10-18/19)** | **灵活缓冲与学习** | **缓冲:** 处理本周未完成的任务或评审后的修改。<br>**学习:** 提前研究关键技术点如JWT认证、二维码生成原理、AI大模型API对接等。 | 计划中 |
---
## 需要的支持与资源
1. **明确的业务需求:**
* 需要产品经理提供清晰、无歧义的“注册”、“支付”、“地铁通行码”业务流程图,作为数据库和接口设计的根本依据。
2. **及时的跨端沟通:**
* 在API设计阶段需要与前端/APP同事紧密协作共同确认接口的数据格式、认证方式等细节。
* 希望他们能积极参与API文档的评审。
3. **团队的技术决策:**
* 对于技术选型如ORM框架、认证机制希望团队能快速决策以便进行环境配置和架构集成。
4. **工具与权限:**
* 确保拥有Git仓库的读写权限。
* 确保拥有团队文档库如Confluence、飞书文档的编辑权限。
* 如有共用测试数据库,需要获取连接信息。
5. **充足的工作时间:**
* 希望会议能高效进行,为核心的设计和文档工作留出充足的“安静时间”。

@ -0,0 +1,23 @@
# 个人周工作计划 -第四周
**姓名:** 张豪
**角色:** 安卓app开发工程师
**团队:** 菜鸟队
**周期:** 2025-10-13 至 2025-10-19
---
| 序号 | 计划内容| 协作人 | 情况说明 |
| ----| ------ | ------| ------- |
| 1 | 需求获取 | 组员 | 2025-10-09 与边耐政老师面对面沟通确定需求 |
| 2 | 学习安卓app知识 | 个人 | 周内持续学习css的浮动与定位的相关知识 |
| 3 | 确定分工 | 组员 | 2025-10-12 细分确定团队分工,统一开发工具 |
| 4 | 搭建安卓项目基础架构 | 组员 | 周内完成安卓项目初始化:基于 Android Studio 创建 Module |
| 5 | 开发 “扫一扫” 核心功能模块 | 组员 | 完成摄像头调用权限申请、扫描框 UI 绘制 |
---
## 小结
1. **学习需求:** 希望团队能组织安卓端 “动态码生成优化”(如防止截屏、提高识别效率)的技术分享,或提供成熟项目的相关代码参考;
2. **知识储备:** 本周将抽时间学习安卓 Jetpack Compose 组件(为后续复杂页面开发做准备),以及移动支付安全相关知识(如数据加密、支付签名校验);
3. **文档撰写:**同步整理安卓端核心功能的开发文档(含接口调用流程、关键代码注释),后续上传至代码托管平台供团队参考。

@ -0,0 +1,38 @@
# 个人周总结-第4周
## 姓名和起止时间
**姓  名** 张豪
**团队名称** 4班-菜鸟队
**开始时间** 2025-10-13
**结束时间** 2025-10-19
## 本周任务完成情况
**序号 总结内容 是否完成 情况说明**
1 Kotlin专业知识的初步学习 完成 2025-10-13到2025-10-20 完成了Kotlin语言的基本学习能理解并编写简单的代码
2 Kotlin语言的运用 完成 2025-10-13到2025-10-20利用Kotlin完成一些简单组件的编写
## 对团队工作的建议
1\.**进度统一** 团队成员尽量统一项目进度,共同协助来进行项目的开发;
2\.**互助学习** 小组成员应该根据自身的技能长短开展互帮互助的活动,共同努力提高小组成员的专业水平;
## 小结
1\.**项目管理** PM确保工作有条不紊协助其他组员完成工作
2\.**技能学习** 小组成员各自开展自己所负责部分的个人技能的学习;
3\.**计划制定** 根据本周任务完成情况与下一阶段文档提交要求,制定团队任务计划。

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.payment">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MobilePaymentApp"
android:usesCleartextTraffic="true"> <activity
android:name=".ui.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".user.LoginActivity" />
<activity android:name=".user.RegisterActivity" />
<activity android:name=".user.RealNameAuthActivity" />
<activity android:name=".user.AuditStatusActivity" />
<activity android:name=".asset.BalanceActivity" />
<activity android:name=".asset.BankCardListActivity" />
<activity android:name=".asset.AddBankCardActivity" />
<activity android:name=".asset.RechargeWithdrawActivity" />
</application>
</manifest>

@ -0,0 +1,19 @@
package com.payment;
import android.app.Application;
import android.content.Context;
public class MyApplication extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
// 提供全局上下文
public static Context getContext() {
return context;
}
}

@ -0,0 +1,61 @@
package com.payment.asset;
import com.payment.base.BaseActivity;
import com.payment.R;
import com.payment.utils.ToastUtils;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class AddBankCardActivity extends BaseActivity {
private EditText etCardNo, etBankName;
private Button btnSubmit;
private AssetViewModel assetViewModel;
@Override
protected int getLayoutId() {
return R.layout.activity_add_bank_card;
}
@Override
protected void initView() {
etCardNo = findViewById(R.id.et_card_no);
etBankName = findViewById(R.id.et_bank_name);
btnSubmit = findViewById(R.id.btn_submit);
}
@Override
protected void initData() {
assetViewModel = new ViewModelProvider(this).get(AssetViewModel.class);
// 观察添加结果
assetViewModel.getAddCardResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
ToastUtils.showToast(this, "银行卡添加成功");
finish(); // 返回列表页
} else {
ToastUtils.showToast(this, "添加失败:" + (resultBean != null ? resultBean.getMsg() : "网络异常"));
}
});
}
@Override
protected void bindEvent() {
btnSubmit.setOnClickListener(v -> {
String cardNo = etCardNo.getText().toString().trim();
String bankName = etBankName.getText().toString().trim();
if (cardNo.isEmpty() || bankName.isEmpty()) {
showToast("请完善银行卡信息");
return;
}
if (cardNo.length() < 16 || cardNo.length() > 19) {
showToast("请输入正确的银行卡号");
return;
}
// 提交添加银行卡
assetViewModel.addBankCard(cardNo, bankName);
});
}
}

@ -0,0 +1,279 @@
package com.payment.asset;
import com.payment.base.BaseViewModel;
import com.payment.model.BankCard;
import com.payment.network.ApiService;
import com.payment.network.RetrofitManager;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.LiveData;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import java.util.ArrayList;
public class AssetViewModel extends BaseViewModel {
// 银行卡列表结果使用ApiService内部ResultBean
private final MutableLiveData<ApiService.ResultBean<List<BankCard>>> bankCardListResult = new MutableLiveData<>();
// 添加银行卡结果
private final MutableLiveData<ApiService.ResultBean<String>> addCardResult = new MutableLiveData<>();
// 设置默认卡结果
private final MutableLiveData<ApiService.ResultBean<String>> defaultCardResult = new MutableLiveData<>();
// 删除银行卡结果
private final MutableLiveData<ApiService.ResultBean<String>> deleteCardResult = new MutableLiveData<>();
// 余额结果修正为ApiService.BalanceBean
private final MutableLiveData<ApiService.ResultBean<ApiService.BalanceBean>> balanceResult = new MutableLiveData<>();
// 充值结果
private final MutableLiveData<ApiService.ResultBean<String>> rechargeResult = new MutableLiveData<>();
// 提现结果
private final MutableLiveData<ApiService.ResultBean<String>> withdrawResult = new MutableLiveData<>();
// 获取各结果观察器
public LiveData<ApiService.ResultBean<List<BankCard>>> getBankCardListResult() { return bankCardListResult; }
public LiveData<ApiService.ResultBean<String>> getAddCardResult() { return addCardResult; }
public LiveData<ApiService.ResultBean<String>> getDefaultCardResult() { return defaultCardResult; }
public LiveData<ApiService.ResultBean<String>> getDeleteCardResult() { return deleteCardResult; }
public LiveData<ApiService.ResultBean<ApiService.BalanceBean>> getBalanceResult() { return balanceResult; }
public LiveData<ApiService.ResultBean<String>> getRechargeResult() { return rechargeResult; }
public LiveData<ApiService.ResultBean<String>> getWithdrawResult() { return withdrawResult; }
// 获取银行卡列表
// 修改 AssetViewModel 中的 getBankCardList() 方法
public void getBankCardList() {
showLoading();
ApiService apiService = RetrofitManager.getApiService(com.payment.MyApplication.getContext());
// 回调类型修正为 ResultBean<BankCardListBean>(与接口定义一致)
apiService.getBankCardList().enqueue(new Callback<ApiService.ResultBean<ApiService.BankCardListBean>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BankCardListBean>> call,
Response<ApiService.ResultBean<ApiService.BankCardListBean>> response) {
hideLoading();
if (response.isSuccessful() && response.body() != null) {
ApiService.ResultBean<ApiService.BankCardListBean> result = response.body();
// 转换 BankCardBean[] 为 List<BankCard>
List<BankCard> cardList = convertToBankCardList(result.getData());
// 封装成 UI 层需要的 ResultBean<List<BankCard>>
ApiService.ResultBean<List<BankCard>> uiResult = new ApiService.ResultBean<>();
uiResult.setSuccess(result.isSuccess());
uiResult.setMsg(result.getMsg());
uiResult.setData(cardList);
bankCardListResult.postValue(uiResult);
} else {
bankCardListResult.postValue(null);
}
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BankCardListBean>> call, Throwable t) {
hideLoading();
sendErrorMsg("获取银行卡列表失败:" + t.getMessage());
bankCardListResult.postValue(null);
}
});
}
// 新增转换方法:将 BankCardBean[] 转换为 List<BankCard>
private List<BankCard> convertToBankCardList(ApiService.BankCardListBean bankCardListBean) {
List<BankCard> result = new ArrayList<>();
if (bankCardListBean == null || bankCardListBean.getCards() == null) {
return result;
}
// 遍历数组,逐个转换
for (ApiService.BankCardBean bean : bankCardListBean.getCards()) {
BankCard card = new BankCard();
card.setId(bean.getId());
card.setCardNo(bean.getCardNo());
card.setBankName(bean.getBankName());
card.setDefault(bean.isDefault());
result.add(card);
}
return result;
}
// 添加银行卡
public void addBankCard(String cardNo, String bankName) {
showLoading();
ApiService apiService = RetrofitManager.getApiService(com.payment.MyApplication.getContext());
// 正确直接通过构造方法传入参数无需再调用setter
ApiService.AddBankCardRequest request = new ApiService.AddBankCardRequest(cardNo, bankName);
// 修正回调类型为ResultBean<BaseResponse>
apiService.addBankCard(request).enqueue(new Callback<ApiService.ResultBean<ApiService.BaseResponse>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BaseResponse>> call,
Response<ApiService.ResultBean<ApiService.BaseResponse>> response) {
hideLoading();
// 转换为UI层需要的ResultBean<String>
ApiService.ResultBean<String> uiResult = new ApiService.ResultBean<>();
if (response.body() != null) {
uiResult.setSuccess(response.body().isSuccess());
uiResult.setMsg(response.body().getMsg());
// 使用BaseResponse的message作为数据或根据实际需求提取
uiResult.setData(response.body().getData() != null ? response.body().getData().getMessage() : "");
}
addCardResult.postValue(uiResult);
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Throwable t) {
hideLoading();
sendErrorMsg("添加银行卡失败:" + t.getMessage());
addCardResult.postValue(null);
}
});
}
// 设置默认银行卡
public void setDefaultCard(int cardId) {
showLoading();
ApiService apiService = RetrofitManager.getApiService(com.payment.MyApplication.getContext());
// 正确通过String.valueOf()将int转换为String
ApiService.DefaultBankCardRequest request = new ApiService.DefaultBankCardRequest(String.valueOf(cardId));
// 正确泛型类型与接口定义一致BaseResponse
apiService.setDefaultBankCard(request).enqueue(new Callback<ApiService.ResultBean<ApiService.BaseResponse>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Response<ApiService.ResultBean<ApiService.BaseResponse>> response) {
if (response.isSuccessful() && response.body() != null) {
ApiService.ResultBean<ApiService.BaseResponse> result = response.body();
if (result.isSuccess()) {
// 处理成功逻辑(如提示"设置默认银行卡成功"
} else {
// 处理业务失败如显示错误信息result.getMsg()
}
} else {
// 处理请求失败(如网络异常)
}
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Throwable t) {
// 处理网络错误
}
});
}
// 删除银行卡
public void deleteBankCard(int cardId) {
showLoading();
ApiService apiService = RetrofitManager.getApiService(com.payment.MyApplication.getContext());
// 正确通过String.valueOf()将int转换为String
ApiService.DeleteBankCardRequest request = new ApiService.DeleteBankCardRequest(String.valueOf(cardId));
// 正确代码泛型类型与接口定义一致BaseResponse
apiService.deleteBankCard(request).enqueue(new Callback<ApiService.ResultBean<ApiService.BaseResponse>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BaseResponse>> call,
Response<ApiService.ResultBean<ApiService.BaseResponse>> response) {
hideLoading();
// 转换为UI层需要的ResultBean<String>保持与LiveData类型一致
ApiService.ResultBean<String> uiResult = new ApiService.ResultBean<>();
if (response.body() != null) {
uiResult.setSuccess(response.body().isSuccess());
uiResult.setMsg(response.body().getMsg());
// 可根据实际需求设置data如使用BaseResponse的message
uiResult.setData(response.body().getData() != null ? response.body().getData().getMessage() : "");
}
deleteCardResult.postValue(uiResult);
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Throwable t) {
hideLoading();
sendErrorMsg("删除银行卡失败:" + t.getMessage());
deleteCardResult.postValue(null);
}
});
}
// 查询余额修正为ApiService.BalanceBean
public void getBalance() {
showLoading();
ApiService apiService = RetrofitManager.getApiService(com.payment.MyApplication.getContext());
apiService.getBalance().enqueue(new Callback<ApiService.ResultBean<ApiService.BalanceBean>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BalanceBean>> call, Response<ApiService.ResultBean<ApiService.BalanceBean>> response) {
hideLoading();
balanceResult.postValue(response.body());
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BalanceBean>> call, Throwable t) {
hideLoading();
sendErrorMsg("获取余额失败:" + t.getMessage());
balanceResult.postValue(null);
}
});
}
// 充值
public void recharge(double amount, int cardId) {
showLoading();
ApiService apiService = RetrofitManager.getApiService(com.payment.MyApplication.getContext());
ApiService.RechargeWithdrawRequest request = new ApiService.RechargeWithdrawRequest(
String.valueOf(amount), // 转换为String类型接口要求amount为String
String.valueOf(cardId) // 转换为String类型接口要求cardId为String
);
// 正确代码泛型类型与接口定义一致BaseResponse
apiService.recharge(request).enqueue(new Callback<ApiService.ResultBean<ApiService.BaseResponse>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BaseResponse>> call,
Response<ApiService.ResultBean<ApiService.BaseResponse>> response) {
hideLoading();
// 转换为UI层需要的ResultBean<String>与rechargeResult的LiveData类型匹配
ApiService.ResultBean<String> uiResult = new ApiService.ResultBean<>();
if (response.body() != null) {
uiResult.setSuccess(response.body().isSuccess());
uiResult.setMsg(response.body().getMsg());
// 提取BaseResponse中的message作为data或根据实际需求设置
uiResult.setData(response.body().getData() != null ? response.body().getData().getMessage() : "");
}
rechargeResult.postValue(uiResult);
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Throwable t) {
hideLoading();
sendErrorMsg("充值失败:" + t.getMessage());
rechargeResult.postValue(null);
}
});
}
// 提现
public void withdraw(double amount, int cardId) {
showLoading();
ApiService apiService = RetrofitManager.getApiService(com.payment.MyApplication.getContext());
ApiService.RechargeWithdrawRequest request = new ApiService.RechargeWithdrawRequest(
String.valueOf(amount), // 转换为String接口要求amount为String类型
String.valueOf(cardId) // 转换为String接口要求cardId为String类型
);
// 正确代码泛型类型与接口定义一致BaseResponse
apiService.withdraw(request).enqueue(new Callback<ApiService.ResultBean<ApiService.BaseResponse>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BaseResponse>> call,
Response<ApiService.ResultBean<ApiService.BaseResponse>> response) {
hideLoading();
// 转换为UI层需要的ResultBean<String>与withdrawResult的LiveData类型匹配
ApiService.ResultBean<String> uiResult = new ApiService.ResultBean<>();
if (response.body() != null) {
uiResult.setSuccess(response.body().isSuccess());
uiResult.setMsg(response.body().getMsg());
// 提取BaseResponse中的message作为data或根据实际需求设置
uiResult.setData(response.body().getData() != null ? response.body().getData().getMessage() : "");
}
withdrawResult.postValue(uiResult);
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Throwable t) {
hideLoading();
sendErrorMsg("提现失败:" + t.getMessage());
withdrawResult.postValue(null);
}
});
}
}

@ -0,0 +1,80 @@
package com.payment.asset;
import com.payment.base.BaseActivity;
import com.payment.R;
import com.payment.model.Balance;
import com.payment.network.ApiService;
import com.payment.utils.IntentUtils;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class BalanceActivity extends BaseActivity {
private TextView tvBalance, tvUpdateTime;
private Button btnRecharge, btnWithdraw;
private AssetViewModel assetViewModel;
@Override
protected int getLayoutId() {
return R.layout.activity_balance;
}
@Override
protected void initView() {
tvBalance = findViewById(R.id.tv_balance);
tvUpdateTime = findViewById(R.id.tv_update_time);
btnRecharge = findViewById(R.id.btn_recharge);
btnWithdraw = findViewById(R.id.btn_withdraw);
}
@Override
protected void initData() {
assetViewModel = new ViewModelProvider(this).get(AssetViewModel.class);
// 查询余额
assetViewModel.getBalance();
// 观察余额结果处理ApiService.BalanceBean类型
assetViewModel.getBalanceResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
// 接口返回的是ApiService内部的BalanceBean
ApiService.BalanceBean apiBalance = resultBean.getData();
if (apiBalance != null) {
// 转换为本地Balance模型或直接使用apiBalance
Balance balance = new Balance();
// 注意根据ApiService.BalanceBean实际字段调整setter
// 假设BalanceBean的余额字段是String类型需要转换为double
balance.setBalance(Double.parseDouble(apiBalance.getBalance()));
balance.setUpdateTime(apiBalance.getUpdateTime());
// 更新UI
tvBalance.setText(String.format("%.2f 元", balance.getBalance()));
tvUpdateTime.setText("最后更新:" + (balance.getUpdateTime() != null ? balance.getUpdateTime() : "未知"));
} else {
tvBalance.setText("0.00 元");
showToast("余额数据为空");
}
} else {
tvBalance.setText("0.00 元");
showToast("获取余额失败:" + (resultBean != null ? resultBean.getMsg() : "未知错误"));
}
});
}
@Override
protected void bindEvent() {
// 充值
btnRecharge.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString("type", "recharge");
IntentUtils.jumpToWithBundle(this, RechargeWithdrawActivity.class, bundle, false);
});
// 提现
btnWithdraw.setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putString("type", "withdraw");
IntentUtils.jumpToWithBundle(this, RechargeWithdrawActivity.class, bundle, false);
});
}
}

@ -0,0 +1,97 @@
package com.payment.asset;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.payment.R;
import com.payment.model.BankCard;
import java.util.List;
import android.widget.Button;
public class BankCardAdapter extends RecyclerView.Adapter<BankCardAdapter.CardViewHolder> {
private Context context;
private List<BankCard> cardList;
private OnItemActionListener actionListener;
// 点击事件接口
public interface OnItemActionListener {
void onAction(BankCard card, String action);
}
public void setOnItemActionListener(OnItemActionListener listener) {
this.actionListener = listener;
}
public BankCardAdapter(Context context, List<BankCard> cardList) {
this.context = context;
this.cardList = cardList;
}
// 更新数据
public void updateData(List<BankCard> cardList) {
this.cardList = cardList;
notifyDataSetChanged();
}
@NonNull
@Override
public CardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_bank_card, parent, false);
return new CardViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull CardViewHolder holder, int position) {
BankCard card = cardList.get(position);
if (card == null) return;
// 显示银行名称和脱敏卡号
holder.tvBankName.setText(card.getBankName());
String cardNo = card.getCardNo();
String maskedCardNo = cardNo.replaceAll("(\\d{4})(\\d{8})(\\d{4})", "$1 **** **** $3");
holder.tvCardNo.setText(maskedCardNo);
// 显示默认卡标识
holder.ivDefault.setVisibility(card.isDefault() ? View.VISIBLE : View.GONE);
// 设置默认卡点击
holder.btnSetDefault.setOnClickListener(v -> {
if (actionListener != null) {
actionListener.onAction(card, "setDefault");
}
});
// 删除卡点击
holder.btnDelete.setOnClickListener(v -> {
if (actionListener != null) {
actionListener.onAction(card, "delete");
}
});
}
@Override
public int getItemCount() {
return cardList == null ? 0 : cardList.size();
}
// ViewHolder
static class CardViewHolder extends RecyclerView.ViewHolder {
TextView tvBankName, tvCardNo;
ImageView ivDefault;
Button btnSetDefault, btnDelete;
public CardViewHolder(@NonNull View itemView) {
super(itemView);
tvBankName = itemView.findViewById(R.id.tv_bank_name);
tvCardNo = itemView.findViewById(R.id.tv_card_no);
ivDefault = itemView.findViewById(R.id.iv_default);
btnSetDefault = itemView.findViewById(R.id.btn_set_default);
btnDelete = itemView.findViewById(R.id.btn_delete);
}
}
}

@ -0,0 +1,101 @@
package com.payment.asset;
import com.payment.base.BaseActivity;
import com.payment.R;
import com.payment.model.BankCard;
import com.payment.utils.IntentUtils;
import com.payment.utils.ToastUtils;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.util.List;
public class BankCardListActivity extends BaseActivity {
private RecyclerView rvBankCards;
private Button btnAddCard;
private TextView tvEmpty;
private BankCardAdapter adapter;
private AssetViewModel assetViewModel;
@Override
protected int getLayoutId() {
return R.layout.activity_bank_card_list;
}
@Override
protected void initView() {
rvBankCards = findViewById(R.id.rv_bank_cards);
btnAddCard = findViewById(R.id.btn_add_card);
tvEmpty = findViewById(R.id.tv_empty);
// 初始化RecyclerView
rvBankCards.setLayoutManager(new LinearLayoutManager(this));
adapter = new BankCardAdapter(this, null);
rvBankCards.setAdapter(adapter);
}
@Override
protected void initData() {
assetViewModel = new ViewModelProvider(this).get(AssetViewModel.class);
// 获取银行卡列表
assetViewModel.getBankCardList();
// 观察列表结果
assetViewModel.getBankCardListResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
List<BankCard> cardList = resultBean.getData();
if (cardList != null && !cardList.isEmpty()) {
rvBankCards.setVisibility(View.VISIBLE);
tvEmpty.setVisibility(View.GONE);
adapter.updateData(cardList);
} else {
rvBankCards.setVisibility(View.GONE);
tvEmpty.setVisibility(View.VISIBLE);
}
} else {
ToastUtils.showToast(this, "获取银行卡列表失败");
}
});
// 观察默认卡设置结果
assetViewModel.getDefaultCardResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
ToastUtils.showToast(this, "默认银行卡设置成功");
assetViewModel.getBankCardList(); // 刷新列表
} else {
ToastUtils.showToast(this, "设置失败");
}
});
// 观察删除结果
assetViewModel.getDeleteCardResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
ToastUtils.showToast(this, "银行卡删除成功");
assetViewModel.getBankCardList(); // 刷新列表
} else {
ToastUtils.showToast(this, "删除失败");
}
});
}
@Override
protected void bindEvent() {
// 添加银行卡
btnAddCard.setOnClickListener(v -> IntentUtils.jumpTo(this, AddBankCardActivity.class, false));
// 列表项点击事件(设置默认卡/删除)
adapter.setOnItemActionListener((card, action) -> {
switch (action) {
case "setDefault":
assetViewModel.setDefaultCard(card.getId());
break;
case "delete":
assetViewModel.deleteBankCard(card.getId());
break;
}
});
}
}

@ -0,0 +1,127 @@
package com.payment.asset;
import com.payment.base.BaseActivity;
import com.payment.R;
import com.payment.model.BankCard;
import com.payment.utils.ToastUtils;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.ArrayAdapter;
import java.util.List;
public class RechargeWithdrawActivity extends BaseActivity {
private RadioGroup rgType;
private EditText etAmount;
private Spinner spBankCards;
private Button btnConfirm;
private AssetViewModel assetViewModel;
private List<BankCard> cardList;
private String type = "recharge"; // 默认充值
@Override
protected int getLayoutId() {
return R.layout.activity_recharge_withdraw;
}
@Override
protected void initView() {
rgType = findViewById(R.id.rg_type);
etAmount = findViewById(R.id.et_amount);
spBankCards = findViewById(R.id.sp_bank_cards);
btnConfirm = findViewById(R.id.btn_confirm);
}
@Override
protected void initData() {
assetViewModel = new ViewModelProvider(this).get(AssetViewModel.class);
// 获取银行卡列表(用于下拉选择)
assetViewModel.getBankCardList();
assetViewModel.getBankCardListResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
cardList = resultBean.getData();
if (cardList != null && !cardList.isEmpty()) {
// 初始化下拉框
String[] cardNames = new String[cardList.size()];
for (int i = 0; i < cardList.size(); i++) {
BankCard card = cardList.get(i);
cardNames[i] = card.getBankName() + "(" + card.getCardNo().replaceAll("(\\d{4})(\\d{8})(\\d{4})", "$1 **** **** $3") + ")";
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, cardNames);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spBankCards.setAdapter(adapter);
} else {
showToast("暂无绑定银行卡,请先添加");
finish();
}
} else {
showToast("获取银行卡失败");
finish();
}
});
// 观察充值结果
assetViewModel.getRechargeResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
showToast("充值成功");
finish();
} else {
showToast("充值失败:" + (resultBean != null ? resultBean.getMsg() : "网络异常"));
}
});
// 观察提现结果
assetViewModel.getWithdrawResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
showToast("提现申请提交成功");
finish();
} else {
showToast("提现失败:" + (resultBean != null ? resultBean.getMsg() : "网络异常"));
}
});
}
@Override
protected void bindEvent() {
// 选择充值/提现类型
rgType.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.rb_recharge) {
type = "recharge";
btnConfirm.setText("确认充值");
} else if (checkedId == R.id.rb_withdraw) {
type = "withdraw";
btnConfirm.setText("确认提现");
}
});
// 确认按钮
btnConfirm.setOnClickListener(v -> {
String amountStr = etAmount.getText().toString().trim();
if (amountStr.isEmpty()) {
showToast("请输入金额");
return;
}
double amount = Double.parseDouble(amountStr);
if (amount <= 0) {
showToast("金额必须大于0");
return;
}
// 获取选中的银行卡ID
int selectedPosition = spBankCards.getSelectedItemPosition();
int cardId = cardList.get(selectedPosition).getId();
// 执行充值或提现
if ("recharge".equals(type)) {
assetViewModel.recharge(amount, cardId);
} else {
assetViewModel.withdraw(amount, cardId);
}
});
}
}

@ -0,0 +1,48 @@
package com.payment.base;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.payment.utils.ToastUtils;
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置布局
setContentView(getLayoutId());
// 初始化视图
initView();
// 初始化数据
initData();
// 绑定事件
bindEvent();
}
// 获取布局ID子类实现
protected abstract int getLayoutId();
// 初始化视图(子类按需实现)
protected abstract void initView();
// 初始化数据(子类按需实现)
protected void initData() {}
// 绑定事件(子类按需实现)
protected void bindEvent() {}
// 简化Toast调用
protected void showToast(String msg) {
ToastUtils.showToast(this, msg);
}
// 登录过期处理(统一跳转登录页)
protected void handleLoginExpired() {
showToast("登录已过期,请重新登录");
// 清除Token
com.payment.utils.TokenUtils.clearToken(this);
// 跳转到登录页关闭所有栈内Activity
com.payment.utils.IntentUtils.jumpTo(this, com.payment.user.LoginActivity.class, true);
finishAffinity();
}
}

@ -0,0 +1,40 @@
package com.payment.base;
import androidx.lifecycle.ViewModel;
// 在现有导入基础上补充以下两行
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.LiveData;
import com.payment.utils.ToastUtils;
public abstract class BaseViewModel extends ViewModel {
// 加载状态true-加载中false-加载完成)
private final MutableLiveData<Boolean> loadingState = new MutableLiveData<>();
// 错误信息
private final MutableLiveData<String> errorMsg = new MutableLiveData<>();
// 获取加载状态观察器
public LiveData<Boolean> getLoadingState() {
return loadingState;
}
// 获取错误信息观察器
public LiveData<String> getErrorMsg() {
return errorMsg;
}
// 显示加载
protected void showLoading() {
loadingState.postValue(true);
}
// 隐藏加载
protected void hideLoading() {
loadingState.postValue(false);
}
// 发送错误信息
protected void sendErrorMsg(String msg) {
errorMsg.postValue(msg);
ToastUtils.showToast(com.payment.MyApplication.getContext(), msg);
}
}

@ -0,0 +1,10 @@
package com.payment.base;
public class NetConfig {
// 模拟服务器BaseUrlMockWebServer
public static final String BASE_URL = "http://10.0.2.2:8080/";
// 后续对接真实后端的BaseUrl预留
public static final String REAL_BASE_URL = "http://10.0.2.2:8080/";
// 网络请求超时时间(秒)
public static final int TIMEOUT = 10;
}

@ -0,0 +1,18 @@
package com.payment.base;
public class ResultBean<T> {
private int code; // 响应码200成功其他失败
private String msg; // 响应信息
private T data; // 响应数据
// getter + setter
public int getCode() { return code; }
public void setCode(int code) { this.code = code; }
public String getMsg() { return msg; }
public void setMsg(String msg) { this.msg = msg; }
public T getData() { return data; }
public void setData(T data) { this.data = data; }
// 快捷判断成功方法
public boolean isSuccess() { return code == 200; }
}

@ -0,0 +1,12 @@
package com.payment.model;
public class Balance {
private double balance; // 账户余额
private String updateTime; // 最后更新时间
// getter + setter
public double getBalance() { return balance; }
public void setBalance(double balance) { this.balance = balance; }
public String getUpdateTime() { return updateTime; }
public void setUpdateTime(String updateTime) { this.updateTime = updateTime; }
}

@ -0,0 +1,18 @@
package com.payment.model;
public class BankCard {
private int id; // 银行卡ID
private String cardNo; // 银行卡号(脱敏)
private String bankName; // 银行名称
private boolean isDefault; // 是否默认卡
// getter + setter
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getCardNo() { return cardNo; }
public void setCardNo(String cardNo) { this.cardNo = cardNo; }
public String getBankName() { return bankName; }
public void setBankName(String bankName) { this.bankName = bankName; }
public boolean isDefault() { return isDefault; }
public void setDefault(boolean aDefault) { isDefault = aDefault; }
}

@ -0,0 +1,21 @@
package com.payment.model;
public class User {
private int userId; // 用户ID
private String userName; // 用户名
private String token; // 登录令牌
private String realName; // 真实姓名(实名认证后)
private String idCard; // 身份证号(脱敏)
// getter + setter
public int getUserId() { return userId; }
public void setUserId(int userId) { this.userId = userId; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public String getToken() { return token; }
public void setToken(String token) { this.token = token; }
public String getRealName() { return realName; }
public void setRealName(String realName) { this.realName = realName; }
public String getIdCard() { return idCard; }
public void setIdCard(String idCard) { this.idCard = idCard; }
}

@ -0,0 +1,498 @@
package com.payment.network;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
/**
*
*/
public interface ApiService {
// ------------------------ 用户模块接口 ------------------------
/**
*
*/
@POST("user/login")
Call<ResultBean<UserBean>> login(@Body LoginRequest loginRequest);
/**
*
*/
@POST("user/register")
Call<ResultBean<BaseResponse>> register(@Body RegisterRequest registerRequest);
/**
*
*/
@GET("user/info")
Call<ResultBean<UserBean>> getUserInfo();
// ------------------------ 实名认证模块接口 ------------------------
/**
*
*/
@POST("user/auth/submit")
Call<ResultBean<BaseResponse>> submitRealNameAuth(@Body RealNameAuthRequest authRequest);
/**
*
*/
@GET("user/auth/status")
Call<ResultBean<AuditStatusBean>> getAuditStatus();
// ------------------------ 银行卡模块接口 ------------------------
/**
*
*/
@GET("bankCard/list")
Call<ResultBean<BankCardListBean>> getBankCardList();
/**
*
*/
@POST("bankCard/add")
Call<ResultBean<BaseResponse>> addBankCard(@Body AddBankCardRequest cardRequest);
/**
*
*/
@POST("bankCard/setDefault")
Call<ResultBean<BaseResponse>> setDefaultBankCard(@Body DefaultBankCardRequest request);
/**
*
*/
@POST("bankCard/delete")
Call<ResultBean<BaseResponse>> deleteBankCard(@Body DeleteBankCardRequest request);
// ------------------------ 资产模块接口 ------------------------
/**
*
*/
@GET("asset/balance")
Call<ResultBean<BalanceBean>> getBalance();
/**
*
*/
@POST("asset/recharge")
Call<ResultBean<BaseResponse>> recharge(@Body RechargeWithdrawRequest request);
/**
*
*/
@POST("asset/withdraw")
Call<ResultBean<BaseResponse>> withdraw(@Body RechargeWithdrawRequest request);
// ------------------------ 请求参数实体类 ------------------------
/**
*
*/
class LoginRequest {
private String phone;
private String password;
public LoginRequest(String phone, String password) {
this.phone = phone;
this.password = password;
}
// Getter & Setter
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
/**
*
*/
class RegisterRequest {
private String phone;
private String verifyCode;
private String password;
public RegisterRequest(String phone, String verifyCode, String password) {
this.phone = phone;
this.verifyCode = verifyCode;
this.password = password;
}
// Getter & Setter
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getVerifyCode() {
return verifyCode;
}
public void setVerifyCode(String verifyCode) {
this.verifyCode = verifyCode;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
/**
*
*/
class RealNameAuthRequest {
private String realName;
private String idCard;
public RealNameAuthRequest(String realName, String idCard) {
this.realName = realName;
this.idCard = idCard;
}
// Getter & Setter
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getIdCard() {
return idCard;
}
public void setIdCard(String idCard) {
this.idCard = idCard;
}
}
/**
*
*/
class AddBankCardRequest {
private String cardNo;
private String bankName;
public AddBankCardRequest(String cardNo, String bankName) {
this.cardNo = cardNo;
this.bankName = bankName;
}
// Getter & Setter
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
}
/**
*
*/
class DefaultBankCardRequest {
private String cardId;
public DefaultBankCardRequest(String cardId) {
this.cardId = cardId;
}
// Getter & Setter
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
}
/**
*
*/
class DeleteBankCardRequest {
private String cardId;
public DeleteBankCardRequest(String cardId) {
this.cardId = cardId;
}
// Getter & Setter
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
}
/**
* /
*/
class RechargeWithdrawRequest {
private String amount;
private String cardId;
public RechargeWithdrawRequest(String amount, String cardId) {
this.amount = amount;
this.cardId = cardId;
}
// Getter & Setter
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
}
// ------------------------ 响应结果实体类 ------------------------
/**
*
*/
class BaseResponse {
private int code;
private String message;
// Getter & Setter
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
/**
*
*/
class ResultBean<T> {
private int code;
private String msg;
private T data;
private boolean success;
// Getter & Setter
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}
/**
*
*/
class UserBean {
private String userId;
private String phone;
private String realName;
private int authStatus; // 0:未认证 1:审核中 2:已认证
private String token; // 新增登录返回的Token字段
// Getter & Setter
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public int getAuthStatus() {
return authStatus;
}
public void setAuthStatus(int authStatus) {
this.authStatus = authStatus;
}
// 新增Token的getter方法
public String getToken() {
return token;
}
// 新增Token的setter方法
public void setToken(String token) {
this.token = token;
}
}
/**
*
*/
class AuditStatusBean {
private int status; // 0:未提交 1:审核中 2:审核通过 3:审核驳回
private String desc; // 状态描述
// Getter & Setter
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
/**
*
*/
class BankCardListBean {
private BankCardBean[] cards;
// Getter & Setter
public BankCardBean[] getCards() {
return cards;
}
public void setCards(BankCardBean[] cards) {
this.cards = cards;
}
}
/**
*
*/
// 在 ApiService 中添加
class BankCardBean {
private int id; // 与 BankCard 对应
private String cardNo; // 与 BankCard 对应
private String bankName; // 与 BankCard 对应
private boolean isDefault; // 与 BankCard 对应
// Getter & Setter
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getCardNo() { return cardNo; }
public void setCardNo(String cardNo) { this.cardNo = cardNo; }
public String getBankName() { return bankName; }
public void setBankName(String bankName) { this.bankName = bankName; }
public boolean isDefault() { return isDefault; }
public void setDefault(boolean aDefault) { isDefault = aDefault; }
}
/**
*
*/
class BalanceBean {
private String balance;
private String updateTime;
// Getter & Setter
public String getBalance() {
return balance;
}
public void setBalance(String balance) {
this.balance = balance;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
}
}

@ -0,0 +1,74 @@
package com.payment.network;
import android.util.Log;
import java.io.IOException;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
public class MockServerManager {
private static MockWebServer mockWebServer;
private static final String TAG = "MockServerManager";
// 启动模拟服务器
public static void startMockServer() {
if (mockWebServer == null) {
mockWebServer = new MockWebServer();
try {
mockWebServer.start(8080); // 启动在8080端口
Log.d(TAG, "模拟服务器启动成功,地址:" + mockWebServer.url("/"));
// 配置接口模拟响应
configMockResponses();
} catch (IOException e) {
Log.e(TAG, "模拟服务器启动失败:" + e.getMessage());
e.printStackTrace();
}
}
}
// 配置接口模拟数据
private static void configMockResponses() {
// 1. 登录接口模拟响应
mockWebServer.enqueue(new MockResponse()
.setBody("{\"code\":200,\"msg\":\"登录成功\",\"data\":{\"token\":\"mock_token_123\",\"userName\":\"测试用户\",\"userId\":1001}}")
.setResponseCode(200));
// 2. 实名认证接口模拟响应
mockWebServer.enqueue(new MockResponse()
.setBody("{\"code\":200,\"msg\":\"实名认证提交成功,请等待审核\",\"data\":null}")
.setResponseCode(200));
// 3. 审核状态接口模拟响应
mockWebServer.enqueue(new MockResponse()
.setBody("{\"code\":200,\"msg\":\"success\",\"data\":{\"status\":1,\"desc\":\"审核中\"}}") // 0-未提交1-审核中2-通过3-驳回
.setResponseCode(200));
// 4. 银行卡列表接口模拟响应
mockWebServer.enqueue(new MockResponse()
.setBody("{\"code\":200,\"msg\":\"success\",\"data\":[" +
"{\"id\":1,\"cardNo\":\"622202********1234\",\"bankName\":\"中国工商银行\",\"isDefault\":true}," +
"{\"id\":2,\"cardNo\":\"621700********5678\",\"bankName\":\"中国建设银行\",\"isDefault\":false}]}" +
"")
.setResponseCode(200));
// 5. 余额查询接口模拟响应
mockWebServer.enqueue(new MockResponse()
.setBody("{\"code\":200,\"msg\":\"success\",\"data\":{\"balance\":1234.56}}")
.setResponseCode(200));
}
// 停止模拟服务器
public static void stopMockServer() {
if (mockWebServer != null) {
try {
mockWebServer.shutdown();
mockWebServer = null;
Log.d(TAG, "模拟服务器已停止");
} catch (IOException e) {
Log.e(TAG, "模拟服务器停止失败:" + e.getMessage());
e.printStackTrace();
}
}
}
}

@ -0,0 +1,111 @@
package com.payment.network;
import android.content.Context; // 新增:为了修复报错引入的
import com.payment.base.NetConfig;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okhttp3.Protocol;
import java.io.IOException;
public class RetrofitManager {
private static RetrofitManager instance;
private Retrofit retrofit;
private RetrofitManager() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
// ★★★ 核心安卓A 的假后端数据中心 ★★★
Interceptor mockInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String url = request.url().toString();
String responseJson = "";
// ------------- 模块一:用户中心 (Week 9) -------------
if (url.contains("/user/login")) {
responseJson = "{\"code\": 200, \"msg\": \"登录成功\", \"data\": {\"token\": \"mock_token_123456\", \"username\": \"测试用户A\", \"realNameStatus\": 1}}";
}
else if (url.contains("/user/register")) {
responseJson = "{\"code\": 200, \"msg\": \"注册成功,请登录\", \"data\": null}";
}
else if (url.contains("/user/info")) {
responseJson = "{\"code\": 200, \"msg\": \"成功\", \"data\": {\"username\": \"测试用户A\", \"auditStatus\": 1}}";
}
else if (url.contains("/user/realname")) {
responseJson = "{\"code\": 200, \"msg\": \"提交成功,等待审核\", \"data\": null}";
}
// ------------- 模块二:资金与卡包 (Week 10) -------------
else if (url.contains("/asset/balance")) {
responseJson = "{\"code\": 200, \"msg\": \"成功\", \"data\": {\"balance\": 10086.50}}";
}
else if (url.contains("/asset/bankcard/list")) {
responseJson = "{\"code\": 200, \"msg\": \"成功\", \"data\": [" +
"{\"id\": 1, \"bankName\": \"中国工商银行\", \"cardNo\": \"6222021001112222\", \"cardType\": \"储蓄卡\"}," +
"{\"id\": 2, \"bankName\": \"招商银行\", \"cardNo\": \"6225888899996666\", \"cardType\": \"信用卡\"}" +
"]}";
}
else if (url.contains("/asset/bankcard/add")) {
responseJson = "{\"code\": 200, \"msg\": \"绑卡成功\", \"data\": null}";
}
else if (url.contains("/asset/recharge") || url.contains("/asset/withdraw")) {
responseJson = "{\"code\": 200, \"msg\": \"操作成功\", \"data\": null}";
}
if (!responseJson.isEmpty()) {
try { Thread.sleep(500); } catch (InterruptedException e) {}
return new Response.Builder()
.code(200)
.message("OK")
.request(request)
.protocol(Protocol.HTTP_1_1)
.body(ResponseBody.create(MediaType.parse("application/json"), responseJson))
.addHeader("content-type", "application/json")
.build();
}
return chain.proceed(request);
}
};
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(logging)
.addInterceptor(mockInterceptor)
.connectTimeout(15, TimeUnit.SECONDS)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(NetConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
}
public static RetrofitManager getInstance() {
if (instance == null) {
synchronized (RetrofitManager.class) {
if (instance == null) instance = new RetrofitManager();
}
}
return instance;
}
public <T> T create(Class<T> service) {
return retrofit.create(service);
}
// ★★★★★ 修复报错的关键方法 ★★★★★
// 这个方法就是为了兼容 AssetViewModel 里的旧代码
// 虽然参数里传了 Context但其实我们不需要用到它直接忽略即可
public static ApiService getApiService(Context context) {
return getInstance().create(ApiService.class);
}
}

@ -0,0 +1,42 @@
package com.payment.network;
import android.content.Context;
import androidx.annotation.NonNull;
import com.payment.utils.TokenUtils;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* TokenToken
*/
public class TokenInterceptor implements Interceptor {
private Context context;
// 构造方法传入上下文用于获取Token
public TokenInterceptor(Context context) {
this.context = context.getApplicationContext(); // 使用全局上下文,避免内存泄漏
}
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
// 1. 获取原始请求
Request originalRequest = chain.request();
// 2. 从SP中获取Token需提前实现TokenUtils工具类
String token = TokenUtils.getToken(context);
// 3. 若Token存在添加到请求头否则保持原请求
Request.Builder requestBuilder = originalRequest.newBuilder();
if (token != null && !token.isEmpty()) {
requestBuilder.addHeader("Authorization", "Bearer " + token); // JWT标准格式也可根据后端要求调整
requestBuilder.addHeader("token", token); // 若后端直接用token字段接收补充此头
}
// 4. 构建新请求并继续执行
Request newRequest = requestBuilder.build();
return chain.proceed(newRequest);
}
}

@ -0,0 +1,87 @@
package com.payment.ui;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.FrameLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import com.payment.R;
import com.payment.ui.fragment.HomeFragment;
import com.payment.ui.fragment.TravelCodeFragment;
import com.payment.ui.fragment.BillFragment;
import com.payment.ui.fragment.MineFragment;
public class MainActivity extends AppCompatActivity {
private FrameLayout flContent;
private RadioGroup rgBottomNav;
private RadioButton rbHome, rbTravel, rbBill, rbMine;
// 碎片实例
private Fragment homeFragment, travelFragment, billFragment, mineFragment;
private Fragment currentFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化视图
initView();
// 初始化碎片
initFragment();
// 底部导航点击事件
setNavClickListener();
}
private void initView() {
flContent = findViewById(R.id.fl_content);
rgBottomNav = findViewById(R.id.rg_bottom_nav);
rbHome = findViewById(R.id.rb_home);
rbTravel = findViewById(R.id.rb_travel);
rbBill = findViewById(R.id.rb_bill);
rbMine = findViewById(R.id.rb_mine);
}
private void initFragment() {
homeFragment = new HomeFragment();
travelFragment = new TravelCodeFragment();
billFragment = new BillFragment();
mineFragment = new MineFragment();
// 默认显示首页
currentFragment = homeFragment;
getSupportFragmentManager().beginTransaction()
.add(R.id.fl_content, homeFragment)
.commit();
}
private void setNavClickListener() {
rgBottomNav.setOnCheckedChangeListener((group, checkedId) -> {
Fragment targetFragment = null;
// 用if-else替代switch-case
if (checkedId == R.id.rb_home) {
targetFragment = homeFragment;
} else if (checkedId == R.id.rb_travel) {
targetFragment = travelFragment;
} else if (checkedId == R.id.rb_bill) {
targetFragment = billFragment;
} else if (checkedId == R.id.rb_mine) {
targetFragment = mineFragment;
}
// 切换碎片
if (targetFragment != null && targetFragment != currentFragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!targetFragment.isAdded()) {
transaction.add(R.id.fl_content, targetFragment);
}
transaction.hide(currentFragment).show(targetFragment).commit();
currentFragment = targetFragment;
}
});
}
}

@ -0,0 +1,22 @@
package com.payment.ui.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.payment.R;
public class BillFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_bill, container, false);
TextView tvTip = view.findViewById(R.id.tv_tip);
tvTip.setText("账单功能暂未开放,敬请期待");
return view;
}
}

@ -0,0 +1,68 @@
package com.payment.ui.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.payment.R;
import com.payment.utils.IntentUtils;
import com.payment.asset.BalanceActivity;
import com.payment.asset.BankCardListActivity;
public class HomeFragment extends Fragment {
private Button btnBalance, btnBankCard, btnRecharge, btnWithdraw;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home, container, false);
initView(view);
bindEvent();
return view;
}
private void initView(View view) {
btnBalance = view.findViewById(R.id.btn_balance);
btnBankCard = view.findViewById(R.id.btn_bank_card);
btnRecharge = view.findViewById(R.id.btn_recharge);
btnWithdraw = view.findViewById(R.id.btn_withdraw);
}
private void bindEvent() {
// 余额查询
btnBalance.setOnClickListener(v -> {
if (getActivity() != null) {
IntentUtils.jumpTo(getActivity(), BalanceActivity.class, false);
}
});
// 银行卡管理
btnBankCard.setOnClickListener(v -> {
if (getActivity() != null) {
IntentUtils.jumpTo(getActivity(), BankCardListActivity.class, false);
}
});
// 充值
btnRecharge.setOnClickListener(v -> {
if (getActivity() != null) {
Bundle bundle = new Bundle();
bundle.putString("type", "recharge");
IntentUtils.jumpToWithBundle(getActivity(), com.payment.asset.RechargeWithdrawActivity.class, bundle, false);
}
});
// 提现
btnWithdraw.setOnClickListener(v -> {
if (getActivity() != null) {
Bundle bundle = new Bundle();
bundle.putString("type", "withdraw");
IntentUtils.jumpToWithBundle(getActivity(), com.payment.asset.RechargeWithdrawActivity.class, bundle, false);
}
});
}
}

@ -0,0 +1,69 @@
package com.payment.ui.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.payment.R;
import com.payment.utils.IntentUtils;
import com.payment.utils.TokenUtils;
import com.payment.user.AuditStatusActivity;
import com.payment.user.LoginActivity;
import com.payment.user.RealNameAuthActivity;
public class MineFragment extends Fragment {
private TextView tvUserName;
private Button btnRealName, btnAuditStatus, btnLogout;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_mine, container, false);
initView(view);
initData();
bindEvent();
return view;
}
private void initView(View view) {
tvUserName = view.findViewById(R.id.tv_user_name);
btnRealName = view.findViewById(R.id.btn_real_name);
btnAuditStatus = view.findViewById(R.id.btn_audit_status);
btnLogout = view.findViewById(R.id.btn_logout);
}
private void initData() {
// 模拟显示用户名实际应从登录成功后的User对象获取
tvUserName.setText("测试用户");
}
private void bindEvent() {
// 实名认证
btnRealName.setOnClickListener(v -> {
if (getActivity() != null) {
IntentUtils.jumpTo(getActivity(), RealNameAuthActivity.class, false);
}
});
// 审核状态
btnAuditStatus.setOnClickListener(v -> {
if (getActivity() != null) {
IntentUtils.jumpTo(getActivity(), AuditStatusActivity.class, false);
}
});
// 退出登录
btnLogout.setOnClickListener(v -> {
if (getActivity() != null) {
TokenUtils.clearToken(getActivity());
IntentUtils.jumpTo(getActivity(), LoginActivity.class, true);
getActivity().finishAffinity();
}
});
}
}

@ -0,0 +1,22 @@
package com.payment.ui.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.payment.R;
public class TravelCodeFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_travel_code, container, false);
TextView tvTip = view.findViewById(R.id.tv_tip);
tvTip.setText("出行码功能暂未开放,敬请期待");
return view;
}
}

@ -0,0 +1,73 @@
package com.payment.user;
import com.payment.base.BaseActivity;
import com.payment.R;
import com.payment.network.ApiService;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
public class AuditStatusActivity extends BaseActivity {
private TextView tvStatus, tvDesc;
private UserViewModel userViewModel;
@Override
protected int getLayoutId() {
return R.layout.activity_audit_status;
}
@Override
protected void initView() {
tvStatus = findViewById(R.id.tv_status);
tvDesc = findViewById(R.id.tv_desc);
}
@Override
protected void initData() {
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
// 查询审核状态
userViewModel.getAuditStatus();
// 观察审核状态结果
userViewModel.getAuditStatusResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
ApiService.AuditStatusBean statusBean = resultBean.getData();
updateStatusUI(statusBean.getStatus(), statusBean.getDesc());
} else {
showToast("查询审核状态失败");
}
});
}
// 更新审核状态UI
private void updateStatusUI(int status, String desc) {
tvStatus.setText(getStatusText(status));
tvDesc.setText(desc);
// 根据状态设置文字颜色
switch (status) {
case 0: // 未提交
tvStatus.setTextColor(getResources().getColor(R.color.gray));
break;
case 1: // 审核中
tvStatus.setTextColor(getResources().getColor(R.color.blue));
break;
case 2: // 审核通过
tvStatus.setTextColor(getResources().getColor(R.color.green));
break;
case 3: // 驳回
tvStatus.setTextColor(getResources().getColor(R.color.red));
break;
}
}
// 状态文字映射
private String getStatusText(int status) {
switch (status) {
case 0: return "未提交实名认证";
case 1: return "审核中";
case 2: return "审核通过";
case 3: return "审核驳回";
default: return "未知状态";
}
}
}

@ -0,0 +1,87 @@
package com.payment.user;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.payment.R;
import com.payment.network.MockServerManager;
import com.payment.utils.IntentUtils;
import com.payment.utils.TokenUtils;
import com.payment.ui.MainActivity;
public class LoginActivity extends AppCompatActivity {
private EditText etPhone, etPassword;
private Button btnLogin, btnRegister;
private UserViewModel userViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 启动模拟服务器
MockServerManager.startMockServer();
// 初始化视图
initView();
// 初始化ViewModel
initViewModel();
// 绑定点击事件
setClickListeners();
}
private void initView() {
etPhone = findViewById(R.id.et_phone);
etPassword = findViewById(R.id.et_password);
btnLogin = findViewById(R.id.btn_login);
btnRegister = findViewById(R.id.btn_register);
}
private void initViewModel() {
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
// 观察登录结果
userViewModel.getLoginResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
// 保存Token
TokenUtils.saveToken(this, resultBean.getData().getToken());
Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();
// 跳转到主页面
IntentUtils.jumpTo(this, MainActivity.class, true);
} else {
Toast.makeText(this, "登录失败:" + (resultBean != null ? resultBean.getMsg() : "网络异常"), Toast.LENGTH_SHORT).show();
}
});
}
private void setClickListeners() {
// 登录按钮
btnLogin.setOnClickListener(v -> {
String phone = etPhone.getText().toString().trim();
String password = etPassword.getText().toString().trim();
if (phone.isEmpty() || password.isEmpty()) {
Toast.makeText(this, "手机号和密码不能为空", Toast.LENGTH_SHORT).show();
return;
}
// 调用ViewModel登录方法
userViewModel.login(phone, password);
});
// 注册按钮
btnRegister.setOnClickListener(v -> {
IntentUtils.jumpTo(this, RegisterActivity.class, false);
});
}
@Override
protected void onDestroy() {
super.onDestroy();
// 停止模拟服务器可选也可在MainActivity中统一管理
// MockServerManager.stopMockServer();
}
}

@ -0,0 +1,61 @@
package com.payment.user;
import com.payment.base.BaseActivity;
import com.payment.R;
import com.payment.utils.ToastUtils;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class RealNameAuthActivity extends BaseActivity {
private EditText etRealName, etIdCard;
private Button btnSubmit;
private UserViewModel userViewModel;
@Override
protected int getLayoutId() {
return R.layout.activity_real_name_auth;
}
@Override
protected void initView() {
etRealName = findViewById(R.id.et_real_name);
etIdCard = findViewById(R.id.et_id_card);
btnSubmit = findViewById(R.id.btn_submit);
}
@Override
protected void initData() {
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
// 观察实名认证结果
userViewModel.getRealNameResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
showToast(resultBean.getMsg());
finish(); // 返回上一页
} else {
showToast("提交失败:" + (resultBean != null ? resultBean.getMsg() : "网络异常"));
}
});
}
@Override
protected void bindEvent() {
btnSubmit.setOnClickListener(v -> {
String realName = etRealName.getText().toString().trim();
String idCard = etIdCard.getText().toString().trim();
if (realName.isEmpty() || idCard.isEmpty()) {
showToast("请完善实名认证信息");
return;
}
if (idCard.length() != 18) {
showToast("请输入正确的身份证号");
return;
}
// 提交实名认证
userViewModel.submitRealNameAuth(realName, idCard);
});
}
}

@ -0,0 +1,79 @@
package com.payment.user;
import com.payment.base.BaseActivity;
import com.payment.R;
import com.payment.utils.IntentUtils;
import com.payment.utils.ToastUtils;
import androidx.lifecycle.ViewModelProvider;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class RegisterActivity extends BaseActivity {
private EditText etPhone, etVerifyCode, etPassword;
private Button btnGetCode, btnRegister;
private UserViewModel userViewModel;
@Override
protected int getLayoutId() {
return R.layout.activity_register;
}
@Override
protected void initView() {
etPhone = findViewById(R.id.et_phone);
etVerifyCode = findViewById(R.id.et_verify_code);
etPassword = findViewById(R.id.et_password);
btnGetCode = findViewById(R.id.btn_get_code);
btnRegister = findViewById(R.id.btn_register);
}
@Override
protected void initData() {
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
// 观察注册结果
userViewModel.getRegisterResult().observe(this, resultBean -> {
if (resultBean != null && resultBean.isSuccess()) {
ToastUtils.showToast(this, "注册成功,请登录");
IntentUtils.jumpTo(this, LoginActivity.class, true);
} else {
ToastUtils.showToast(this, "注册失败:" + (resultBean != null ? resultBean.getMsg() : "网络异常"));
}
});
}
@Override
protected void bindEvent() {
// 获取验证码(模拟,无需真实校验)
btnGetCode.setOnClickListener(v -> {
String phone = etPhone.getText().toString().trim();
if (phone.isEmpty()) {
showToast("请输入手机号");
return;
}
showToast("验证码已发送至:" + phone);
// 模拟倒计时60秒
btnGetCode.setEnabled(false);
new android.os.Handler().postDelayed(() -> btnGetCode.setEnabled(true), 60000);
});
// 注册按钮
btnRegister.setOnClickListener(v -> {
String phone = etPhone.getText().toString().trim();
String verifyCode = etVerifyCode.getText().toString().trim();
String password = etPassword.getText().toString().trim();
if (phone.isEmpty() || verifyCode.isEmpty() || password.isEmpty()) {
showToast("请完善所有信息");
return;
}
if (password.length() < 6) {
showToast("密码长度不能少于6位");
return;
}
// 调用注册接口
userViewModel.register(phone, verifyCode, password);
});
}
}

@ -0,0 +1,186 @@
package com.payment.user;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.payment.MyApplication;
import com.payment.network.ApiService;
import com.payment.network.RetrofitManager;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* ViewModel
*/
public class UserViewModel extends ViewModel {
// ========== 登录相关 ==========
private MutableLiveData<ApiService.ResultBean<ApiService.UserBean>> loginResult = new MutableLiveData<>();
public LiveData<ApiService.ResultBean<ApiService.UserBean>> getLoginResult() {
return loginResult;
}
public void login(String phone, String password) {
ApiService apiService = RetrofitManager.getApiService(MyApplication.getContext());
ApiService.LoginRequest request = new ApiService.LoginRequest(phone, password);
apiService.login(request).enqueue(new Callback<ApiService.ResultBean<ApiService.UserBean>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.UserBean>> call, Response<ApiService.ResultBean<ApiService.UserBean>> response) {
if (response.isSuccessful() && response.body() != null) {
loginResult.postValue(response.body());
} else {
ApiService.ResultBean<ApiService.UserBean> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("登录失败:" + (response.message() != null ? response.message() : "服务器错误"));
loginResult.postValue(errorResult);
}
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.UserBean>> call, Throwable t) {
ApiService.ResultBean<ApiService.UserBean> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("网络错误:" + t.getMessage());
loginResult.postValue(errorResult);
}
});
}
// ========== 注册相关 ==========
private MutableLiveData<ApiService.ResultBean<ApiService.BaseResponse>> registerResult = new MutableLiveData<>();
public LiveData<ApiService.ResultBean<ApiService.BaseResponse>> getRegisterResult() {
return registerResult;
}
public void register(String phone, String verifyCode, String password) {
ApiService apiService = RetrofitManager.getApiService(MyApplication.getContext());
ApiService.RegisterRequest request = new ApiService.RegisterRequest(phone, verifyCode, password);
apiService.register(request).enqueue(new Callback<ApiService.ResultBean<ApiService.BaseResponse>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Response<ApiService.ResultBean<ApiService.BaseResponse>> response) {
if (response.isSuccessful() && response.body() != null) {
registerResult.postValue(response.body());
} else {
ApiService.ResultBean<ApiService.BaseResponse> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("注册失败:" + response.message());
registerResult.postValue(errorResult);
}
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Throwable t) {
ApiService.ResultBean<ApiService.BaseResponse> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("网络错误:" + t.getMessage());
registerResult.postValue(errorResult);
}
});
}
// ========== 实名认证相关 ==========
private MutableLiveData<ApiService.ResultBean<ApiService.BaseResponse>> realNameResult = new MutableLiveData<>();
public LiveData<ApiService.ResultBean<ApiService.BaseResponse>> getRealNameResult() {
return realNameResult;
}
public void submitRealNameAuth(String realName, String idCard) {
ApiService apiService = RetrofitManager.getApiService(MyApplication.getContext());
ApiService.RealNameAuthRequest request = new ApiService.RealNameAuthRequest(realName, idCard);
apiService.submitRealNameAuth(request).enqueue(new Callback<ApiService.ResultBean<ApiService.BaseResponse>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Response<ApiService.ResultBean<ApiService.BaseResponse>> response) {
if (response.isSuccessful() && response.body() != null) {
realNameResult.postValue(response.body());
} else {
ApiService.ResultBean<ApiService.BaseResponse> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("提交失败:" + (response.message() != null ? response.message() : "服务器错误"));
realNameResult.postValue(errorResult);
}
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.BaseResponse>> call, Throwable t) {
ApiService.ResultBean<ApiService.BaseResponse> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("网络错误:" + t.getMessage());
realNameResult.postValue(errorResult);
}
});
}
// ========== 审核状态查询相关 ==========
private MutableLiveData<ApiService.ResultBean<ApiService.AuditStatusBean>> auditStatusResult = new MutableLiveData<>();
public LiveData<ApiService.ResultBean<ApiService.AuditStatusBean>> getAuditStatusResult() {
return auditStatusResult;
}
public void getAuditStatus() {
ApiService apiService = RetrofitManager.getApiService(MyApplication.getContext());
apiService.getAuditStatus().enqueue(new Callback<ApiService.ResultBean<ApiService.AuditStatusBean>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.AuditStatusBean>> call, Response<ApiService.ResultBean<ApiService.AuditStatusBean>> response) {
if (response.isSuccessful() && response.body() != null) {
auditStatusResult.postValue(response.body());
} else {
ApiService.ResultBean<ApiService.AuditStatusBean> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("查询失败:" + response.message());
auditStatusResult.postValue(errorResult);
}
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.AuditStatusBean>> call, Throwable t) {
ApiService.ResultBean<ApiService.AuditStatusBean> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("网络错误:" + t.getMessage());
auditStatusResult.postValue(errorResult);
}
});
}
// ========== 用户信息查询相关 ==========
private MutableLiveData<ApiService.ResultBean<ApiService.UserBean>> userInfoResult = new MutableLiveData<>();
public LiveData<ApiService.ResultBean<ApiService.UserBean>> getUserInfoResult() {
return userInfoResult;
}
public void getUserInfo() {
ApiService apiService = RetrofitManager.getApiService(MyApplication.getContext());
apiService.getUserInfo().enqueue(new Callback<ApiService.ResultBean<ApiService.UserBean>>() {
@Override
public void onResponse(Call<ApiService.ResultBean<ApiService.UserBean>> call, Response<ApiService.ResultBean<ApiService.UserBean>> response) {
if (response.isSuccessful() && response.body() != null) {
userInfoResult.postValue(response.body());
} else {
ApiService.ResultBean<ApiService.UserBean> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("获取用户信息失败:" + response.message());
userInfoResult.postValue(errorResult);
}
}
@Override
public void onFailure(Call<ApiService.ResultBean<ApiService.UserBean>> call, Throwable t) {
ApiService.ResultBean<ApiService.UserBean> errorResult = new ApiService.ResultBean<>();
errorResult.setSuccess(false);
errorResult.setMsg("网络错误:" + t.getMessage());
userInfoResult.postValue(errorResult);
}
});
}
}

@ -0,0 +1,38 @@
package com.payment.utils;
import android.content.Context;
import android.content.Intent;
public class IntentUtils {
/**
*
* @param context
* @param targetClass Activity
* @param isFinish Activity
*/
public static void jumpTo(Context context, Class<?> targetClass, boolean isFinish) {
Intent intent = new Intent(context, targetClass);
context.startActivity(intent);
if (isFinish && context instanceof android.app.Activity) {
((android.app.Activity) context).finish();
}
}
/**
*
* @param context
* @param targetClass Activity
* @param bundle
* @param isFinish Activity
*/
public static void jumpToWithBundle(Context context, Class<?> targetClass, android.os.Bundle bundle, boolean isFinish) {
Intent intent = new Intent(context, targetClass);
if (bundle != null) {
intent.putExtras(bundle);
}
context.startActivity(intent);
if (isFinish && context instanceof android.app.Activity) {
((android.app.Activity) context).finish();
}
}
}

@ -0,0 +1,30 @@
package com.payment.utils;
import android.content.Context;
import android.widget.Toast;
public class ToastUtils {
private static Toast toast;
// 显示短吐司
public static void showToast(Context context, String msg) {
if (toast == null) {
toast = Toast.makeText(context.getApplicationContext(), msg, Toast.LENGTH_SHORT);
} else {
toast.setText(msg);
toast.setDuration(Toast.LENGTH_SHORT);
}
toast.show();
}
// 显示长吐司
public static void showLongToast(Context context, String msg) {
if (toast == null) {
toast = Toast.makeText(context.getApplicationContext(), msg, Toast.LENGTH_LONG);
} else {
toast.setText(msg);
toast.setDuration(Toast.LENGTH_LONG);
}
toast.show();
}
}

@ -0,0 +1,32 @@
package com.payment.utils;
import android.content.Context;
import android.content.SharedPreferences;
public class TokenUtils {
private static final String SP_NAME = "payment_token";
private static final String KEY_TOKEN = "token";
// 保存Token
public static void saveToken(Context context, String token) {
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().putString(KEY_TOKEN, token).apply();
}
// 获取Token
public static String getToken(Context context) {
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
return sp.getString(KEY_TOKEN, "");
}
// 清除Token退出登录
public static void clearToken(Context context) {
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
sp.edit().remove(KEY_TOKEN).apply();
}
// 判断Token是否存在登录状态
public static boolean isLogin(Context context) {
return !getToken(context).isEmpty();
}
}

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="@android:anim/accelerate_interpolator"/>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="200"
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:interpolator="@android:anim/decelerate_interpolator"/>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M19,3H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2zm-2,5h-1.42v1.5h1.71v1.22h-1.71v1.28h1.42V14h-1.71v1.5h1.71v1.22h-1.71v1.28h1.71V20H7v-1.5h1.71v-1.22H7v-1.28h1.71V14H7v-1.5h1.71v-1.22H7V8h10v1.5H9.29v1.22h1.71V11h-1.71v1.28h1.71V14H9.29v1.5h1.71v1.22H9.29v1.28h1.71V20h1.71v-1.5h-1.71v-1.22h1.71v-1.28h-1.71V14h1.71v-1.5h-1.71v-1.22h1.71V8h1.71V6.5h-1.71V5.28h1.71V4h1.71V5.28h-1.71V6.5h1.71V8z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M11,17h2v-6h-2v6zm1,-15C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M20,4H4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2V6c0,-1.11 -0.89,-2 -2,-2zM4,9h10.5v3.5H4V9zm0,5h10.5v3.5H4V14zm16,5h-2.5V9H20v10z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/gray"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/red"
android:pathData="M17,7l-1.41,1.41L18.17,11H8v2h10.17l-2.58,2.58L17,17l5,-5zM4,5h8V3H4C2.9,3 2,3.9 2,5v14c0,1.1 0.9,2 2,2h8v-2H4V5z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/gray"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zm0,2c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zm0,2c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zm0,2c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M11,17h2v-6h-2v6zm1,-15C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,18c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/gray"
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM9,9c0,-1.66 1.34,-3 3,-3s3,1.34 3,3 -1.34,3 -3,3 -3,-1.34 -3,-3z"/> <!-- 与选中状态路径一致 -->
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM9,9c0,-1.66 1.34,-3 3,-3s3,1.34 3,3 -1.34,3 -3,3 -3,-1.34 -3,-3z"/> <!-- 出行码相关图标路径 -->
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="80dp"
android:height="80dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/white"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zm0,2c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/blue_primary"
android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zm5.3,-3c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12H5c0,3.42 2.72,6.23 6,6.72V22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>
</vector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list android:layout_width="match_parent">
<item android:drawable="@android:drawable/ic_menu_view"/>
<item android:gravity="bottom|center" android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="@color/blue_primary"/>
<size android:height="2dp" android:width="20dp"/>
</shape>
</item>
</layer-list>
</item>
<item android:drawable="@android:drawable/ic_menu_agenda"/>
</selector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list>
<item android:drawable="@drawable/ic_home_selected"/>
<item android:gravity="bottom|center" android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="@color/blue_primary"/>
<size android:height="2dp" android:width="20dp"/>
</shape>
</item>
</layer-list>
</item>
<item android:drawable="@drawable/ic_home_normal"/>
</selector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list>
<item android:drawable="@drawable/ic_mine_selected"/>
<item android:gravity="bottom|center" android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="@color/blue_primary"/>
<size android:height="2dp" android:width="20dp"/>
</shape>
</item>
</layer-list>
</item>
<item android:drawable="@drawable/ic_mine_normal"/>
</selector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<layer-list>
<item android:drawable="@drawable/ic_travel_selected"/>
<item android:gravity="bottom|center" android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="@color/blue_primary"/>
<size android:height="2dp" android:width="20dp"/>
</shape>
</item>
</layer-list>
</item>
<item android:drawable="@drawable/ic_travel_normal"/>
</selector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<shape android:shape="rectangle">
<solid android:color="@color/blue_primary"/>
<corners android:topLeftRadius="8dp" android:bottomLeftRadius="8dp"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/gray_light"/>
<corners android:topLeftRadius="8dp" android:bottomLeftRadius="8dp"/>
</shape>
</item>
</selector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<shape android:shape="rectangle">
<solid android:color="@color/blue_primary"/>
<corners android:topRightRadius="8dp" android:bottomRightRadius="8dp"/>
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@color/gray_light"/>
<corners android:topRightRadius="8dp" android:bottomRightRadius="8dp"/>
</shape>
</item>
</selector>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<corners android:radius="12dp"/>
<elevation android:elevation="4dp"/>
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp"/>
</shape>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/gray_light"/>
<size
android:width="80dp"
android:height="80dp"/>
</shape>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white"/>
<corners android:radius="8dp"/>
<stroke
android:width="1dp"
android:color="@color/gray_light"/>
</shape>

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加银行卡"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginTop="50dp"/>
<EditText
android:id="@+id/et_card_no"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入银行卡号"
android:inputType="number"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="30dp"/>
<EditText
android:id="@+id/et_bank_name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入银行名称"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="15dp"/>
<Button
android:id="@+id/btn_submit"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="确认添加"
android:textSize="18sp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginTop="40dp"
android:radius="8dp"/>
</LinearLayout>

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="实名认证审核状态"
android:textSize="22sp"
android:textStyle="bold"
android:layout_marginTop="80dp"/>
<TextView
android:id="@+id/tv_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="审核中"
android:textSize="30sp"
android:textStyle="bold"
android:layout_marginTop="50dp"
android:textColor="@color/blue_primary"/>
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="提交成功,工作人员正在审核中,请耐心等待"
android:textSize="18sp"
android:layout_marginTop="20dp"
android:textColor="@color/gray"
android:gravity="center"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="返回"
android:layout_marginTop="50dp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:paddingHorizontal="30dp"
android:paddingVertical="10dp"
android:radius="8dp"
android:onClick="finish"/>
</LinearLayout>

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的余额"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginTop="50dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_marginTop="50dp">
<TextView
android:id="@+id/tv_balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0.00 元"
android:textSize="48sp"
android:textStyle="bold"
android:textColor="@color/blue_primary"/>
<TextView
android:id="@+id/tv_update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="最后更新:未知"
android:textSize="14sp"
android:textColor="@color/gray"
android:layout_marginTop="10dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="80dp">
<Button
android:id="@+id/btn_recharge"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="充值"
android:textSize="18sp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:radius="8dp"/>
<Button
android:id="@+id/btn_withdraw"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="提现"
android:textSize="18sp"
android:backgroundTint="@color/gray"
android:textColor="@color/white"
android:layout_marginStart="20dp"
android:radius="8dp"/>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="银行卡管理"
android:textSize="24sp"
android:textStyle="bold"/>
<Button
android:id="@+id/btn_add_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加银行卡"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginStart="16dp"
android:paddingHorizontal="15dp"
android:paddingVertical="5dp"
android:radius="4dp"/>
</LinearLayout>
<!-- 银行卡列表 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_bank_cards"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="20dp"/>
<!-- 空数据提示 -->
<TextView
android:id="@+id/tv_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂无绑定银行卡,点击添加"
android:textSize="18sp"
android:textColor="@color/gray"
android:layout_gravity="center"
android:visibility="gone"/>
</LinearLayout>

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="移动支付平台"
android:textSize="28sp"
android:textStyle="bold"
android:layout_marginTop="100dp"
android:layout_gravity="center"/>
<EditText
android:id="@+id/et_phone"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入手机号"
android:inputType="phone"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="80dp"/>
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入密码"
android:inputType="textPassword"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="15dp"/>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="登录"
android:textSize="18sp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginTop="40dp"
android:radius="8dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginTop="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="还没有账号?"/>
<Button
android:id="@+id/btn_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="立即注册"
android:textColor="@color/blue_primary"
android:background="@null"/>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- 内容容器(碎片展示区域) -->
<FrameLayout
android:id="@+id/fl_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<!-- 底部导航栏 -->
<RadioGroup
android:id="@+id/rg_bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@color/white"
android:paddingVertical="8dp">
<!-- 首页 -->
<RadioButton
android:id="@+id/rb_home"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:gravity="center"
android:text="首页"
android:textSize="14sp"
android:drawableTop="@drawable/selector_nav_home"/>
<!-- 出行码 -->
<RadioButton
android:id="@+id/rb_travel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:gravity="center"
android:text="出行码"
android:textSize="14sp"
android:drawableTop="@drawable/selector_nav_travel"/>
<!-- 账单 -->
<RadioButton
android:id="@+id/rb_bill"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:gravity="center"
android:text="账单"
android:textSize="14sp"
android:drawableTop="@drawable/selector_nav_bill"/>
<!-- 我的 -->
<RadioButton
android:id="@+id/rb_mine"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:button="@null"
android:gravity="center"
android:text="我的"
android:textSize="14sp"
android:drawableTop="@drawable/selector_nav_mine"/>
</RadioGroup>
</LinearLayout>

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="实名认证"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginTop="50dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="完成实名认证后可解锁全部功能"
android:textSize="14sp"
android:textColor="@color/gray"
android:layout_marginTop="10dp"/>
<EditText
android:id="@+id/et_real_name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入真实姓名"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="30dp"/>
<EditText
android:id="@+id/et_id_card"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入身份证号"
android:inputType="number"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="15dp"/>
<Button
android:id="@+id/btn_submit"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="提交认证"
android:textSize="18sp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginTop="40dp"
android:radius="8dp"/>
</LinearLayout>

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<!-- 充值/提现切换 -->
<RadioGroup
android:id="@+id/rg_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="50dp">
<RadioButton
android:id="@+id/rb_recharge"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="充值"
android:textSize="18sp"
android:button="@null"
android:gravity="center"
android:background="@drawable/selector_radio_recharge"
android:textColor="@color/white"
android:checked="true"/>
<RadioButton
android:id="@+id/rb_withdraw"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:text="提现"
android:textSize="18sp"
android:button="@null"
android:gravity="center"
android:background="@drawable/selector_radio_withdraw"
android:textColor="@color/gray"/>
</RadioGroup>
<EditText
android:id="@+id/et_amount"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入金额"
android:inputType="numberDecimal"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="30dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择支付/提现银行卡"
android:textSize="16sp"
android:layout_marginTop="20dp"/>
<!-- 银行卡下拉选择 -->
<Spinner
android:id="@+id/sp_bank_cards"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="10dp"/>
<Button
android:id="@+id/btn_confirm"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="确认充值"
android:textSize="18sp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginTop="40dp"
android:radius="8dp"/>
</LinearLayout>

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户注册"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginTop="80dp"/>
<EditText
android:id="@+id/et_phone"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请输入手机号"
android:inputType="phone"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="40dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
android:layout_marginTop="15dp">
<EditText
android:id="@+id/et_verify_code"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:hint="请输入验证码"
android:inputType="number"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"/>
<Button
android:id="@+id/btn_get_code"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="获取验证码"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginStart="10dp"
android:radius="8dp"/>
</LinearLayout>
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="请设置密码不少于6位"
android:inputType="textPassword"
android:background="@drawable/shape_edittext"
android:paddingHorizontal="15dp"
android:layout_marginTop="15dp"/>
<Button
android:id="@+id/btn_register"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="完成注册"
android:textSize="18sp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginTop="40dp"
android:radius="8dp"/>
</LinearLayout>

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@color/gray_f5">
<TextView
android:id="@+id/tv_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="账单功能暂未开放"
android:textSize="20sp"
android:textColor="@color/gray"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="刷新账单"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginTop="20dp"
android:paddingHorizontal="30dp"
android:paddingVertical="10dp"
android:radius="8dp"/>
</LinearLayout>

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="资产中心"
android:textSize="22sp"
android:textStyle="bold"
android:layout_marginTop="30dp"/>
<!-- 功能按钮区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="40dp">
<Button
android:id="@+id/btn_balance"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="查询余额"
android:textSize="18sp"
android:backgroundTint="@color/white"
android:textColor="@color/black"
android:gravity="center"
android:layout_marginBottom="15dp"
android:drawableStart="@drawable/ic_balance"
android:drawablePadding="15dp"/>
<Button
android:id="@+id/btn_bank_card"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="银行卡管理"
android:textSize="18sp"
android:backgroundTint="@color/white"
android:textColor="@color/black"
android:gravity="center"
android:layout_marginBottom="15dp"
android:drawableStart="@drawable/ic_bank_card"
android:drawablePadding="15dp"/>
<Button
android:id="@+id/btn_recharge"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="充值"
android:textSize="18sp"
android:backgroundTint="@color/white"
android:textColor="@color/black"
android:gravity="center"
android:layout_marginBottom="15dp"
android:drawableStart="@drawable/ic_recharge"
android:drawablePadding="15dp"/>
<Button
android:id="@+id/btn_withdraw"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="提现"
android:textSize="18sp"
android:backgroundTint="@color/white"
android:textColor="@color/black"
android:gravity="center"
android:drawableStart="@drawable/ic_withdraw"
android:drawablePadding="15dp"/>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
android:background="@color/gray_f5">
<!-- 用户信息区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="30dp">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/ic_user_avatar"
android:background="@drawable/shape_circle"
android:scaleType="centerCrop"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="15dp">
<TextView
android:id="@+id/tv_user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="未登录"
android:textSize="20sp"
android:textStyle="bold"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击实名认证解锁全部功能"
android:textSize="14sp"
android:textColor="@color/gray"
android:layout_marginTop="5dp"/>
</LinearLayout>
</LinearLayout>
<!-- 功能按钮区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="40dp">
<Button
android:id="@+id/btn_real_name"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="实名认证"
android:textSize="18sp"
android:backgroundTint="@color/white"
android:textColor="@color/black"
android:gravity="center_vertical"
android:layout_marginBottom="15dp"
android:drawableStart="@drawable/ic_real_name"
android:drawablePadding="15dp"
android:paddingHorizontal="15dp"/>
<Button
android:id="@+id/btn_audit_status"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="审核状态查询"
android:textSize="18sp"
android:backgroundTint="@color/white"
android:textColor="@color/black"
android:gravity="center_vertical"
android:layout_marginBottom="15dp"
android:drawableStart="@drawable/ic_audit"
android:drawablePadding="15dp"
android:paddingHorizontal="15dp"/>
<Button
android:id="@+id/btn_logout"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="退出登录"
android:textSize="18sp"
android:backgroundTint="@color/white"
android:textColor="@color/red"
android:gravity="center_vertical"
android:drawableStart="@drawable/ic_logout"
android:drawablePadding="15dp"
android:paddingHorizontal="15dp"/>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@color/gray_f5">
<TextView
android:id="@+id/tv_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="出行码功能暂未开放"
android:textSize="20sp"
android:textColor="@color/gray"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开通出行码"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginTop="20dp"
android:paddingHorizontal="30dp"
android:paddingVertical="10dp"
android:radius="8dp"/>
</LinearLayout>

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="15dp"
android:background="@drawable/shape_card_bg"
android:layout_margin="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_bank_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="中国工商银行"
android:textSize="18sp"
android:textStyle="bold"/>
<ImageView
android:id="@+id/iv_default"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_default"
android:visibility="gone"
android:layout_marginStart="10dp"/>
</LinearLayout>
<TextView
android:id="@+id/tv_card_no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="6222 02**** 1234"
android:layout_marginTop="5dp"
android:textSize="16sp"
android:textColor="@color/gray"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<Button
android:id="@+id/btn_set_default"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="设为默认"
android:textSize="14sp"
android:backgroundTint="@color/blue_primary"
android:textColor="@color/white"
android:layout_marginEnd="10dp"
android:paddingHorizontal="15dp"
android:radius="4dp"/>
<Button
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="删除"
android:textSize="14sp"
android:backgroundTint="@color/red"
android:textColor="@color/white"
android:paddingHorizontal="15dp"
android:radius="4dp"/>
</LinearLayout>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 主色调 -->
<color name="blue_primary">#2196F3</color>
<color name="blue_primary_dark">#1976D2</color>
<color name="blue_accent">#64B5F6</color>
<!-- 基础色 -->
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
<color name="gray">#9E9E9E</color>
<color name="gray_light">#E0E0E0</color>
<color name="gray_f5">#F5F5F5</color>
<color name="gray_ee">#EEEEEE</color>
<color name="blue">@color/blue_primary</color> <!-- 新增别名 -->
<!-- 功能色 -->
<color name="red">#F44336</color>
<color name="green">#4CAF50</color>
<color name="yellow">#FFC107</color>
</resources>

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 应用名称 -->
<string name="app_name">移动支付平台</string>
<!-- 登录/注册 -->
<string name="login">登录</string>
<string name="register">注册</string>
<string name="phone">手机号</string>
<string name="password">密码</string>
<string name="verify_code">验证码</string>
<string name="get_code">获取验证码</string>
<string name="no_account">还没有账号?</string>
<!-- 实名认证 -->
<string name="real_name_auth">实名认证</string>
<string name="real_name">真实姓名</string>
<string name="id_card">身份证号</string>
<string name="submit_auth">提交认证</string>
<string name="audit_status">审核状态</string>
<string name="audit_ing">审核中</string>
<string name="audit_pass">审核通过</string>
<string name="audit_reject">审核驳回</string>
<!-- 资产管理 -->
<string name="asset_center">资产中心</string>
<string name="balance">余额</string>
<string name="bank_card_manage">银行卡管理</string>
<string name="add_bank_card">添加银行卡</string>
<string name="card_no">银行卡号</string>
<string name="bank_name">银行名称</string>
<string name="set_default">设为默认</string>
<string name="delete">删除</string>
<string name="recharge">充值</string>
<string name="withdraw">提现</string>
<string name="amount">金额</string>
<string name="select_card">选择银行卡</string>
<string name="confirm">确认</string>
<!-- 底部导航 -->
<string name="home">首页</string>
<string name="travel_code">出行码</string>
<string name="bill">账单</string>
<string name="mine">我的</string>
<!-- 提示语 -->
<string name="input_phone">请输入手机号</string>
<string name="input_password">请输入密码</string>
<string name="input_verify_code">请输入验证码</string>
<string name="input_real_name">请输入真实姓名</string>
<string name="input_id_card">请输入身份证号</string>
<string name="input_card_no">请输入银行卡号</string>
<string name="input_bank_name">请输入银行名称</string>
<string name="input_amount">请输入金额</string>
<string name="empty_card_list">暂无绑定银行卡,点击添加</string>
<string name="function_not_open">功能暂未开放,敬请期待</string>
<!-- 错误提示 -->
<string name="phone_empty">手机号不能为空</string>
<string name="password_empty">密码不能为空</string>
<string name="code_empty">验证码不能为空</string>
<string name="name_empty">真实姓名不能为空</string>
<string name="id_card_empty">身份证号不能为空</string>
<string name="card_no_empty">银行卡号不能为空</string>
<string name="bank_name_empty">银行名称不能为空</string>
<string name="amount_empty">金额不能为空</string>
<string name="amount_invalid">金额必须大于0</string>
<string name="id_card_invalid">请输入正确的身份证号</string>
<string name="card_no_invalid">请输入正确的银行卡号</string>
<string name="password_short">密码长度不能少于6位</string>
<!-- 成功提示 -->
<string name="login_success">登录成功</string>
<string name="register_success">注册成功</string>
<string name="auth_submit_success">实名认证提交成功,请等待审核</string>
<string name="card_add_success">银行卡添加成功</string>
<string name="card_default_success">默认银行卡设置成功</string>
<string name="card_delete_success">银行卡删除成功</string>
<string name="recharge_success">充值成功</string>
<string name="withdraw_success">提现申请提交成功</string>
<!-- 失败提示 -->
<string name="login_fail">登录失败</string>
<string name="register_fail">注册失败</string>
<string name="network_error">网络请求失败</string>
<string name="auth_submit_fail">实名认证提交失败</string>
<string name="card_add_fail">银行卡添加失败</string>
<string name="card_default_fail">默认银行卡设置失败</string>
<string name="card_delete_fail">银行卡删除失败</string>
<string name="recharge_fail">充值失败</string>
<string name="withdraw_fail">提现失败</string>
</resources>

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 基础应用主题 -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/blue_primary</item>
<item name="colorPrimaryDark">@color/blue_primary_dark</item>
<item name="colorAccent">@color/blue_accent</item>
<item name="android:windowBackground">@color/gray_f5</item>
</style>
<!-- 输入框样式 -->
<style name="EditTextStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">50dp</item>
<item name="android:background">@drawable/shape_edittext</item>
<item name="android:paddingHorizontal">15dp</item>
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/black</item>
<item name="android:textColorHint">@color/gray</item>
</style>
<!-- 按钮样式 -->
<style name="ButtonStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">50dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">@color/white</item>
<item name="android:backgroundTint">@color/blue_primary</item>
<item name="android:radius">8dp</item>
</style>
<!-- 卡片按钮样式 -->
<style name="CardButtonStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">60dp</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">@color/black</item>
<item name="android:backgroundTint">@color/white</item>
<item name="android:gravity">center_vertical</item>
<item name="android:paddingHorizontal">15dp</item>
<item name="android:drawablePadding">15dp</item>
</style>
<!-- 底部导航按钮样式 -->
<style name="BottomNavButtonStyle">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:button">@null</item>
<item name="android:gravity">center</item>
<item name="android:textSize">14sp</item>
<item name="android:drawableTop">@drawable/selector_nav_home</item>
</style>
</resources>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.MobilePaymentApp" parent="Theme.AppCompat.Light.NoActionBar">
</style>
</resources>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older than API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>
Loading…
Cancel
Save