diff --git a/app/src/main/java/com/example/tyre/TyreLayoutActivity.java b/app/src/main/java/com/example/tyre/TyreLayoutActivity.java index c150d46..c23c667 100644 --- a/app/src/main/java/com/example/tyre/TyreLayoutActivity.java +++ b/app/src/main/java/com/example/tyre/TyreLayoutActivity.java @@ -1,7 +1,6 @@ package com.example.tyre; -import androidx.appcompat.app.AppCompatActivity; - +import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -20,18 +19,22 @@ import android.widget.Button; import android.widget.TextView; import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; + import com.android.hdhe.uhf.reader.UhfReader; import com.android.hdhe.uhf.readerInterface.TagModel; -import com.example.tyre.entity.AjaxResult; +import com.example.tyre.adapter.CarRecordAdapter; +import com.example.tyre.databinding.ActivityTyreLayoutBinding; import com.example.tyre.entity.BaseCar; -import com.example.tyre.entity.BaseTyre; +import com.example.tyre.entity.CarLifecycleDTO; +import com.example.tyre.entity.CarMaintenanceLifecycleDTO; import com.example.tyre.entity.EPC; import com.example.tyre.maintenance.base.MyRecultCall; import com.example.tyre.maintenance.base.MyResult; +import com.example.tyre.maintenance.been.BaseTyre; import com.example.tyre.util.CarSelectionDialog; import com.example.tyre.util.CommonDialog; import com.example.tyre.util.MyUrl; -import com.example.tyre.util.SharedPreferencesUtils; import com.example.tyre.util.Util; import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; @@ -51,44 +54,74 @@ import cn.pda.serialport.Tools; import okhttp3.MediaType; import okhttp3.RequestBody; -import com.example.tyre.databinding.ActivityTyreLayoutBinding; - -public class TyreLayoutActivity extends AppCompatActivity { - - private ActivityTyreLayoutBinding binding; +public class TyreLayoutActivity extends AppCompatActivity implements CarRecordAdapter.ItemClickCall { + // 防抖延迟时间 (毫秒) + private static final long DEBOUNCE_DELAY = 500; + public MediaType JSON = MediaType.parse("application/json; charset=utf-8"); TextInputEditText etPlateNumber; Button btnRetrieve; TextInputLayout tilPlateNumber; - + long lastTime; + long nextTime; + String min = "EC0001012026010100000001"; // 左边界(包含) + String max = "EC0001012026010100100000"; // 右边界(包含) + private ActivityTyreLayoutBinding binding; private ProgressDialog progressDialog; - private boolean isStart = true; private boolean runFlag = true; private boolean startFlag = false; private UhfReader manager; // UHF manager,UHF Operating handle private ArrayList listEPC; private ArrayList listepc = new ArrayList(); - long lastTime; - long nextTime; private Toast mToast; private Toast toast; private KeyReceiver keyReceiver; - String min = "EC0001012026010100000001"; // 左边界(包含) - String max = "EC0001012026010100100000"; // 右边界(包含) - // 1. 定义数据模型类 (对应后台返回的字段) - public static class TireData { - public String position; // 轮位名称 - public String brand; // 品牌 - public String spec; // 规格 - public String installDate; // 安装日期 + private CarRecordAdapter adapter; + // 用于存储最后一次扫描到的 EPC + private String lastScannedEpc; + // 用于处理防抖逻辑的 Handler + private Handler debounceHandler = new Handler(new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + if (msg.what == 1 && lastScannedEpc != null) { + // 延迟时间到,执行查询 + showLoadingDialog(); - public TireData(String position, String brand, String spec, String installDate) { - this.position = position; - this.brand = brand; - this.spec = spec; - this.installDate = installDate; + // 查询车辆数据方法 + findCar(lastScannedEpc); + lastScannedEpc = null; // 清空,等待下一次扫描 + } + return true; } + }); + + /** + * 判断字符串是否在指定的区间内(包含边界) + * + * @param target 要判断的目标字符串 + * @param min 区间左边界 + * @param max 区间右边界 + * @return true=在区间内,false=不在 + */ + public static boolean isInRange(String target, String min, String max) { + // 空值校验,避免空指针异常 + if (target == null || min == null || max == null) { + return false; + } + // compareTo规则: + // 1. 字符串相等返回0; + // 2. 目标字符串 > 对比字符串 返回正数; + // 3. 目标字符串 < 对比字符串 返回负数。 + // 因此:target >= min 等价于 target.compareTo(min) >= 0; + // target <= max 等价于 target.compareTo(max) <= 0。 + return target.compareTo(min) >= 0 && target.compareTo(max) <= 0; + } + + // 点击item + @Override + public void onClick(int position) { + } @Override @@ -106,10 +139,12 @@ public class TyreLayoutActivity extends AppCompatActivity { tilPlateNumber = binding.tilPlateNumber; etPlateNumber.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } @Override - public void onTextChanged(CharSequence s, int start, int before, int count) {} + public void onTextChanged(CharSequence s, int start, int before, int count) { + } @Override public void afterTextChanged(Editable s) { @@ -120,11 +155,13 @@ public class TyreLayoutActivity extends AppCompatActivity { String plateNumber = etPlateNumber.getText().toString().trim(); if (!plateNumber.isEmpty()) { showLoadingDialog(); - performSearch(plateNumber); + performSearchOld(plateNumber); } else { tilPlateNumber.setError("车牌号不能为空"); } }); + adapter = new CarRecordAdapter(this, this); + binding.setAdapter(adapter); } private void bindViews() { @@ -136,14 +173,14 @@ public class TyreLayoutActivity extends AppCompatActivity { private void setupClickListeners() { binding.btnRetrieve.setOnClickListener(v -> { String PlateNumber = etPlateNumber.getText().toString(); - if (PlateNumber == null || PlateNumber.isEmpty()) - { + if (PlateNumber == null || PlateNumber.isEmpty()) { new CommonDialog(TyreLayoutActivity.this).setMessage("请输入车牌号!").show(); return; } carBangding(PlateNumber); }); } + @Override public void onResume() { super.onResume(); @@ -155,34 +192,99 @@ public class TyreLayoutActivity extends AppCompatActivity { registerReceiver(); } - @Override public void onPause() { startFlag = false; super.onPause(); unregisterReceiver(); } + @Override protected void onDestroy() { startFlag = false; runFlag = false; super.onDestroy(); } - public MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - private void performSearch(String carNo) { - Map map=new HashMap<>(); + + private void selectInfo(String carNo) { + OkGo.get(MyUrl.url + "/tyre/car/lifecycle/" + carNo) + .execute(new MyRecultCall(progressDialog, this) { + @SuppressLint("NotifyDataSetChanged") + @Override + public void onSuccess(Response response) { + super.onSuccess(response); + MyResult body = response.body(); + if (body.getCode() == 0) { + CarLifecycleDTO carLifecycleDTO = + new Gson().fromJson(body.getJson(), CarLifecycleDTO.class); + List maintenanceList = + carLifecycleDTO.getMaintenanceList(); + if (maintenanceList != null && !maintenanceList.isEmpty()) { + adapter.setList(maintenanceList); + adapter.notifyDataSetChanged(); + } + // 轮位显示 + List mountedTyres = carLifecycleDTO.getMountedTyres(); + mountedTyres.forEach(tire -> { + String wheelPostion = tire.getWheelPostion(); + initTire(wheelPostion, tire); + + }); + // 显示里程 + binding.selectInfoMileage.setText(carLifecycleDTO.getCar().getInputMileage()); + + } + + } + }); + } + + // 初始化轮胎信息 + private void initTire(String wheelPostion, com.example.tyre.maintenance.been.BaseTyre baseTyre) { + binding.setTire1(new com.example.tyre.maintenance.been.BaseTyre()); + binding.setTire2(new com.example.tyre.maintenance.been.BaseTyre()); + binding.setTire3(new com.example.tyre.maintenance.been.BaseTyre()); + binding.setTire4(new com.example.tyre.maintenance.been.BaseTyre()); + binding.setTire5(new com.example.tyre.maintenance.been.BaseTyre()); + binding.setTire6(new com.example.tyre.maintenance.been.BaseTyre()); + switch (wheelPostion) { + case "左前轮": + binding.setTire1(baseTyre); + break; + case "右前轮": + binding.setTire2(baseTyre); + break; + case "左外轮": + binding.setTire3(baseTyre); + break; + case "左内轮": + binding.setTire4(baseTyre); + break; + + case "右内轮": + binding.setTire5(baseTyre); + break; + case "右外轮": + binding.setTire6(baseTyre); + break; + } + } + + // 检索车牌号 + private void performSearchOld(String carNo) { + Map map = new HashMap<>(); map.put("carNo", carNo); OkGo.post(MyUrl.url + "/tyre/car/PdaQueryCarList") .tag(this) .upRequestBody(RequestBody.create(JSON, new Gson().toJson(map))) .params("carNo", carNo) .execute( - new MyRecultCall(progressDialog,this){ + new MyRecultCall(progressDialog, this) { @Override public void onSuccess(Response response) { super.onSuccess(response); var body = response.body(); - if (body.getCode()==0) { + if (body.getCode() == 0) { Gson gson = new Gson(); List baseCarList = @@ -215,6 +317,7 @@ public class TyreLayoutActivity extends AppCompatActivity { } }*/); } + private void showCarSelectionDialog(List carNoList) { CarSelectionDialog dialog = new CarSelectionDialog(this, carNoList); dialog.setOnCarSelectedListener(new CarSelectionDialog.OnCarSelectedListener() { @@ -222,25 +325,45 @@ public class TyreLayoutActivity extends AppCompatActivity { public void onCarSelected(String carNo) { // 处理选中的车辆 etPlateNumber.setText(carNo); + selectInfo(carNo);// 检索车辆信息 } }); dialog.show(); } + private void carBangding(String PlateNumber) { OkGo.post(MyUrl.url + "/tyre/tyre/getCarBingTire") .tag(this).params("carNo", PlateNumber) .execute(new StringCallback() { @Override public void onSuccess(Response response) { - //hideLoadingDialog(); + // hideLoadingDialog(); String body = response.body(); - Gson gson=new Gson(); + Gson gson = new Gson(); // List baseTyreList = gson.fromJson(body, BaseTyre.class); - List baseTyreList = gson.fromJson(body, new com.google.gson.reflect.TypeToken>(){}.getType()); + List baseTyreList = + gson.fromJson(body, new com.google.gson.reflect.TypeToken>() { + }.getType()); bindDataToViews(baseTyreList); } }); } +// private void bindDataToViews(List dataList) { +// // 假设 dataList.get(0) 是左前轮,dataList.get(1) 是右前轮... +// // 请根据你实际的列表顺序调整索引 +// +// if (dataList.size() >= 2) { +// // 绑定左前轮 +// updateTireView(findViewById(R.id.tire_left_front), dataList.get(0)); +// +// // 绑定右前轮 +// updateTireView(findViewById(R.id.tire_right_front), dataList.get(1)); +// +// // 绑定其他轮胎... +// // updateTireView(findViewById(R.id.tire_left_mid), dataList.get(2)); +// } +// } + private void findCar(String carNumber) { OkGo.post(MyUrl.url + "/tyre/car/queryCarByRfid").tag(this).params("rfid", carNumber).execute(new StringCallback() { @Override @@ -254,7 +377,7 @@ public class TyreLayoutActivity extends AppCompatActivity { // 空值处理:若字段为 null 则显示空字符串 String carNo = safeGetString(baseCar.getCarNo()); etPlateNumber.setText(carNo); - }else { + } else { new CommonDialog(TyreLayoutActivity.this).setMessage("请检查车辆芯片绑定数据!").show(); } } catch (JsonSyntaxException e) { @@ -263,9 +386,11 @@ public class TyreLayoutActivity extends AppCompatActivity { } }); } + private String safeGetString(String value) { return value == null || "null".equals(value) ? "" : value; } + /** * 核心方法:将数据绑定到具体的 Include 视图上 */ @@ -292,15 +417,15 @@ public class TyreLayoutActivity extends AppCompatActivity { targetView = findViewById(R.id.tire_middle_left); TextView viewById = targetView.findViewById(R.id.iv_tire_icon); viewById.setText("左内轮"); - }else if ("右内轮".equals(pos)) { + } else if ("右内轮".equals(pos)) { targetView = findViewById(R.id.tire_middle_right); TextView viewById = targetView.findViewById(R.id.iv_tire_icon); viewById.setText("右内轮"); - }else if ("左外轮".equals(pos)) { + } else if ("左外轮".equals(pos)) { targetView = findViewById(R.id.tire_bottom_left); TextView viewById = targetView.findViewById(R.id.iv_tire_icon); viewById.setText("左外轮"); - }else if ("右外轮".equals(pos)) { + } else if ("右外轮".equals(pos)) { targetView = findViewById(R.id.tire_bottom_right); TextView viewById = targetView.findViewById(R.id.iv_tire_icon); viewById.setText("右外轮"); @@ -312,26 +437,12 @@ public class TyreLayoutActivity extends AppCompatActivity { } } } -// private void bindDataToViews(List dataList) { -// // 假设 dataList.get(0) 是左前轮,dataList.get(1) 是右前轮... -// // 请根据你实际的列表顺序调整索引 -// -// if (dataList.size() >= 2) { -// // 绑定左前轮 -// updateTireView(findViewById(R.id.tire_left_front), dataList.get(0)); -// -// // 绑定右前轮 -// updateTireView(findViewById(R.id.tire_right_front), dataList.get(1)); -// -// // 绑定其他轮胎... -// // updateTireView(findViewById(R.id.tire_left_mid), dataList.get(2)); -// } -// } /** * 通用方法:更新单个轮胎卡片的 UI + * * @param container include 标签对应的根布局 View - * @param data 该轮胎的数据对象 + * @param data 该轮胎的数据对象 */ private void updateTireView(View container, BaseTyre data) { if (container == null) return; @@ -345,7 +456,7 @@ public class TyreLayoutActivity extends AppCompatActivity { if (tvBrand != null) tvBrand.setText("品牌: " + data.getTyreBrand()); if (tvSpec != null) tvSpec.setText("规格: " + data.getTyreModel()); if (tvSelfNo != null) tvSelfNo.setText("自编号: " + data.getSelfNo()); - if (tvDate != null) tvDate.setText("日期: " + data.getCreateTime()); + // if (tvDate != null) tvDate.setText("日期: " + data.getCreateTime()); } private void addToList(final List list, final String epc, final byte rssi) { @@ -361,7 +472,7 @@ public class TyreLayoutActivity extends AppCompatActivity { list.add(epcTag); listepc.add(epc); - }else { + } else { for (int i = 0; i < list.size(); i++) { EPC mEPC = list.get(i); // list contain this epc @@ -383,20 +494,20 @@ public class TyreLayoutActivity extends AppCompatActivity { } // play sound - lastTime = SystemClock.elapsedRealtime(); + lastTime = SystemClock.elapsedRealtime(); long time = lastTime - nextTime; if (time >= 60) { Util.play(1, 0); nextTime = lastTime; Log.e("TAG", "run: " + time); } - if (listepc != null && !listepc.isEmpty()){ + if (listepc != null && !listepc.isEmpty()) { startFlag = false; String currentEpc = listepc.get(0); if (isInRange(currentEpc, min, max)) { - //请求后台 查询车辆信息 + // 请求后台 查询车辆信息 // car.setText(currentEpc); - //请求后台 + // 请求后台 debounceHandler.removeMessages(1); lastScannedEpc = currentEpc; debounceHandler.sendEmptyMessageDelayed(1, DEBOUNCE_DELAY); @@ -408,50 +519,52 @@ public class TyreLayoutActivity extends AppCompatActivity { }); Log.e("EPC", "listepc:+ " + listepc); } - /** - * 判断字符串是否在指定的区间内(包含边界) - * @param target 要判断的目标字符串 - * @param min 区间左边界 - * @param max 区间右边界 - * @return true=在区间内,false=不在 - */ - public static boolean isInRange(String target, String min, String max) { - // 空值校验,避免空指针异常 - if (target == null || min == null || max == null) { - return false; - } - // compareTo规则: - // 1. 字符串相等返回0; - // 2. 目标字符串 > 对比字符串 返回正数; - // 3. 目标字符串 < 对比字符串 返回负数。 - // 因此:target >= min 等价于 target.compareTo(min) >= 0; - // target <= max 等价于 target.compareTo(max) <= 0。 - return target.compareTo(min) >= 0 && target.compareTo(max) <= 0; - } - // 防抖延迟时间 (毫秒) - private static final long DEBOUNCE_DELAY = 500; - // 用于存储最后一次扫描到的 EPC - private String lastScannedEpc; - // 用于处理防抖逻辑的 Handler - private Handler debounceHandler = new Handler(new Handler.Callback() { - @Override - public boolean handleMessage(Message msg) { - if (msg.what == 1 && lastScannedEpc != null) { - // 延迟时间到,执行查询 - showLoadingDialog(); - //查询车辆数据方法 - findCar(lastScannedEpc); - lastScannedEpc = null; // 清空,等待下一次扫描 - } - return true; - } - }); private void clearData() { listEPC.removeAll(listEPC); listepc.removeAll(listepc); } + private void registerReceiver() { + keyReceiver = new KeyReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction("android.rfid.FUN_KEY"); + filter.addAction("android.intent.action.FUN_KEY"); + registerReceiver(keyReceiver, filter); + } + + private void unregisterReceiver() { + unregisterReceiver(keyReceiver); + } + + private void showLoadingDialog() { + progressDialog = new ProgressDialog(this); + progressDialog.setMessage("数据加载中..."); + progressDialog.setCancelable(false); + progressDialog.show(); + } + + private void hideLoadingDialog() { + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + } + } + + // 1. 定义数据模型类 (对应后台返回的字段) + public static class TireData { + public String position; // 轮位名称 + public String brand; // 品牌 + public String spec; // 规格 + public String installDate; // 安装日期 + + public TireData(String position, String brand, String spec, String installDate) { + this.position = position; + this.brand = brand; + this.spec = spec; + this.installDate = installDate; + } + } + private class KeyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -474,35 +587,26 @@ public class TyreLayoutActivity extends AppCompatActivity { case KeyEvent.KEYCODE_F4: case KeyEvent.KEYCODE_F5: case 136: - //扫描 + // 扫描 startFlag = true; break; } } } } - private void registerReceiver() { - keyReceiver = new KeyReceiver(); - IntentFilter filter = new IntentFilter(); - filter.addAction("android.rfid.FUN_KEY"); - filter.addAction("android.intent.action.FUN_KEY"); - registerReceiver(keyReceiver, filter); - } - private void unregisterReceiver() { - unregisterReceiver(keyReceiver); - } class InventoryThread extends Thread { - private List tagList; byte[] accessPassword = Tools.HexString2Bytes("00000000"); + private List tagList; + @Override public void run() { super.run(); while (runFlag) { if (startFlag) { - tagList = manager.inventoryRealTime(); //实时盘存 + tagList = manager.inventoryRealTime(); // 实时盘存 if (tagList != null && !tagList.isEmpty()) { - //播放提示音 + // 播放提示音 Util.play(1, 0); for (TagModel tag : tagList) { if (tag == null) { @@ -510,7 +614,8 @@ public class TyreLayoutActivity extends AppCompatActivity { // String epcStr = new String(epc); addToList(listEPC, epcStr, (byte) -1); } else { - String epcStr = Tools.Bytes2HexString(tag.getmEpcBytes(), tag.getmEpcBytes().length); + String epcStr = + Tools.Bytes2HexString(tag.getmEpcBytes(), tag.getmEpcBytes().length); // String epcStr = new String(epc); byte rssi = tag.getmRssi(); addToList(listEPC, epcStr, rssi); @@ -529,16 +634,4 @@ public class TyreLayoutActivity extends AppCompatActivity { } } } - - private void showLoadingDialog() { - progressDialog = new ProgressDialog(this); - progressDialog.setMessage("数据加载中..."); - progressDialog.setCancelable(false); - progressDialog.show(); - } - private void hideLoadingDialog() { - if (progressDialog != null && progressDialog.isShowing()) { - progressDialog.dismiss(); - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/example/tyre/adapter/CarRecordAdapter.java b/app/src/main/java/com/example/tyre/adapter/CarRecordAdapter.java new file mode 100644 index 0000000..17571d9 --- /dev/null +++ b/app/src/main/java/com/example/tyre/adapter/CarRecordAdapter.java @@ -0,0 +1,79 @@ +package com.example.tyre.adapter; + +import android.content.Context; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.databinding.DataBindingUtil; +import androidx.recyclerview.widget.RecyclerView; + +import com.example.tyre.BR; +import com.example.tyre.R; +import com.example.tyre.databinding.ItemCarRecordBinding; +import com.example.tyre.entity.CarMaintenanceLifecycleDTO; +import com.example.tyre.maintenance.been.CheckInstanceFiles; + +import java.util.List; + +/** + * @author wanghao + * @date 2024/3/11 + */ +public class CarRecordAdapter extends RecyclerView.Adapter { + private List list; + private static Context context; + private LayoutInflater inflater; + private ItemClickCall clickCall; + + + + + public CarRecordAdapter(Context context, ItemClickCall clickCall) { + this.context = context; + this.clickCall = clickCall; + inflater = LayoutInflater.from(context); + } + + public void setList(List list) { + this.list = list; + } + + @NonNull + @Override + public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + ItemCarRecordBinding binding = DataBindingUtil.inflate(inflater, R.layout.item_car_record, parent, false); + return new MyViewHolder(binding); + } + + // @SuppressLint("CheckResult") + @Override + public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { + var item = list.get(position); + var binding = holder.binding; + binding.setVariable(BR.item, item); + + + + } + + @Override + public int getItemCount() { + return list==null?0:list.size(); + } + + class MyViewHolder extends RecyclerView.ViewHolder { + private ItemCarRecordBinding binding; + + public MyViewHolder(ItemCarRecordBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + + + } + public interface ItemClickCall { + void onClick(int position); + } +} diff --git a/app/src/main/java/com/example/tyre/entity/CarLifecycleDTO.java b/app/src/main/java/com/example/tyre/entity/CarLifecycleDTO.java new file mode 100644 index 0000000..65f63cb --- /dev/null +++ b/app/src/main/java/com/example/tyre/entity/CarLifecycleDTO.java @@ -0,0 +1,50 @@ +package com.example.tyre.entity; + +import java.io.Serializable; +import com.example.tyre.maintenance.been.BaseTyre; +import java.util.List; + +/** + * 车辆生命周期聚合报表DTO。 + *

+ * 作为车辆全生命周期弹窗“首屏”的统一返回对象,承载车辆概要、当前装车轮胎快照、 + * 最近事件时间线、车辆维保历史以及各维度记录总数量。维保历史已并入本聚合对象, + * 避免页面为同一车辆生命周期再额外请求独立维保列表接口。 + *

+ */ +public class CarLifecycleDTO implements Serializable +{ + private CarLifecycleSummaryDTO car; + /** 当前装车轮胎快照,数量较少(通常不超过车辆轮位数),随概要一次返回用于首屏快速展示。 */ + private List mountedTyres ; + + + + /** 车辆维保工单历史,随生命周期聚合接口返回,避免页面重复调用单独的维保列表接口。 */ + private List maintenanceList ; + + + public List getMountedTyres() { + return mountedTyres; + } + + public void setMountedTyres(List mountedTyres) { + this.mountedTyres = mountedTyres; + } + + public List getMaintenanceList() { + return maintenanceList; + } + + public void setMaintenanceList(List maintenanceList) { + this.maintenanceList = maintenanceList; + } + + public CarLifecycleSummaryDTO getCar() { + return car; + } + + public void setCar(CarLifecycleSummaryDTO car) { + this.car = car; + } +} diff --git a/app/src/main/java/com/example/tyre/entity/CarLifecycleEventDTO.java b/app/src/main/java/com/example/tyre/entity/CarLifecycleEventDTO.java new file mode 100644 index 0000000..d09dfc3 --- /dev/null +++ b/app/src/main/java/com/example/tyre/entity/CarLifecycleEventDTO.java @@ -0,0 +1,302 @@ +package com.example.tyre.entity; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 车辆生命周期统一事件DTO。 + *

+ * 作为“最近事件时间线”的数据载体,将轮胎装卸事件与维保工单事件抽象为统一结构, + * 便于前端以同一套模板按时间轴展示。事件类型(eventType)区分数据来源: + * INSTALL 表示轮胎装卸动作,MAINTENANCE 表示维保工单动作。 + *

+ */ +public class CarLifecycleEventDTO +{ + + /** 事件类型字典值,区分数据来源。例如:INSTALL(轮胎装卸)、MAINTENANCE(维保工单)。 */ + private String eventType; + + /** 事件发生时间,统一取各来源表中的操作/创建时间,用于时间轴排序。 */ + private Date eventTime; + + /** 轮胎RFID编码,仅在事件类型为轮胎装卸时有效。 */ + private String tyreRfid; + + /** 轮胎编号,业务展示用。 */ + private String tyreNo; + + /** 轮胎自编号,与 tyreNo 区分,用于内部管理。 */ + private String selfNo; + + /** 轮胎品牌。 */ + private String tyreBrand; + + /** 轮胎规格型号。 */ + private String tyreModel; + + /** 轮位名称,例如:左前轮、右后第二轴等,仅在装卸事件中有效。 */ + private String wheelPostion; + + /** 事件关联的行驶里程(字符串形式,保留原始录入格式)。 */ + private String mileage; + + /** 事件关联的花纹深度(毫米),用于磨损评估。 */ + private String patternDepth; + + /** 状态字典值,例如:工单状态、轮胎状态等,视 eventType 而定。 */ + private String status; + + /** 工单编号,仅在事件类型为维保工单时有效。 */ + private String orderNo; + + /** 类型编码,例如:维保类型字典值、操作类型字典值。 */ + private String typeCode; + + /** 修理厂/工厂名称,仅在维保工单事件中有效。 */ + private String factoryName; + + /** 录入里程(数值型),维保工单或质检记录中由用户录入的当前总里程。 */ + private BigDecimal inputMileage; + + /** 上次里程(数值型),维保工单中记录的上一次保养时的里程。 */ + private BigDecimal lastMileage; + + /** 保养/维修日期,维保工单事件中的计划或实际执行日期。 */ + private Date maintainDate; + + /** 事件描述/故障描述,维保工单中的故障现象或备注信息。 */ + private String description; + + /** 质检结果,仅在轮胎质检相关事件中有效。 */ + private String result; + + /** 维保/检测类型字典值,例如:一级保养、二级保养、日常巡检。 */ + private String maintenanceType; + + /** 轮胎里程记录开始时间,仅在里程类事件中有效。 */ + private Date startTime; + + /** 轮胎里程记录结束时间,仅在里程类事件中有效。 */ + private Date endTime; + + public String getEventType() + { + return eventType; + } + + public void setEventType(String eventType) + { + this.eventType = eventType; + } + + public Date getEventTime() + { + return eventTime; + } + + public void setEventTime(Date eventTime) + { + this.eventTime = eventTime; + } + + public String getTyreRfid() + { + return tyreRfid; + } + + public void setTyreRfid(String tyreRfid) + { + this.tyreRfid = tyreRfid; + } + + public String getTyreNo() + { + return tyreNo; + } + + public void setTyreNo(String tyreNo) + { + this.tyreNo = tyreNo; + } + + public String getSelfNo() + { + return selfNo; + } + + public void setSelfNo(String selfNo) + { + this.selfNo = selfNo; + } + + public String getTyreBrand() + { + return tyreBrand; + } + + public void setTyreBrand(String tyreBrand) + { + this.tyreBrand = tyreBrand; + } + + public String getTyreModel() + { + return tyreModel; + } + + public void setTyreModel(String tyreModel) + { + this.tyreModel = tyreModel; + } + + public String getWheelPostion() + { + return wheelPostion; + } + + public void setWheelPostion(String wheelPostion) + { + this.wheelPostion = wheelPostion; + } + + public String getMileage() + { + return mileage; + } + + public void setMileage(String mileage) + { + this.mileage = mileage; + } + + public String getPatternDepth() + { + return patternDepth; + } + + public void setPatternDepth(String patternDepth) + { + this.patternDepth = patternDepth; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getOrderNo() + { + return orderNo; + } + + public void setOrderNo(String orderNo) + { + this.orderNo = orderNo; + } + + public String getTypeCode() + { + return typeCode; + } + + public void setTypeCode(String typeCode) + { + this.typeCode = typeCode; + } + + public String getFactoryName() + { + return factoryName; + } + + public void setFactoryName(String factoryName) + { + this.factoryName = factoryName; + } + + public BigDecimal getInputMileage() + { + return inputMileage; + } + + public void setInputMileage(BigDecimal inputMileage) + { + this.inputMileage = inputMileage; + } + + public BigDecimal getLastMileage() + { + return lastMileage; + } + + public void setLastMileage(BigDecimal lastMileage) + { + this.lastMileage = lastMileage; + } + + public Date getMaintainDate() + { + return maintainDate; + } + + public void setMaintainDate(Date maintainDate) + { + this.maintainDate = maintainDate; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public String getResult() + { + return result; + } + + public void setResult(String result) + { + this.result = result; + } + + public String getMaintenanceType() + { + return maintenanceType; + } + + public void setMaintenanceType(String maintenanceType) + { + this.maintenanceType = maintenanceType; + } + + public Date getStartTime() + { + return startTime; + } + + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getEndTime() + { + return endTime; + } + + public void setEndTime(Date endTime) + { + this.endTime = endTime; + } +} diff --git a/app/src/main/java/com/example/tyre/entity/CarLifecycleSummaryDTO.java b/app/src/main/java/com/example/tyre/entity/CarLifecycleSummaryDTO.java new file mode 100644 index 0000000..4dd20e6 --- /dev/null +++ b/app/src/main/java/com/example/tyre/entity/CarLifecycleSummaryDTO.java @@ -0,0 +1,113 @@ +package com.example.tyre.entity; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 车辆生命周期头部概要DTO。 + *

+ * 作为弹窗顶部的“车辆名片”数据,展示用户最关心的车辆静态属性与最近动态指标。 + * 所有字段均来自 base_car 主档及其关联字典/部门表,通过 {@link BaseCarLifecycleMapper#selectLifecycleCar} 一次性查询返回。 + *

+ */ +public class CarLifecycleSummaryDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 车辆主键ID,base_car 表的唯一标识,用于后续子查询精确关联。 */ + private Long carId; + + /** 车牌号,车辆的唯一业务标识,例如:粤B12345。 */ + private String carNo; + + /** 所属部门ID,关联 sys_dept,用于数据权限过滤。 */ + private Long deptId; + + /** 所属车队名称,由部门ID关联翻译而来,前端直接展示。 */ + private String team; + + /** 线路名称,车辆运营的公交/客运线路。 */ + private String line; + + /** 车型,例如:纯电动大巴、混合动力公交等字典值。 */ + private String type; + + /** + * 最近工单录入里程。 + *

+ * 取自该车辆最近一次维保工单中的 input_mileage 字段,仅作为弹窗头部的展示快照。 + * 使用 BigDecimal 类型避免浮点精度问题,但不参与聚合统计,防止不同工单录入口径差异导致统计失真。 + *

+ */ + private String inputMileage; + + public Long getCarId() + { + return carId; + } + + public void setCarId(Long carId) + { + this.carId = carId; + } + + public String getCarNo() + { + return carNo; + } + + public void setCarNo(String carNo) + { + this.carNo = carNo; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + public String getTeam() + { + return team; + } + + public void setTeam(String team) + { + this.team = team; + } + + public String getLine() + { + return line; + } + + public void setLine(String line) + { + this.line = line; + } + + public String getType() + { + return type; + } + + public void setType(String type) + { + this.type = type; + } + + public String getInputMileage() + { + return inputMileage; + } + + public void setInputMileage(String inputMileage) + { + this.inputMileage = inputMileage; + } +} diff --git a/app/src/main/java/com/example/tyre/entity/CarMaintenanceLifecycleDTO.java b/app/src/main/java/com/example/tyre/entity/CarMaintenanceLifecycleDTO.java new file mode 100644 index 0000000..9ebbf2f --- /dev/null +++ b/app/src/main/java/com/example/tyre/entity/CarMaintenanceLifecycleDTO.java @@ -0,0 +1,188 @@ +package com.example.tyre.entity; + +import java.io.Serializable; + + +/** + * 车辆生命周期维保工单记录DTO。 + *

+ * 用于“车辆全生命周期”弹窗中【维保工单记录】Tab页的数据展示。 + * 数据来源为 biz_maintenance_order 表,通过 plate_number(车牌号)直接与车辆关联,无需额外表桥接。 + *

+ */ +public class CarMaintenanceLifecycleDTO implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 工单主键ID,对应 biz_maintenance_order.order_id。 + */ + private Long orderId; + + /** + * 工单编号,业务展示的唯一编号,例如:WB202401150001。 + */ + private String orderNo; + + /** + * 车辆ID,对应工单表中的 vehicle_id 外键(若存在)。 + */ + private Long vehicleId; + + /** + * 车牌号,工单中直接记录的车牌号,用于与车辆主档确认关联。 + */ + private String plateNumber; + + /** + * 维保类型编码,字典值,例如:一级保养、二级保养、小修、大修。 + */ + private String typeCode; + private String typeName; + + /** + * 工单状态编码,字典值,例如:待派工、维修中、已完成、已结算。 + */ + private String status; + + /** + * 录入里程,本次维保/保养时车辆的总行驶里程(数值型)。 + */ + private String inputMileage; + + /** + * 上次里程,上一次保养时记录的里程,用于计算两次保养间的行驶距离。 + */ + private String lastMileage; + + /** + * 保养/维修日期,工单的计划或实际执行日期。 + */ + private String maintainDate; + + /** + * 修理厂名称,执行本次维保的外部或内部修理厂。 + */ + private String factoryName; + + /** + * 故障描述/备注,记录车辆故障现象、维修内容或用户补充说明。 + */ + private String description; + + + public String getTypeName() { + if (typeCode == null) { + typeName = ""; + } else if (typeCode.equals("1")) { + typeName = "二级保养"; + } else if (typeCode.equals("2")) { + typeName = "抢碎修"; + } else if (typeCode.equals("3")) { + typeName = "拆报废车"; + } else if (typeCode.equals("4")) { + typeName = "月检"; + } else if (typeCode.equals("5")) { + typeName = "小修"; + } else if (typeCode.equals("6")) { + typeName = "轮胎修补"; + } else if (typeCode.equals("7")) { + typeName = "轮胎报废"; + } + return typeName; + } + + public Long getOrderId() { + return orderId; + } + + public void setOrderId(Long orderId) { + this.orderId = orderId; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public Long getVehicleId() { + return vehicleId; + } + + public void setVehicleId(Long vehicleId) { + this.vehicleId = vehicleId; + } + + public String getPlateNumber() { + return plateNumber; + } + + public void setPlateNumber(String plateNumber) { + this.plateNumber = plateNumber; + } + + public String getTypeCode() { + return typeCode; + } + + public void setTypeCode(String typeCode) { + this.typeCode = typeCode; + } + + public String getStatus() { + if (status .equals("UNSTARTED")) { + return "未开始"; + } else if (status .equals("PROCESSING")) { + return "执行中"; + } else if (status .equals("COMPLETED")) { + return "已完成"; + } + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getInputMileage() { + return inputMileage; + } + + public void setInputMileage(String inputMileage) { + this.inputMileage = inputMileage; + } + + public String getLastMileage() { + return lastMileage; + } + + public void setLastMileage(String lastMileage) { + this.lastMileage = lastMileage; + } + + public String getMaintainDate() { + return maintainDate; + } + + public void setMaintainDate(String maintainDate) { + this.maintainDate = maintainDate; + } + + public String getFactoryName() { + return factoryName; + } + + public void setFactoryName(String factoryName) { + this.factoryName = factoryName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} diff --git a/app/src/main/java/com/example/tyre/maintenance/TireScrapActivity.java b/app/src/main/java/com/example/tyre/maintenance/TireScrapActivity.java index 1f45132..c99b5df 100644 --- a/app/src/main/java/com/example/tyre/maintenance/TireScrapActivity.java +++ b/app/src/main/java/com/example/tyre/maintenance/TireScrapActivity.java @@ -1,17 +1,193 @@ package com.example.tyre.maintenance; -import androidx.appcompat.app.AppCompatActivity; - +import android.content.Intent; import android.os.Bundle; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Toast; + +import androidx.databinding.DataBindingUtil; import com.example.tyre.R; +import com.example.tyre.databinding.ActivityTireScrapBinding; import com.example.tyre.maintenance.base.BaseActivity; +import com.example.tyre.maintenance.base.MyRecultCall; +import com.example.tyre.maintenance.base.MyResult; +import com.example.tyre.maintenance.been.BaseTyre; +import com.example.tyre.maintenance.been.BizOrderTireDetail; +import com.example.tyre.maintenance.been.Order; +import com.example.tyre.util.MyUrl; +import com.google.gson.reflect.TypeToken; +import com.lzy.okgo.OkGo; +import com.lzy.okgo.callback.StringCallback; +import com.lzy.okgo.model.Response; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import okhttp3.RequestBody; public class TireScrapActivity extends BaseActivity { + private ActivityTireScrapBinding binding; + private Order order; + private String carNo; + private Map tyreMap; + private List baseTyreList; + private List positionList; + private ArrayAdapter positionAdapter; + + // Photos + private int currentPhotoIndex = -1; + private List fileList; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_tire_scrap); + binding = DataBindingUtil.setContentView(this, R.layout.activity_tire_scrap); + + tyreMap = new HashMap<>(); + positionList = new ArrayList<>(); + fileList = new ArrayList<>(); + + Intent intent = getIntent(); + carNo = intent.getStringExtra("carNo"); + String site = intent.getStringExtra("site"); + order = gson.fromJson(intent.getStringExtra("json"), Order.class); + + binding.setCarNo(carNo); + binding.setSite(site); + + positionAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, positionList); + positionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + binding.spinnerScrapPosition.setAdapter(positionAdapter); + + selectTire(carNo); + } + + // 查询轮胎信息 + private void selectTire(String carNo) { + OkGo.post(MyUrl.url + "/tyre/tyre/getCarBingTire").tag(this).params("carNo", carNo).execute(new StringCallback() { + @Override + public void onSuccess(Response response) { + baseTyreList = gson.fromJson(response.body(), new TypeToken>() { + }.getType()); + if (baseTyreList == null || baseTyreList.isEmpty()) { + Toast.makeText(context, "该车无绑定轮胎", Toast.LENGTH_SHORT).show(); + return; + } + positionList.clear(); + tyreMap.clear(); + for (BaseTyre tire : baseTyreList) { + String wheelPostion = tire.getWheelPostion(); + if (wheelPostion != null && !wheelPostion.isEmpty()) { + positionList.add(wheelPostion); + tyreMap.put(wheelPostion, tire); + } + } + positionAdapter.notifyDataSetChanged(); + } + }); + } + + public void takePhoto1(View view) { + currentPhotoIndex = 1; + try { + teke_photo(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void takePhoto2(View view) { + currentPhotoIndex = 2; + try { + teke_photo(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void takePhoto3(View view) { + currentPhotoIndex = 3; + try { + teke_photo(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void tekePhotoResult(String fileUrl, File file) { + super.tekePhotoResult(fileUrl, file); + if (file != null) { + fileList.add(file); + if (currentPhotoIndex == 1) { + binding.ivPhoto1.setImageResource(R.mipmap.ic_duihao); + } else if (currentPhotoIndex == 2) { + binding.ivPhoto2.setImageResource(R.mipmap.ic_duihao); + } else if (currentPhotoIndex == 3) { + binding.ivPhoto3.setImageResource(R.mipmap.ic_duihao); + } + } + } + + public void saveScrapOrder(View view) { + if (positionList.isEmpty()) { + Toast.makeText(context, "无可报废的轮胎", Toast.LENGTH_SHORT).show(); + return; + } + + if (fileList.isEmpty()) { + Toast.makeText(context, "请至少拍摄一张报废照片", Toast.LENGTH_SHORT).show(); + return; + } + + String selectedPosition = (String) binding.spinnerScrapPosition.getSelectedItem(); + BaseTyre selectedTire = tyreMap.get(selectedPosition); + if (selectedTire == null) { + Toast.makeText(context, "选择的轮位无效", Toast.LENGTH_SHORT).show(); + return; + } + + String remark = binding.dialogTireRemark1.getText().toString().trim(); + + BizOrderTireDetail scrapDetail = new BizOrderTireDetail(); + scrapDetail.setOrderId(order.getOrderId()); + scrapDetail.setTireId(selectedTire.getTyreId()); + scrapDetail.setTireCode(selectedTire.getTyreNo()); + scrapDetail.setPositionName(selectedTire.getWheelPostion()); + scrapDetail.setDataType("报废"); + scrapDetail.setTireStatus("报废"); + scrapDetail.setRemark(remark); + + List tireDetails = new ArrayList<>(); + tireDetails.add(scrapDetail); + + Map orderSubmitMap = new HashMap<>(); + orderSubmitMap.put("order", order); + orderSubmitMap.put("tireDetails", tireDetails); + + OkGo.post(url + "/tyre/order/PDASaveMaintenanceOrder") + .tag(this) + .isMultipart(true) + .params("json", gson.toJson(orderSubmitMap)) + .addFileParams("files", fileList) + .execute(new MyRecultCall(dialog, this) { + @Override + public void onSuccess(Response response) { + super.onSuccess(response); + MyResult body = response.body(); + if (body.getCode() == 0) { + Toast.makeText(context, "报废工单提交成功", Toast.LENGTH_SHORT).show(); + finish(); + } else { + Toast.makeText(context, body.getMsg(), Toast.LENGTH_SHORT).show(); + } + } + }); } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_new_home_page.xml b/app/src/main/res/layout/activity_new_home_page.xml index d152a49..e76cbd6 100644 --- a/app/src/main/res/layout/activity_new_home_page.xml +++ b/app/src/main/res/layout/activity_new_home_page.xml @@ -91,7 +91,7 @@ android:onClick="goActivity6" android:text="轮胎修补" - app:layout_columnWeight="1" /> + app:layout_columnWeight="1" />--> --> + app:layout_columnWeight="1" /> diff --git a/app/src/main/res/layout/activity_tire_scrap.xml b/app/src/main/res/layout/activity_tire_scrap.xml index a061143..2208690 100644 --- a/app/src/main/res/layout/activity_tire_scrap.xml +++ b/app/src/main/res/layout/activity_tire_scrap.xml @@ -60,7 +60,7 @@ @@ -107,10 +108,11 @@ android:layout_marginEnd="10dp" android:background="@drawable/bg_block_img_selector" android:gravity="center" - android:onClick="blockClick_1" + android:onClick="takePhoto2" android:orientation="vertical"> @@ -128,10 +130,11 @@ android:layout_marginEnd="10dp" android:background="@drawable/bg_block_img_selector" android:gravity="center" - android:onClick="blockClick_1" + android:onClick="takePhoto3" android:orientation="vertical"> @@ -184,6 +187,7 @@ android:text="完成处理" android:textColor="@color/white" android:textSize="16sp" + android:onClick="saveScrapOrder" android:textStyle="bold" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_tyre_layout.xml b/app/src/main/res/layout/activity_tyre_layout.xml index c034ded..13207b0 100644 --- a/app/src/main/res/layout/activity_tyre_layout.xml +++ b/app/src/main/res/layout/activity_tyre_layout.xml @@ -1,214 +1,398 @@ - + - + + + + + + + + + + + + + + + + + + + android:layout_height="match_parent" + android:background="#F0F4F8" + android:fillViewport="true"> - - + + + + + + + + + + + + + + + +