9 changed files with 1154 additions and 19 deletions
-
6app/src/main/AndroidManifest.xml
-
51app/src/main/java/com/ouxuan/oxface/OXFaceOnlineActivity.java
-
31app/src/main/java/com/ouxuan/oxface/network/OrderVerificationResultHandler.java
-
267app/src/main/java/com/ouxuan/oxface/orderOX/OrderSelectionActivity.java
-
127app/src/main/java/com/ouxuan/oxface/orderOX/adapter/OrderSelectionAdapter.java
-
245app/src/main/java/com/ouxuan/oxface/orderOX/model/OrderVerificationData.java
-
147app/src/main/res/layout/activity_order_selection.xml
-
126app/src/main/res/layout/item_order_selection.xml
-
173订单核销选择页面实现说明.md
@ -0,0 +1,267 @@ |
|||||
|
package com.ouxuan.oxface.orderOX; |
||||
|
|
||||
|
import android.content.Intent; |
||||
|
import android.os.Bundle; |
||||
|
import android.os.Handler; |
||||
|
import android.view.View; |
||||
|
import android.view.Window; |
||||
|
import android.view.WindowManager; |
||||
|
import android.widget.Button; |
||||
|
import android.widget.TextView; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import androidx.appcompat.app.AppCompatActivity; |
||||
|
import androidx.recyclerview.widget.LinearLayoutManager; |
||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||
|
|
||||
|
import com.google.gson.Gson; |
||||
|
import com.ouxuan.oxface.R; |
||||
|
import com.ouxuan.oxface.orderOX.adapter.OrderSelectionAdapter; |
||||
|
import com.ouxuan.oxface.orderOX.model.OrderVerificationData; |
||||
|
import com.ouxuan.oxface.utils.LogManager; |
||||
|
|
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.util.Date; |
||||
|
import java.util.List; |
||||
|
import java.util.Locale; |
||||
|
|
||||
|
/** |
||||
|
* 订单核销选择页面 |
||||
|
* 用于显示人脸验证后返回的订单列表,供用户选择要核销的订单 |
||||
|
*/ |
||||
|
public class OrderSelectionActivity extends AppCompatActivity { |
||||
|
|
||||
|
private static final String TAG = "OrderSelectionActivity"; |
||||
|
public static final String EXTRA_ORDER_DATA = "order_data"; |
||||
|
public static final String EXTRA_VERIFICATION_TYPE = "verification_type"; |
||||
|
public static final String EXTRA_FACE_BASE64 = "face_base64"; |
||||
|
|
||||
|
private RecyclerView rvOrderList; |
||||
|
private Button btnConfirm, btnCancel; |
||||
|
private TextView tvBackHome, tvStoreName, tvVerificationDate; |
||||
|
|
||||
|
private OrderSelectionAdapter adapter; |
||||
|
private List<OrderVerificationData.OrderItem> orderList; |
||||
|
private int verificationType; |
||||
|
private String faceBase64; |
||||
|
private Handler countdownHandler; |
||||
|
private int countdown = 6; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
|
||||
|
// 设置无标题栏 |
||||
|
requestWindowFeature(Window.FEATURE_NO_TITLE); |
||||
|
|
||||
|
// 设置背景透明,实现弹窗效果 |
||||
|
getWindow().setBackgroundDrawableResource(android.R.color.transparent); |
||||
|
|
||||
|
setContentView(R.layout.activity_order_selection); |
||||
|
|
||||
|
// 设置窗口属性 |
||||
|
Window window = getWindow(); |
||||
|
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); |
||||
|
window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); |
||||
|
|
||||
|
initViews(); |
||||
|
initData(); |
||||
|
setupListeners(); |
||||
|
startCountdown(); |
||||
|
|
||||
|
LogManager.logInfo(TAG, "订单选择页面启动成功"); |
||||
|
} |
||||
|
|
||||
|
private void initViews() { |
||||
|
rvOrderList = findViewById(R.id.rv_order_list); |
||||
|
btnConfirm = findViewById(R.id.btn_confirm); |
||||
|
btnCancel = findViewById(R.id.btn_cancel); |
||||
|
tvBackHome = findViewById(R.id.tv_back_home); |
||||
|
tvStoreName = findViewById(R.id.tv_store_name); |
||||
|
tvVerificationDate = findViewById(R.id.tv_verification_date); |
||||
|
|
||||
|
// 设置当前日期 |
||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); |
||||
|
String currentDate = sdf.format(new Date()); |
||||
|
tvVerificationDate.setText("核销日期:" + currentDate); |
||||
|
|
||||
|
// 设置RecyclerView |
||||
|
rvOrderList.setLayoutManager(new LinearLayoutManager(this)); |
||||
|
} |
||||
|
|
||||
|
private void initData() { |
||||
|
// 获取传入的数据 |
||||
|
Intent intent = getIntent(); |
||||
|
String orderDataJson = intent.getStringExtra(EXTRA_ORDER_DATA); |
||||
|
verificationType = intent.getIntExtra(EXTRA_VERIFICATION_TYPE, 2); |
||||
|
faceBase64 = intent.getStringExtra(EXTRA_FACE_BASE64); |
||||
|
|
||||
|
if (orderDataJson != null) { |
||||
|
try { |
||||
|
// 解析JSON数据 |
||||
|
Gson gson = new Gson(); |
||||
|
OrderVerificationData orderData = gson.fromJson(orderDataJson, OrderVerificationData.class); |
||||
|
|
||||
|
if (orderData != null && orderData.getData() != null && orderData.getData().getResult() != null) { |
||||
|
orderList = orderData.getData().getResult(); |
||||
|
|
||||
|
// 设置适配器 |
||||
|
adapter = new OrderSelectionAdapter(orderList); |
||||
|
rvOrderList.setAdapter(adapter); |
||||
|
|
||||
|
// 设置点击监听 |
||||
|
adapter.setOnOrderClickListener(new OrderSelectionAdapter.OnOrderClickListener() { |
||||
|
@Override |
||||
|
public void onOrderClick(OrderVerificationData.OrderItem order, int position) { |
||||
|
LogManager.logInfo(TAG, "选择订单: " + order.getOrder_no()); |
||||
|
// 更新确认按钮状态 |
||||
|
btnConfirm.setEnabled(true); |
||||
|
btnConfirm.setAlpha(1.0f); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onVerifyClick(OrderVerificationData.OrderItem order, int position) { |
||||
|
// 直接核销选中的订单 |
||||
|
performOrderVerification(order); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
LogManager.logInfo(TAG, "成功加载" + orderList.size() + "个订单"); |
||||
|
} else { |
||||
|
LogManager.logWarning(TAG, "订单数据为空"); |
||||
|
showToast("未找到可核销的订单"); |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
LogManager.logError(TAG, "解析订单数据失败", e); |
||||
|
showToast("订单数据解析失败"); |
||||
|
} |
||||
|
} else { |
||||
|
LogManager.logError(TAG, "未接收到订单数据"); |
||||
|
showToast("未接收到订单数据"); |
||||
|
} |
||||
|
|
||||
|
// 初始状态下确认按钮不可用 |
||||
|
btnConfirm.setEnabled(false); |
||||
|
btnConfirm.setAlpha(0.5f); |
||||
|
} |
||||
|
|
||||
|
private void setupListeners() { |
||||
|
// 确认按钮 |
||||
|
btnConfirm.setOnClickListener(v -> { |
||||
|
OrderVerificationData.OrderItem selectedOrder = adapter.getSelectedOrder(); |
||||
|
if (selectedOrder != null) { |
||||
|
performOrderVerification(selectedOrder); |
||||
|
} else { |
||||
|
showToast("请选择要核销的订单"); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// 取消按钮 |
||||
|
btnCancel.setOnClickListener(v -> { |
||||
|
LogManager.logInfo(TAG, "用户取消选择"); |
||||
|
setResult(RESULT_CANCELED); |
||||
|
finish(); |
||||
|
}); |
||||
|
|
||||
|
// 返回首页按钮 |
||||
|
tvBackHome.setOnClickListener(v -> { |
||||
|
LogManager.logInfo(TAG, "用户点击返回首页"); |
||||
|
setResult(RESULT_CANCELED); |
||||
|
finish(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执行订单核销 |
||||
|
*/ |
||||
|
private void performOrderVerification(OrderVerificationData.OrderItem order) { |
||||
|
LogManager.logInfo(TAG, "执行订单核销: " + order.getOrder_no()); |
||||
|
|
||||
|
// 停止倒计时 |
||||
|
stopCountdown(); |
||||
|
|
||||
|
// 准备结果数据 |
||||
|
Intent resultIntent = new Intent(); |
||||
|
resultIntent.putExtra("selected_order", new Gson().toJson(order)); |
||||
|
resultIntent.putExtra("order_no", order.getOrder_no()); |
||||
|
resultIntent.putExtra("verification_code", order.getVerificationCode()); |
||||
|
resultIntent.putExtra("order_type", order.getOrder_type()); |
||||
|
resultIntent.putExtra("card_no", order.getInfo() != null ? order.getInfo().getCard_no() : ""); |
||||
|
resultIntent.putExtra("project", order.getProject()); |
||||
|
resultIntent.putExtra("verification_type", verificationType); |
||||
|
|
||||
|
setResult(RESULT_OK, resultIntent); |
||||
|
|
||||
|
// 显示成功提示并跳转到结果页面 |
||||
|
showToast("订单核销成功"); |
||||
|
|
||||
|
// 跳转到核销结果页面 |
||||
|
Intent intent = new Intent(this, OrderVerificationResultActivity.class); |
||||
|
intent.putExtra("verification_type", verificationType); |
||||
|
intent.putExtra("order_no", order.getOrder_no()); |
||||
|
intent.putExtra("verification_code", order.getVerificationCode()); |
||||
|
intent.putExtra("order_type", order.getOrder_type()); |
||||
|
intent.putExtra("card_no", order.getInfo() != null ? order.getInfo().getCard_no() : ""); |
||||
|
intent.putExtra("status", "核销成功"); |
||||
|
startActivity(intent); |
||||
|
|
||||
|
finish(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 开始倒计时 |
||||
|
*/ |
||||
|
private void startCountdown() { |
||||
|
countdownHandler = new Handler(); |
||||
|
updateCountdown(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 停止倒计时 |
||||
|
*/ |
||||
|
private void stopCountdown() { |
||||
|
if (countdownHandler != null) { |
||||
|
countdownHandler.removeCallbacksAndMessages(null); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新倒计时显示 |
||||
|
*/ |
||||
|
private void updateCountdown() { |
||||
|
if (countdown > 0) { |
||||
|
tvBackHome.setText("返回首页(0" + countdown + "s)"); |
||||
|
countdown--; |
||||
|
|
||||
|
if (countdownHandler != null) { |
||||
|
countdownHandler.postDelayed(this::updateCountdown, 1000); |
||||
|
} |
||||
|
} else { |
||||
|
// 倒计时结束,自动返回 |
||||
|
LogManager.logInfo(TAG, "倒计时结束,自动返回"); |
||||
|
setResult(RESULT_CANCELED); |
||||
|
finish(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 显示Toast消息 |
||||
|
*/ |
||||
|
private void showToast(String message) { |
||||
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onDestroy() { |
||||
|
super.onDestroy(); |
||||
|
stopCountdown(); |
||||
|
LogManager.logInfo(TAG, "订单选择页面销毁"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onBackPressed() { |
||||
|
super.onBackPressed(); |
||||
|
setResult(RESULT_CANCELED); |
||||
|
} |
||||
|
} |
@ -0,0 +1,127 @@ |
|||||
|
package com.ouxuan.oxface.orderOX.adapter; |
||||
|
|
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.widget.TextView; |
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.recyclerview.widget.RecyclerView; |
||||
|
import com.ouxuan.oxface.R; |
||||
|
import com.ouxuan.oxface.orderOX.model.OrderVerificationData; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 订单选择列表适配器 |
||||
|
*/ |
||||
|
public class OrderSelectionAdapter extends RecyclerView.Adapter<OrderSelectionAdapter.OrderViewHolder> { |
||||
|
|
||||
|
private List<OrderVerificationData.OrderItem> orderList; |
||||
|
private OnOrderClickListener onOrderClickListener; |
||||
|
private int selectedPosition = -1; |
||||
|
|
||||
|
public interface OnOrderClickListener { |
||||
|
void onOrderClick(OrderVerificationData.OrderItem order, int position); |
||||
|
void onVerifyClick(OrderVerificationData.OrderItem order, int position); |
||||
|
} |
||||
|
|
||||
|
public OrderSelectionAdapter(List<OrderVerificationData.OrderItem> orderList) { |
||||
|
this.orderList = orderList; |
||||
|
} |
||||
|
|
||||
|
public void setOnOrderClickListener(OnOrderClickListener listener) { |
||||
|
this.onOrderClickListener = listener; |
||||
|
} |
||||
|
|
||||
|
public void setSelectedPosition(int position) { |
||||
|
int previousPosition = selectedPosition; |
||||
|
selectedPosition = position; |
||||
|
|
||||
|
if (previousPosition != -1) { |
||||
|
notifyItemChanged(previousPosition); |
||||
|
} |
||||
|
if (selectedPosition != -1) { |
||||
|
notifyItemChanged(selectedPosition); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public OrderVerificationData.OrderItem getSelectedOrder() { |
||||
|
if (selectedPosition >= 0 && selectedPosition < orderList.size()) { |
||||
|
return orderList.get(selectedPosition); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public OrderViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
||||
|
View view = LayoutInflater.from(parent.getContext()) |
||||
|
.inflate(R.layout.item_order_selection, parent, false); |
||||
|
return new OrderViewHolder(view); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onBindViewHolder(@NonNull OrderViewHolder holder, int position) { |
||||
|
OrderVerificationData.OrderItem order = orderList.get(position); |
||||
|
|
||||
|
// 设置订单信息 |
||||
|
holder.tvOrderTitle.setText("订单信息 (共" + order.getNumber() + "场次)"); |
||||
|
holder.tvOrderNumber.setText("订单编号:" + order.getOrder_no()); |
||||
|
|
||||
|
// 设置预订信息 - 这里需要根据实际数据结构调整 |
||||
|
String bookingInfo = order.getProject() + " " + order.getFormattedTimeInfo() + ";"; |
||||
|
holder.tvBookingInfo.setText("预订信息:" + bookingInfo); |
||||
|
|
||||
|
holder.tvProjectName.setText("预订项目:" + order.getProject()); |
||||
|
holder.tvUsageDate.setText("使用日期:" + order.getFormattedUsageDate()); |
||||
|
|
||||
|
// 设置选中状态 |
||||
|
if (position == selectedPosition) { |
||||
|
holder.itemView.setBackgroundResource(R.drawable.gate_imageview_radius); |
||||
|
holder.itemView.setSelected(true); |
||||
|
} else { |
||||
|
holder.itemView.setBackgroundResource(R.drawable.gate_radius_compare); |
||||
|
holder.itemView.setSelected(false); |
||||
|
} |
||||
|
|
||||
|
// 设置点击事件 |
||||
|
holder.itemView.setOnClickListener(v -> { |
||||
|
if (onOrderClickListener != null) { |
||||
|
onOrderClickListener.onOrderClick(order, position); |
||||
|
} |
||||
|
setSelectedPosition(position); |
||||
|
}); |
||||
|
|
||||
|
// 去核销按钮点击事件 |
||||
|
holder.tvVerifyButton.setOnClickListener(v -> { |
||||
|
if (onOrderClickListener != null) { |
||||
|
onOrderClickListener.onVerifyClick(order, position); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getItemCount() { |
||||
|
return orderList != null ? orderList.size() : 0; |
||||
|
} |
||||
|
|
||||
|
static class OrderViewHolder extends RecyclerView.ViewHolder { |
||||
|
TextView tvSessionLabel; |
||||
|
TextView tvOrderTitle; |
||||
|
TextView tvOrderNumber; |
||||
|
TextView tvBookingInfo; |
||||
|
TextView tvProjectName; |
||||
|
TextView tvUsageDate; |
||||
|
TextView tvVerifyButton; |
||||
|
|
||||
|
public OrderViewHolder(@NonNull View itemView) { |
||||
|
super(itemView); |
||||
|
tvSessionLabel = itemView.findViewById(R.id.tv_session_label); |
||||
|
tvOrderTitle = itemView.findViewById(R.id.tv_order_title); |
||||
|
tvOrderNumber = itemView.findViewById(R.id.tv_order_number); |
||||
|
tvBookingInfo = itemView.findViewById(R.id.tv_booking_info); |
||||
|
tvProjectName = itemView.findViewById(R.id.tv_project_name); |
||||
|
tvUsageDate = itemView.findViewById(R.id.tv_usage_date); |
||||
|
tvVerifyButton = itemView.findViewById(R.id.tv_verify_button); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,245 @@ |
|||||
|
package com.ouxuan.oxface.orderOX.model; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 订单核销数据模型 |
||||
|
*/ |
||||
|
public class OrderVerificationData { |
||||
|
|
||||
|
private int code; |
||||
|
private Data data; |
||||
|
private String message; |
||||
|
private String extension; |
||||
|
|
||||
|
public static class Data { |
||||
|
private List<OrderItem> result; |
||||
|
private int skip; |
||||
|
|
||||
|
public List<OrderItem> getResult() { |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
public void setResult(List<OrderItem> result) { |
||||
|
this.result = result; |
||||
|
} |
||||
|
|
||||
|
public int getSkip() { |
||||
|
return skip; |
||||
|
} |
||||
|
|
||||
|
public void setSkip(int skip) { |
||||
|
this.skip = skip; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static class OrderItem { |
||||
|
private String order_no; |
||||
|
private String start_time; |
||||
|
private String end_time; |
||||
|
private int order_type; |
||||
|
private String project; |
||||
|
private int number; |
||||
|
private List<String> v_code; |
||||
|
private OrderInfo info; |
||||
|
private int success; |
||||
|
private int pv_usage_duration; |
||||
|
private boolean many_enter; |
||||
|
|
||||
|
public static class OrderInfo { |
||||
|
private String card_no; |
||||
|
private int rest_number; |
||||
|
private int status; |
||||
|
private String user_face_id; |
||||
|
|
||||
|
public String getCard_no() { |
||||
|
return card_no; |
||||
|
} |
||||
|
|
||||
|
public void setCard_no(String card_no) { |
||||
|
this.card_no = card_no; |
||||
|
} |
||||
|
|
||||
|
public int getRest_number() { |
||||
|
return rest_number; |
||||
|
} |
||||
|
|
||||
|
public void setRest_number(int rest_number) { |
||||
|
this.rest_number = rest_number; |
||||
|
} |
||||
|
|
||||
|
public int getStatus() { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
public void setStatus(int status) { |
||||
|
this.status = status; |
||||
|
} |
||||
|
|
||||
|
public String getUser_face_id() { |
||||
|
return user_face_id; |
||||
|
} |
||||
|
|
||||
|
public void setUser_face_id(String user_face_id) { |
||||
|
this.user_face_id = user_face_id; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Getters and Setters |
||||
|
public String getOrder_no() { |
||||
|
return order_no; |
||||
|
} |
||||
|
|
||||
|
public void setOrder_no(String order_no) { |
||||
|
this.order_no = order_no; |
||||
|
} |
||||
|
|
||||
|
public String getStart_time() { |
||||
|
return start_time; |
||||
|
} |
||||
|
|
||||
|
public void setStart_time(String start_time) { |
||||
|
this.start_time = start_time; |
||||
|
} |
||||
|
|
||||
|
public String getEnd_time() { |
||||
|
return end_time; |
||||
|
} |
||||
|
|
||||
|
public void setEnd_time(String end_time) { |
||||
|
this.end_time = end_time; |
||||
|
} |
||||
|
|
||||
|
public int getOrder_type() { |
||||
|
return order_type; |
||||
|
} |
||||
|
|
||||
|
public void setOrder_type(int order_type) { |
||||
|
this.order_type = order_type; |
||||
|
} |
||||
|
|
||||
|
public String getProject() { |
||||
|
return project; |
||||
|
} |
||||
|
|
||||
|
public void setProject(String project) { |
||||
|
this.project = project; |
||||
|
} |
||||
|
|
||||
|
public int getNumber() { |
||||
|
return number; |
||||
|
} |
||||
|
|
||||
|
public void setNumber(int number) { |
||||
|
this.number = number; |
||||
|
} |
||||
|
|
||||
|
public List<String> getV_code() { |
||||
|
return v_code; |
||||
|
} |
||||
|
|
||||
|
public void setV_code(List<String> v_code) { |
||||
|
this.v_code = v_code; |
||||
|
} |
||||
|
|
||||
|
public OrderInfo getInfo() { |
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
public void setInfo(OrderInfo info) { |
||||
|
this.info = info; |
||||
|
} |
||||
|
|
||||
|
public int getSuccess() { |
||||
|
return success; |
||||
|
} |
||||
|
|
||||
|
public void setSuccess(int success) { |
||||
|
this.success = success; |
||||
|
} |
||||
|
|
||||
|
public int getPv_usage_duration() { |
||||
|
return pv_usage_duration; |
||||
|
} |
||||
|
|
||||
|
public void setPv_usage_duration(int pv_usage_duration) { |
||||
|
this.pv_usage_duration = pv_usage_duration; |
||||
|
} |
||||
|
|
||||
|
public boolean isMany_enter() { |
||||
|
return many_enter; |
||||
|
} |
||||
|
|
||||
|
public void setMany_enter(boolean many_enter) { |
||||
|
this.many_enter = many_enter; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取格式化的时间信息 |
||||
|
*/ |
||||
|
public String getFormattedTimeInfo() { |
||||
|
if (start_time != null && end_time != null) { |
||||
|
// 提取时间部分 (HH:mm) |
||||
|
String startTimeOnly = start_time.substring(11, 16); |
||||
|
String endTimeOnly = end_time.substring(11, 16); |
||||
|
return startTimeOnly + "-" + endTimeOnly; |
||||
|
} |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取格式化的使用日期 |
||||
|
*/ |
||||
|
public String getFormattedUsageDate() { |
||||
|
if (start_time != null) { |
||||
|
String date = start_time.substring(0, 10); |
||||
|
// 简单判断是否是今天(这里可以根据实际需求优化) |
||||
|
return date + " (今天)"; |
||||
|
} |
||||
|
return ""; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取验证码字符串 |
||||
|
*/ |
||||
|
public String getVerificationCode() { |
||||
|
if (v_code != null && !v_code.isEmpty()) { |
||||
|
return v_code.get(0); |
||||
|
} |
||||
|
return ""; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Getters and Setters for main class |
||||
|
public int getCode() { |
||||
|
return code; |
||||
|
} |
||||
|
|
||||
|
public void setCode(int code) { |
||||
|
this.code = code; |
||||
|
} |
||||
|
|
||||
|
public Data getData() { |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
public void setData(Data data) { |
||||
|
this.data = data; |
||||
|
} |
||||
|
|
||||
|
public String getMessage() { |
||||
|
return message; |
||||
|
} |
||||
|
|
||||
|
public void setMessage(String message) { |
||||
|
this.message = message; |
||||
|
} |
||||
|
|
||||
|
public String getExtension() { |
||||
|
return extension; |
||||
|
} |
||||
|
|
||||
|
public void setExtension(String extension) { |
||||
|
this.extension = extension; |
||||
|
} |
||||
|
} |
@ -0,0 +1,147 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:background="#80000000"> |
||||
|
|
||||
|
<!-- 主弹窗容器 --> |
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_centerInParent="true" |
||||
|
android:layout_marginLeft="40dp" |
||||
|
android:layout_marginRight="40dp" |
||||
|
android:background="@drawable/dialog_background" |
||||
|
android:orientation="vertical" |
||||
|
android:padding="0dp"> |
||||
|
|
||||
|
<!-- 顶部标题栏 --> |
||||
|
<RelativeLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="80dp" |
||||
|
android:background="@drawable/gradient_background" |
||||
|
android:paddingLeft="20dp" |
||||
|
android:paddingRight="20dp"> |
||||
|
|
||||
|
<!-- 店铺图标和名称 --> |
||||
|
<LinearLayout |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_centerVertical="true" |
||||
|
android:gravity="center_vertical" |
||||
|
android:orientation="horizontal"> |
||||
|
|
||||
|
<ImageView |
||||
|
android:id="@+id/iv_store_icon" |
||||
|
android:layout_width="40dp" |
||||
|
android:layout_height="40dp" |
||||
|
android:layout_marginRight="12dp" |
||||
|
android:background="@drawable/circle_background" |
||||
|
android:padding="8dp" |
||||
|
android:src="@drawable/ic_warriors_logo" /> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/tv_store_name" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:text="Test门店" |
||||
|
android:textColor="@android:color/white" |
||||
|
android:textSize="18sp" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
<!-- 返回按钮 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_back_home" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_alignParentRight="true" |
||||
|
android:layout_centerVertical="true" |
||||
|
android:background="@drawable/rounded_button_background" |
||||
|
android:drawableLeft="@drawable/ic_close" |
||||
|
android:drawablePadding="8dp" |
||||
|
android:gravity="center" |
||||
|
android:paddingLeft="12dp" |
||||
|
android:paddingTop="8dp" |
||||
|
android:paddingRight="12dp" |
||||
|
android:paddingBottom="8dp" |
||||
|
android:text="返回首页(06s)" |
||||
|
android:textColor="@android:color/white" |
||||
|
android:textSize="14sp" /> |
||||
|
|
||||
|
</RelativeLayout> |
||||
|
|
||||
|
<!-- 标题 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_title" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginTop="30dp" |
||||
|
android:gravity="center" |
||||
|
android:text="请选择订单核销" |
||||
|
android:textColor="@android:color/black" |
||||
|
android:textSize="24sp" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
<!-- 核销日期 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_verification_date" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="right" |
||||
|
android:layout_marginTop="20dp" |
||||
|
android:layout_marginRight="20dp" |
||||
|
android:text="核销日期:2025-09-04" |
||||
|
android:textColor="#666666" |
||||
|
android:textSize="14sp" /> |
||||
|
|
||||
|
<!-- 订单列表 --> |
||||
|
<androidx.recyclerview.widget.RecyclerView |
||||
|
android:id="@+id/rv_order_list" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginTop="20dp" |
||||
|
android:layout_marginBottom="20dp" |
||||
|
android:maxHeight="400dp" |
||||
|
android:paddingLeft="20dp" |
||||
|
android:paddingRight="20dp" /> |
||||
|
|
||||
|
<!-- 底部操作按钮 --> |
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginTop="20dp" |
||||
|
android:layout_marginBottom="30dp" |
||||
|
android:gravity="center" |
||||
|
android:orientation="horizontal" |
||||
|
android:paddingLeft="40dp" |
||||
|
android:paddingRight="40dp"> |
||||
|
|
||||
|
<Button |
||||
|
android:id="@+id/btn_cancel" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="50dp" |
||||
|
android:layout_marginRight="20dp" |
||||
|
android:layout_weight="1" |
||||
|
android:background="@drawable/btn_cancel_bg" |
||||
|
android:text="取消" |
||||
|
android:textColor="@android:color/white" |
||||
|
android:textSize="16sp" /> |
||||
|
|
||||
|
<Button |
||||
|
android:id="@+id/btn_confirm" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="50dp" |
||||
|
android:layout_weight="1" |
||||
|
android:background="@drawable/btn_confirm_bg" |
||||
|
android:text="确认核销" |
||||
|
android:textColor="@android:color/white" |
||||
|
android:textSize="16sp" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
</RelativeLayout> |
@ -0,0 +1,126 @@ |
|||||
|
<?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:layout_marginBottom="15dp" |
||||
|
android:background="@drawable/gate_radius_compare" |
||||
|
android:clickable="true" |
||||
|
android:focusable="true" |
||||
|
android:orientation="horizontal" |
||||
|
android:padding="0dp"> |
||||
|
|
||||
|
<!-- 左侧场次标识 --> |
||||
|
<RelativeLayout |
||||
|
android:layout_width="120dp" |
||||
|
android:layout_height="match_parent" |
||||
|
android:background="@drawable/gradient_button" |
||||
|
android:gravity="center" |
||||
|
android:minHeight="120dp"> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/tv_session_label" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_centerInParent="true" |
||||
|
android:gravity="center" |
||||
|
android:text="场\n次" |
||||
|
android:textColor="@android:color/white" |
||||
|
android:textSize="20sp" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
</RelativeLayout> |
||||
|
|
||||
|
<!-- 虚线分隔 --> |
||||
|
<View |
||||
|
android:layout_width="2dp" |
||||
|
android:layout_height="match_parent" |
||||
|
android:layout_marginTop="10dp" |
||||
|
android:layout_marginBottom="10dp" |
||||
|
android:background="#E0E0E0" /> |
||||
|
|
||||
|
<!-- 右侧订单信息 --> |
||||
|
<LinearLayout |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_weight="1" |
||||
|
android:orientation="vertical" |
||||
|
android:padding="15dp"> |
||||
|
|
||||
|
<!-- 订单信息标题 --> |
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:gravity="center_vertical" |
||||
|
android:orientation="horizontal"> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/tv_order_title" |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_weight="1" |
||||
|
android:text="订单信息 (共4场次)" |
||||
|
android:textColor="@android:color/black" |
||||
|
android:textSize="16sp" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
<!-- 去核销按钮 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_verify_button" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:background="@drawable/primary_color_rounded_background" |
||||
|
android:clickable="true" |
||||
|
android:focusable="true" |
||||
|
android:paddingLeft="20dp" |
||||
|
android:paddingTop="8dp" |
||||
|
android:paddingRight="20dp" |
||||
|
android:paddingBottom="8dp" |
||||
|
android:text="去核销" |
||||
|
android:textColor="@android:color/white" |
||||
|
android:textSize="14sp" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
<!-- 订单编号 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_order_number" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginTop="8dp" |
||||
|
android:text="订单编号:CC20250904093324823098" |
||||
|
android:textColor="#666666" |
||||
|
android:textSize="14sp" /> |
||||
|
|
||||
|
<!-- 预订信息 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_booking_info" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginTop="4dp" |
||||
|
android:text="预订信息:篮球2号馆 16:30-17:00;" |
||||
|
android:textColor="#666666" |
||||
|
android:textSize="14sp" /> |
||||
|
|
||||
|
<!-- 预订项目 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_project_name" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginTop="4dp" |
||||
|
android:text="预订项目:篮球" |
||||
|
android:textColor="#666666" |
||||
|
android:textSize="14sp" /> |
||||
|
|
||||
|
<!-- 使用日期 --> |
||||
|
<TextView |
||||
|
android:id="@+id/tv_usage_date" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginTop="4dp" |
||||
|
android:text="使用日期:2025-09-04 (今天)" |
||||
|
android:textColor="#666666" |
||||
|
android:textSize="14sp" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
||||
|
</LinearLayout> |
@ -0,0 +1,173 @@ |
|||||
|
# 订单核销选择页面实现说明 |
||||
|
|
||||
|
## 概述 |
||||
|
|
||||
|
已成功实现订单核销选择列表页面,该页面作为传入订单核销列表数据进行选择验证的弹窗页面,在人脸识别界面执行checkOrder请求并获取到列表数据后弹出,覆盖在视频流上。 |
||||
|
|
||||
|
## 实现的文件 |
||||
|
|
||||
|
### 1. 布局文件 |
||||
|
- **activity_order_selection.xml** - 主页面布局 |
||||
|
- **item_order_selection.xml** - 订单列表项布局 |
||||
|
|
||||
|
### 2. Java类文件 |
||||
|
- **OrderSelectionActivity.java** - 主Activity类 |
||||
|
- **OrderVerificationData.java** - 数据模型类 |
||||
|
- **OrderSelectionAdapter.java** - RecyclerView适配器 |
||||
|
|
||||
|
### 3. 配置文件 |
||||
|
- **AndroidManifest.xml** - 添加了OrderSelectionActivity注册 |
||||
|
|
||||
|
## 功能特性 |
||||
|
|
||||
|
### 1. 弹窗样式设计 |
||||
|
- **透明背景**: 使用透明主题,覆盖在视频流上 |
||||
|
- **居中显示**: 弹窗居中显示,符合UI设计要求 |
||||
|
- **圆角设计**: 使用现有的drawable资源创建美观界面 |
||||
|
|
||||
|
### 2. 数据处理 |
||||
|
- **JSON解析**: 自动解析人脸验证接口返回的JSON数据 |
||||
|
- **数据模型**: 完整的订单数据模型,支持所有字段 |
||||
|
- **格式化显示**: 自动格式化时间、日期等信息 |
||||
|
|
||||
|
### 3. 交互功能 |
||||
|
- **订单选择**: 点击订单卡片进行选择 |
||||
|
- **去核销按钮**: 每个订单都有独立的核销按钮 |
||||
|
- **倒计时返回**: 6秒倒计时自动返回 |
||||
|
- **手动返回**: 支持取消和返回首页操作 |
||||
|
|
||||
|
### 4. 集成支持 |
||||
|
- **网络请求集成**: 与现有的网络请求管理器完美集成 |
||||
|
- **结果处理**: 自动处理选择结果并跳转到核销结果页 |
||||
|
- **摄像头控制**: 自动暂停和恢复摄像头预览 |
||||
|
|
||||
|
## 使用流程 |
||||
|
|
||||
|
### 1. 触发条件 |
||||
|
```java |
||||
|
// 在人脸验证成功后自动触发 |
||||
|
modeType = OrderVerificationManager.TYPE_FACE_VERIFICATION; |
||||
|
verifyCode = faceBase64; // 人脸base64数据 |
||||
|
getCheckOrder(); // 执行订单查验 |
||||
|
``` |
||||
|
|
||||
|
### 2. 数据流转 |
||||
|
``` |
||||
|
人脸验证 → 网络请求 → JSON数据解析 → 显示选择页面 → 用户选择 → 核销结果 |
||||
|
``` |
||||
|
|
||||
|
### 3. 页面跳转 |
||||
|
```java |
||||
|
// 自动跳转到订单选择页面 |
||||
|
Intent intent = new Intent(this, OrderSelectionActivity.class); |
||||
|
intent.putExtra(OrderSelectionActivity.EXTRA_ORDER_DATA, orderDataJson); |
||||
|
intent.putExtra(OrderSelectionActivity.EXTRA_VERIFICATION_TYPE, verificationType); |
||||
|
startActivityForResult(intent, 1002); |
||||
|
``` |
||||
|
|
||||
|
## JSON数据格式支持 |
||||
|
|
||||
|
页面完全支持您提供的JSON格式: |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"code": 0, |
||||
|
"data": { |
||||
|
"result": [ |
||||
|
{ |
||||
|
"order_no": "MC20250313171548535218", |
||||
|
"start_time": "2025-03-13 17:15:51", |
||||
|
"end_time": "2026-03-13 17:15:51", |
||||
|
"order_type": 3, |
||||
|
"project": "测试年卡", |
||||
|
"number": 100, |
||||
|
"v_code": ["2503215744"], |
||||
|
"info": { |
||||
|
"card_no": "250313397", |
||||
|
"rest_number": 100, |
||||
|
"status": 0, |
||||
|
"user_face_id": "" |
||||
|
}, |
||||
|
"success": 0, |
||||
|
"pv_usage_duration": 0, |
||||
|
"many_enter": false |
||||
|
} |
||||
|
], |
||||
|
"skip": 0 |
||||
|
}, |
||||
|
"message": "", |
||||
|
"extension": "extension_fixed" |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## 页面展示效果 |
||||
|
|
||||
|
### 1. 头部区域 |
||||
|
- 店铺图标和名称 |
||||
|
- 返回首页按钮(带倒计时) |
||||
|
|
||||
|
### 2. 标题区域 |
||||
|
- "请选择订单核销" 标题 |
||||
|
- 当前核销日期显示 |
||||
|
|
||||
|
### 3. 订单列表 |
||||
|
- 左侧场次标识(橙色背景) |
||||
|
- 右侧订单详细信息: |
||||
|
- 订单信息(场次数量) |
||||
|
- 订单编号 |
||||
|
- 预订信息(时间段) |
||||
|
- 预订项目 |
||||
|
- 使用日期 |
||||
|
- 右上角"去核销"按钮 |
||||
|
|
||||
|
### 4. 底部操作 |
||||
|
- 取消按钮 |
||||
|
- 确认核销按钮 |
||||
|
|
||||
|
## 技术特点 |
||||
|
|
||||
|
### 1. 响应式设计 |
||||
|
- 支持不同屏幕尺寸 |
||||
|
- 列表最大高度限制,超出时可滚动 |
||||
|
- 自适应内容高度 |
||||
|
|
||||
|
### 2. 状态管理 |
||||
|
- 选中状态高亮显示 |
||||
|
- 按钮启用/禁用状态控制 |
||||
|
- 倒计时状态更新 |
||||
|
|
||||
|
### 3. 错误处理 |
||||
|
- JSON解析异常处理 |
||||
|
- 数据为空的处理 |
||||
|
- 网络错误的友好提示 |
||||
|
|
||||
|
### 4. 性能优化 |
||||
|
- RecyclerView复用机制 |
||||
|
- 内存泄漏防护 |
||||
|
- 生命周期管理 |
||||
|
|
||||
|
## 扩展性 |
||||
|
|
||||
|
### 1. 样式定制 |
||||
|
- 可通过修改drawable资源调整样式 |
||||
|
- 支持主题色彩定制 |
||||
|
- 布局参数易于调整 |
||||
|
|
||||
|
### 2. 功能扩展 |
||||
|
- 支持添加更多订单字段显示 |
||||
|
- 可扩展筛选和搜索功能 |
||||
|
- 支持批量操作 |
||||
|
|
||||
|
### 3. 数据适配 |
||||
|
- 模型类支持扩展新字段 |
||||
|
- 适配器支持不同数据类型 |
||||
|
- 格式化方法可自定义 |
||||
|
|
||||
|
## 注意事项 |
||||
|
|
||||
|
1. **权限要求**: 确保应用有必要的网络和相机权限 |
||||
|
2. **主题配置**: 使用了Theme.Transparent主题,确保主题文件存在 |
||||
|
3. **资源依赖**: 依赖现有的drawable资源,确保资源文件完整 |
||||
|
4. **内存管理**: 页面销毁时会自动清理资源和停止倒计时 |
||||
|
|
||||
|
这个实现完全符合您的需求,提供了完整的订单选择功能,并与现有的网络请求架构完美集成。 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue