app/build.gradle
@@ -173,6 +173,7 @@ implementation "androidx.room:room-ktx:2.3.0" runtimeOnly("androidx.room:room-common:2.3.0") annotationProcessor "androidx.room:room-compiler:2.3.0" implementation "androidx.room:room-rxjava3:2.3.0" //图片 implementation 'com.github.bumptech.glide:glide:4.11.0' app/src/main/assets/js/map.js
@@ -275,15 +275,15 @@ function updateLocation(log,lat){ var lastLat=lat; const intervalId = setInterval(() => { lastLat=lastLat+0.0001; // const intervalId = setInterval(() => { // lastLat=lastLat+0.0001; var newPoint = new T.LngLat(log,lastLat); path.push(newPoint); lineLayer.setLngLats(path); map.addOverLay(lineLayer); // 移动地图视角到最后一个位置 map.panTo(newPoint); }, 500); // }, 500); } app/src/main/java/com/dayu/pipirrapp/MyApplication.java
@@ -16,10 +16,12 @@ */ public class MyApplication extends Application { public static MyApplication myApplication; //数据库的tag值 public String myTag = "-1"; public String token; public String userId; @Override public void onCreate() { super.onCreate(); app/src/main/java/com/dayu/pipirrapp/activity/LoginActivity.java
@@ -27,7 +27,6 @@ import com.dayu.pipirrapp.net.BaseResponse; import com.dayu.pipirrapp.net.subscribers.SubscriberListener; import com.dayu.pipirrapp.observer.LoginObserver; import com.dayu.pipirrapp.utils.CommonData; import com.dayu.pipirrapp.utils.CommonKeyName; import com.dayu.pipirrapp.utils.SharedPreferencesHelper; import com.dayu.pipirrapp.utils.ToastUtil; app/src/main/java/com/dayu/pipirrapp/activity/MainActivity.java
@@ -9,8 +9,11 @@ import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import com.dayu.pipirrapp.MyApplication; import com.dayu.pipirrapp.R; import com.dayu.pipirrapp.adapter.TabAdapter; import com.dayu.pipirrapp.bean.db.TagBean; import com.dayu.pipirrapp.dao.DaoSingleton; import com.dayu.pipirrapp.databinding.ActivityMainBinding; import com.dayu.pipirrapp.fragment.OrderFragment; import com.dayu.pipirrapp.fragment.MapFragment; @@ -42,6 +45,9 @@ setupFragments(); initView(); initTab(); TagBean tagBean = DaoSingleton.getInstance(this).tagDao().findFirst(); MyApplication.myApplication.myTag = tagBean.getTag(); mqttManager = new MqttManager(this); mqttManager.connect(); } app/src/main/java/com/dayu/pipirrapp/activity/OrderDealActivity.java
@@ -1,14 +1,15 @@ package com.dayu.pipirrapp.activity; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.SimpleItemAnimator; @@ -17,20 +18,31 @@ import com.dayu.pipirrapp.databinding.ActivityOrderDealBinding; import com.dayu.pipirrapp.tool.FullyGridLayoutManager; import com.dayu.pipirrapp.tool.GlideEngine; import com.dayu.pipirrapp.view.TitleBar; import com.luck.picture.lib.basic.PictureSelectionModel; import com.luck.picture.lib.basic.PictureSelector; import com.luck.picture.lib.config.PictureConfig; import com.luck.picture.lib.config.PictureMimeType; import com.luck.picture.lib.config.SelectMimeType; import com.luck.picture.lib.config.SelectModeConfig; import com.luck.picture.lib.decoration.GridSpacingItemDecoration; import com.luck.picture.lib.engine.CompressFileEngine; import com.luck.picture.lib.engine.ImageEngine; import com.luck.picture.lib.entity.LocalMedia; import com.luck.picture.lib.interfaces.OnGridItemSelectAnimListener; import com.luck.picture.lib.interfaces.OnQueryFilterListener; import com.luck.picture.lib.interfaces.OnSelectAnimListener; import com.luck.picture.lib.entity.MediaExtraInfo; import com.luck.picture.lib.interfaces.OnExternalPreviewEventListener; import com.luck.picture.lib.interfaces.OnKeyValueResultCallbackListener; import com.luck.picture.lib.utils.DateUtils; import com.luck.picture.lib.utils.DensityUtil; import com.luck.picture.lib.utils.MediaUtils; import com.luck.picture.lib.utils.PictureFileUtils; import java.io.File; import java.util.ArrayList; import java.util.List; import top.zibin.luban.CompressionPredicate; import top.zibin.luban.Luban; import top.zibin.luban.OnNewCompressListener; import top.zibin.luban.OnRenameListener; /** * OrderDealDetailActivity - @@ -41,24 +53,28 @@ * @since 2024-11-27 */ public class OrderDealActivity extends BaseActivity { private String TAG = "OrderDealActivity"; ActivityOrderDealBinding binding; RecyclerView mRecyclerView; AddPictureAdapter mAdapter; int maxSelectNum = 10;//最大照片 int maxSelectVideoNum = 0;//最大视频 private final List<LocalMedia> mData = new ArrayList<>(); private ActivityResultLauncher<Intent> launcherResult; private ImageEngine imageEngine; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityOrderDealBinding.inflate(LayoutInflater.from(this)); setContentView(binding.getRoot()); launcherResult = createActivityResultLauncher(); initView(); } void initView() { new TitleBar(this).setTitleText("处理工单").setLeftIco().setLeftIcoListening(v -> OrderDealActivity.this.finish()); mRecyclerView = binding.recycler; FullyGridLayoutManager manager = new FullyGridLayoutManager(this, 4, GridLayoutManager.VERTICAL, false); @@ -72,29 +88,171 @@ mAdapter = new AddPictureAdapter(this, mData); mAdapter.setSelectMax(maxSelectNum + maxSelectVideoNum); mRecyclerView.setAdapter(mAdapter); imageEngine = GlideEngine.createGlideEngine(); mAdapter.setOnItemClickListener(new AddPictureAdapter.OnItemClickListener() { @Override public void onItemClick(View v, int position) { // 预览图片、视频、音频 PictureSelector.create(OrderDealActivity.this) .openPreview() .setImageEngine(imageEngine) .setExternalPreviewEventListener(new MyExternalPreviewEventListener()) .startActivityPreview(position, true, mAdapter.getData()); } @Override public void openPicture() { //添加图片 mOpenPicture(); } }); } /** * 添加图片 */ private void mOpenPicture() { // 进入相册 PictureSelectionModel selectionModel = PictureSelector.create(this) .openGallery(SelectMimeType.ofImage()) .setMaxSelectNum(maxSelectNum) .setMaxVideoSelectNum(maxSelectVideoNum) .setImageEngine(GlideEngine.createGlideEngine()) .setImageEngine(imageEngine) //设置图片压缩 .setCompressEngine(new ImageFileCompressEngine()) .setSelectedData(mAdapter.getData()); selectionModel.forResult(PictureConfig.CHOOSE_REQUEST); selectionModel.forResult(launcherResult); } /** * 创建一个ActivityResultLauncher * * @return */ private ActivityResultLauncher<Intent> createActivityResultLauncher() { return registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { int resultCode = result.getResultCode(); if (resultCode == RESULT_OK) { ArrayList<LocalMedia> selectList = PictureSelector.obtainSelectorList(result.getData()); analyticalSelectResults(selectList); } else if (resultCode == RESULT_CANCELED) { Log.i(TAG, "onActivityResult PictureSelector Cancel"); } }); } /** * 外部预览监听事件 */ private class MyExternalPreviewEventListener implements OnExternalPreviewEventListener { @Override public void onPreviewDelete(int position) { mAdapter.remove(position); mAdapter.notifyItemRemoved(position); } @Override public boolean onLongPressDownload(Context context, LocalMedia media) { return false; } } /** * 处理选择结果 * * @param result */ private void analyticalSelectResults(ArrayList<LocalMedia> result) { for (LocalMedia media : result) { if (media.getWidth() == 0 || media.getHeight() == 0) { if (PictureMimeType.isHasImage(media.getMimeType())) { MediaExtraInfo imageExtraInfo = MediaUtils.getImageSize(this, media.getPath()); media.setWidth(imageExtraInfo.getWidth()); media.setHeight(imageExtraInfo.getHeight()); } else if (PictureMimeType.isHasVideo(media.getMimeType())) { MediaExtraInfo videoExtraInfo = MediaUtils.getVideoSize(this, media.getPath()); media.setWidth(videoExtraInfo.getWidth()); media.setHeight(videoExtraInfo.getHeight()); } } Log.i(TAG, "文件名: " + media.getFileName()); Log.i(TAG, "是否压缩:" + media.isCompressed()); Log.i(TAG, "压缩:" + media.getCompressPath()); Log.i(TAG, "初始路径:" + media.getPath()); Log.i(TAG, "绝对路径:" + media.getRealPath()); Log.i(TAG, "是否裁剪:" + media.isCut()); Log.i(TAG, "裁剪路径:" + media.getCutPath()); Log.i(TAG, "是否开启原图:" + media.isOriginal()); Log.i(TAG, "原图路径:" + media.getOriginalPath()); Log.i(TAG, "沙盒路径:" + media.getSandboxPath()); Log.i(TAG, "水印路径:" + media.getWatermarkPath()); Log.i(TAG, "视频缩略图:" + media.getVideoThumbnailPath()); Log.i(TAG, "原始宽高: " + media.getWidth() + "x" + media.getHeight()); Log.i(TAG, "裁剪宽高: " + media.getCropImageWidth() + "x" + media.getCropImageHeight()); Log.i(TAG, "文件大小: " + PictureFileUtils.formatAccurateUnitFileSize(media.getSize())); Log.i(TAG, "文件时长: " + media.getDuration()); } runOnUiThread(new Runnable() { @Override public void run() { boolean isMaxSize = result.size() == mAdapter.getSelectMax(); int oldSize = mAdapter.getData().size(); mAdapter.notifyItemRangeRemoved(0, isMaxSize ? oldSize + 1 : oldSize); mAdapter.getData().clear(); mAdapter.getData().addAll(result); mAdapter.notifyItemRangeInserted(0, result.size()); } }); } /** * 自定义图片压缩 */ private static class ImageFileCompressEngine implements CompressFileEngine { @Override public void onStartCompress(Context context, ArrayList<Uri> source, OnKeyValueResultCallbackListener call) { Luban.with(context).load(source).ignoreBy(100).setRenameListener(new OnRenameListener() { @Override public String rename(String filePath) { int indexOf = filePath.lastIndexOf("."); String postfix = indexOf != -1 ? filePath.substring(indexOf) : ".jpg"; return DateUtils.getCreateFileName("CMP_") + postfix; } }).filter(new CompressionPredicate() { @Override public boolean apply(String path) { if (PictureMimeType.isUrlHasImage(path) && !PictureMimeType.isHasHttp(path)) { return true; } return !PictureMimeType.isUrlHasGif(path); } }).setCompressListener(new OnNewCompressListener() { @Override public void onStart() { } @Override public void onSuccess(String source, File compressFile) { if (call != null) { call.onCallback(source, compressFile.getAbsolutePath()); } } @Override public void onError(String source, Throwable e) { if (call != null) { call.onCallback(source, null); } } }).launch(); } } app/src/main/java/com/dayu/pipirrapp/activity/OrderDetailActivity.java
@@ -37,7 +37,7 @@ binding = ActivityOrderDetailBinding.inflate(LayoutInflater.from(this)); setContentView(binding.getRoot()); new TitleBar(this).setTitleText("工单详情"); new TitleBar(this).setTitleText("工单详情").setLeftIco().setLeftIcoListening(v -> OrderDetailActivity.this.finish()); initView(); } app/src/main/java/com/dayu/pipirrapp/activity/SplashScreenActivity.java
@@ -30,18 +30,23 @@ binding = ActivitySplashScreenBinding.inflate(LayoutInflater.from(this)); setContentView(binding.getRoot()); new Handler().postDelayed(() -> { // LoginBean loginBean = DaoSingleton.getInstance(SplashScreenActivity.this).loginDao().findFirst(); // String token = SharedPreferencesHelper.getInstance(SplashScreenActivity.this).get(CommonKeyName.Token, ""); // if (loginBean != null && !TextUtils.isEmpty(token)) { // startMainActivity(); // MyApplication.myApplication.token = token; // MyApplication.myApplication.userId = loginBean.getUserID(); // } else { // startLoginActivity(); // } Intent intent = new Intent(this, OrderDealActivity.class); startActivity(intent); SplashScreenActivity.this.finish(); try { LoginBean loginBean = DaoSingleton.getInstance(SplashScreenActivity.this).loginDao().findFirst(); String token = SharedPreferencesHelper.getInstance(SplashScreenActivity.this).get(CommonKeyName.Token, ""); if (loginBean != null && !TextUtils.isEmpty(token)) { startMainActivity(); MyApplication.myApplication.token = token; MyApplication.myApplication.userId = loginBean.getUserID(); } else { startLoginActivity(); } } catch (Exception e) { e.printStackTrace(); startLoginActivity(); } // Intent intent = new Intent(this, OrderDealActivity.class); // startActivity(intent); // SplashScreenActivity.this.finish(); }, 1000); } app/src/main/java/com/dayu/pipirrapp/bean/db/InspectionBean.java
New file @@ -0,0 +1,46 @@ package com.dayu.pipirrapp.bean.db; import androidx.room.Entity; import androidx.room.PrimaryKey; /** * InspectionBean -巡检记录开始时间和结束时间相关信息 * * @author zuoxiao * @version 1.0 * @since 2024-11-29 */ @Entity public class InspectionBean { @PrimaryKey(autoGenerate = true) public long id; String inspectId;//巡检ID String startTime;//开始巡检时间 String stopTime;//停止巡检时间 public String getInspectId() { return inspectId; } public void setInspectId(String inspectId) { this.inspectId = inspectId; } public String getStartTime() { return startTime; } public void setStartTime(String startTime) { this.startTime = startTime; } public String getStopTime() { return stopTime; } public void setStopTime(String stopTime) { this.stopTime = stopTime; } } app/src/main/java/com/dayu/pipirrapp/bean/db/InspectionLocationBean.java
New file @@ -0,0 +1,72 @@ package com.dayu.pipirrapp.bean.db; import androidx.room.Entity; import androidx.room.PrimaryKey; /** * InspectionBean - 巡检记录的坐标相关信息 * * @author zuoxiao * @version 1.0 * @since 2024-11-29 */ @Entity public class InspectionLocationBean { @PrimaryKey(autoGenerate = true) public long id; String inspectorId;//巡检员ID String inspectId;//巡检ID String lng;//经度 String lat;//纬度 String locateTime;//打点时间 boolean isPost;//是否已经上传 public String getInspectorId() { return inspectorId; } public void setInspectorId(String inspectorId) { this.inspectorId = inspectorId; } public String getInspectId() { return inspectId; } public void setInspectId(String inspectId) { this.inspectId = inspectId; } public String getLng() { return lng; } public void setLng(String lng) { this.lng = lng; } public String getLat() { return lat; } public void setLat(String lat) { this.lat = lat; } public String getLocateTime() { return locateTime; } public void setLocateTime(String locateTime) { this.locateTime = locateTime; } public boolean isPost() { return isPost; } public void setPost(boolean post) { isPost = post; } } app/src/main/java/com/dayu/pipirrapp/bean/net/BaseRequest.java
New file @@ -0,0 +1,38 @@ package com.dayu.pipirrapp.bean.net; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; /** * BaseRequest - * * @author zuoxiao * @version 1.0 * @since 2024-12-02 */ public class BaseRequest { /** * 对象转Map * * @param object * @return * @throws IllegalAccessException */ public Map toMap(Object object) { Map<String, Object> map = null; try { map = new HashMap<String, Object>(); Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); if (field.get(object) != null) { map.put(field.getName(), field.get(object)); } } } catch (IllegalAccessException e) { e.printStackTrace(); } return map; } } app/src/main/java/com/dayu/pipirrapp/bean/net/InspectionRequest.java
New file @@ -0,0 +1,104 @@ package com.dayu.pipirrapp.bean.net; import java.util.ArrayList; import java.util.List; /** * InspectionRequest - * * @author zuoxiao * @version 1.0 * @since 2024-12-02 */ public class InspectionRequest extends BaseRequest{ private String inspectorId; private String inspectId; private String startTime; private String stopTime; private List<Track> tracks; public String getInspectorId() { return inspectorId; } public void setInspectorId(String inspectorId) { this.inspectorId = inspectorId; } public String getInspectId() { return inspectId; } public void setInspectId(String inspectId) { this.inspectId = inspectId; } public String getStartTime() { return startTime; } public void setStartTime(String startTime) { this.startTime = startTime; } public String getStopTime() { return stopTime; } public void setStopTime(String stopTime) { this.stopTime = stopTime; } public List<Track> getTracks() { return tracks; } public void setTracks(List<Track> tracks) { this.tracks = tracks; } public void addTracks(Track track) { if (tracks == null) { tracks = new ArrayList<>(); } tracks.add(track); } // Track 数据类 public static class Track { private String lng; private String lat; private String locateTime; public String getLng() { return lng; } public void setLng(String lng) { this.lng = lng; } public String getLat() { return lat; } public void setLat(String lat) { this.lat = lat; } public String getLocateTime() { return locateTime; } public void setLocateTime(String locateTime) { this.locateTime = locateTime; } } } app/src/main/java/com/dayu/pipirrapp/bean/net/UplodFileState.java
New file @@ -0,0 +1,56 @@ package com.dayu.pipirrapp.bean.net; import java.io.File; /** * Copyright (C), 2023, * Author: zuo * Date: 2023-04-15 8:15 * Description: */ public class UplodFileState { int state = 0;//0正在上传 1上传完成 2上传失败 File file;//上传的文件 String url;//上传文件后返回的url int number;//失败后重试的次数 public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public UplodFileState() { } public UplodFileState(File file) { this.file = file; } public int getState() { return state; } public void setState(int state) { this.state = state; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } app/src/main/java/com/dayu/pipirrapp/dao/AppDatabase.java
@@ -4,10 +4,11 @@ import androidx.room.RoomDatabase; import com.dayu.pipirrapp.bean.db.CenterPointBean; import com.dayu.pipirrapp.bean.db.InspectionBean; import com.dayu.pipirrapp.bean.db.InspectionLocationBean; import com.dayu.pipirrapp.bean.db.LoginBean; import com.dayu.pipirrapp.bean.db.MarkerBean; import com.dayu.pipirrapp.bean.db.TagBean; /** @@ -16,7 +17,7 @@ * Date: 2023-11-05 16:23 * Description: */ @Database(entities = {TagBean.class, LoginBean.class, CenterPointBean.class, MarkerBean.class}, version = 1, exportSchema = false) @Database(entities = {InspectionBean.class,InspectionLocationBean.class, TagBean.class, LoginBean.class, CenterPointBean.class, MarkerBean.class}, version = 1, exportSchema = false) public abstract class AppDatabase extends RoomDatabase { @@ -28,4 +29,8 @@ public abstract MarkerDao markerDao(); public abstract InspectionDao inspectionDao(); public abstract InspectionLocationDao inspectionLocationDao(); } app/src/main/java/com/dayu/pipirrapp/dao/DaoSingleton.java
@@ -14,8 +14,8 @@ * Description: 创建数据库实例 */ public class DaoSingleton { public static AppDatabase baseDao; public static AppDatabase AsynchBaseDao; private static AppDatabase baseDao; private static AppDatabase AsynchBaseDao; public static String name = "dayu_data"; //MyFileUtil.SqlitePath + app/src/main/java/com/dayu/pipirrapp/dao/InspectionDao.java
New file @@ -0,0 +1,34 @@ package com.dayu.pipirrapp.dao; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.OnConflictStrategy; import androidx.room.Query; import androidx.room.Update; import com.dayu.pipirrapp.bean.db.InspectionBean; import io.reactivex.rxjava3.core.Completable; import io.reactivex.rxjava3.core.Single; @Dao public interface InspectionDao { @Insert(onConflict = OnConflictStrategy.REPLACE) Completable insert(InspectionBean inspectionBean); @Update void update(InspectionBean inspectionBean); @Delete void delete(InspectionBean inspectionBean); @Query("DELETE FROM InspectionBean") void deleteAll(); //查询当前没有关闭巡检的巡检ID @Query("SELECT * FROM InspectionBean WHERE stopTime IS NULL OR stopTime = '' ORDER BY startTime DESC LIMIT 1") Single<InspectionBean> getMostRecentInspectionWithNoStopTime(); } app/src/main/java/com/dayu/pipirrapp/dao/InspectionLocationDao.java
New file @@ -0,0 +1,36 @@ package com.dayu.pipirrapp.dao; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.OnConflictStrategy; import androidx.room.Query; import androidx.room.Update; import com.dayu.pipirrapp.bean.db.InspectionLocationBean; import java.util.List; import io.reactivex.rxjava3.core.Completable; @Dao public interface InspectionLocationDao { @Insert(onConflict = OnConflictStrategy.REPLACE) Completable insert(InspectionLocationBean inspectionLocationBean); @Update Completable update(InspectionLocationBean inspectionLocationBean); @Delete void delete(InspectionLocationBean inspectionLocationBean); @Query("DELETE FROM InspectionLocationBean") void deleteAll(); @Query("select * from InspectionLocationBean limit 1") InspectionLocationBean findFirst(); //查询所有没有上传的坐标 @Query("select * from InspectionLocationBean where isPost=false") List<InspectionLocationBean> findByNoPost(); } app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java
@@ -1,10 +1,15 @@ package com.dayu.pipirrapp.fragment; import static com.dayu.pipirrapp.net.Constants.BASE_URL; import static com.dayu.pipirrapp.tool.InspectionUtils.addInspectionLocationData; import static com.dayu.pipirrapp.tool.InspectionUtils.updateInspectionLocationData; import android.content.Context; import android.content.Intent; import android.location.LocationManager; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -20,10 +25,15 @@ import androidx.annotation.Nullable; import androidx.lifecycle.Observer; import com.dayu.pipirrapp.MyApplication; import com.dayu.pipirrapp.bean.db.CenterPointBean; import com.dayu.pipirrapp.bean.db.InspectionBean; import com.dayu.pipirrapp.bean.db.InspectionLocationBean; import com.dayu.pipirrapp.bean.db.LatLonBean; import com.dayu.pipirrapp.bean.db.MarkerBean; import com.dayu.pipirrapp.bean.net.CenterPointResult; import com.dayu.pipirrapp.bean.net.InspectionRequest; import com.dayu.pipirrapp.bean.net.LoginResult; import com.dayu.pipirrapp.bean.net.MarkerResult; import com.dayu.pipirrapp.dao.DaoSingleton; import com.dayu.pipirrapp.databinding.FragmentMapBinding; @@ -34,8 +44,10 @@ import com.dayu.pipirrapp.net.subscribers.SubscriberListener; import com.dayu.pipirrapp.observer.MapFragmenObserver; import com.dayu.pipirrapp.service.MyLocationService; import com.dayu.pipirrapp.tool.InspectionUtils; import com.dayu.pipirrapp.utils.CommonData; import com.dayu.pipirrapp.utils.CommonKeyName; import com.dayu.pipirrapp.utils.DateUtils; import com.dayu.pipirrapp.utils.MapJpgUtils; import com.dayu.pipirrapp.utils.MyLog; import com.dayu.pipirrapp.utils.SharedPreferencesHelper; @@ -43,12 +55,15 @@ import com.dayu.pipirrapp.utils.WebViewUtils; import com.dayu.pipirrapp.view.ConfirmDialog; import com.jeremyliao.liveeventbus.LiveEventBus; import com.tencent.bugly.crashreport.CrashReport; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; @@ -70,8 +85,13 @@ WebView mWebView; CenterPointBean centerPointBean; String strMarkerJson; //是否显示 boolean isStartInspec = false; MapFragmenObserver mapFragmenObserver; //当前巡检记录的相关信息 InspectionBean mInspectionBean; LatLonBean lastLatLonBean; InspectionRequest inspectionRequest; @Override public void onAttach(@NonNull Context context) { @@ -86,48 +106,12 @@ super.onCreate(savedInstanceState); Log.i(TAG, "onCreate"); isStartInspec = SharedPreferencesHelper.getInstance(this.getContext()).get(CommonKeyName.isStartInspec, false); } @Override public void onStart() { super.onStart(); Log.i(TAG, "onStart"); } /** * 修改巡检状态 */ private void chageInspecState() { Intent location = new Intent(this.getActivity(), MyLocationService.class); location.putExtra("isSingle", false); if (isStartInspec) { //获取定位服务传过来的坐标点 LiveEventBus.get(CommonKeyName.locationData).observeForever(new Observer<Object>() { @Override public void onChanged(Object o) { LatLonBean latLonBean = (LatLonBean) o; Log.i("chageInspecState", "lat:" + latLonBean.getLatitude() + ",log:" + latLonBean.getLongitude()); mWebView.evaluateJavascript("javascript:updateLocation(\"" + latLonBean.getLatitude() + "\",\"" + latLonBean.getLongitude() + "\")", value -> { }); } }); binding.stateText.setVisibility(View.VISIBLE); binding.inspectButton.setText("终"); //开启定位 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { this.getActivity().startForegroundService(location); } else { this.getActivity().startService(location); } } else { binding.stateText.setVisibility(View.GONE); binding.inspectButton.setText("巡"); //关闭定位 this.getActivity().stopService(location); } } @@ -396,5 +380,125 @@ binding.bottomLL.setVisibility(View.GONE); } /** * 上报巡检记录 */ private void pushLocationData(InspectionLocationBean inspectionLocationBean) { inspectionRequest.setInspectId(inspectionLocationBean.getInspectId()); inspectionRequest.setInspectorId(inspectionLocationBean.getInspectorId()); if (mInspectionBean != null) { inspectionRequest.setStartTime(mInspectionBean.getStartTime()); inspectionRequest.setStopTime(mInspectionBean.getStopTime()); } InspectionRequest.Track track = new InspectionRequest.Track(); track.setLat(inspectionLocationBean.getLat()); track.setLng(inspectionLocationBean.getLng()); track.setLocateTime(inspectionLocationBean.getLocateTime()); inspectionRequest.getTracks().clear(); inspectionRequest.addTracks(track); ApiManager.getInstance().requestPostHideLoading(MapFragment.this.getContext(), BASE_URL + "/app/inspect/save", LoginResult.class, inspectionRequest.toMap(inspectionRequest), new SubscriberListener<BaseResponse<LoginResult>>() { @Override public void onNext(BaseResponse<LoginResult> t) { try { if (t.isSuccess()) { inspectionLocationBean.setPost(true); updateInspectionLocationData(MapFragment.this.getContext(), inspectionLocationBean); } else { } } catch (Exception e) { e.printStackTrace(); CrashReport.postCatchedException(e); } } }); } /** * 开始巡检 */ private void startInspection() { DaoSingleton.getAsynchInstance(this.getContext()).inspectionDao().getMostRecentInspectionWithNoStopTime() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()).subscribe(inspectionBean -> { // 更新 UI mInspectionBean = inspectionBean; }); } /** * 定位监听 */ private Observer<Object> locationObserver = new Observer<Object>() { @Override public void onChanged(Object o) { if (mInspectionBean != null) { LatLonBean latLonBean = (LatLonBean) o; if (InspectionUtils.isThanMinMeters(lastLatLonBean, latLonBean)) { //大于最小距离 lastLatLonBean = latLonBean; Log.i("chageInspecState", "lat:" + latLonBean.getLatitude() + ",log:" + latLonBean.getLongitude()); InspectionLocationBean inspectionLocationBean = createInspectionLocation(latLonBean); addInspectionLocationData(MapFragment.this.getContext(), inspectionLocationBean); //更新到地图 mWebView.evaluateJavascript("javascript:updateLocation(\"" + latLonBean.getLongitude() + "\",\"" + latLonBean.getLatitude() + "\")", value -> { }); //上传坐标 pushLocationData(inspectionLocationBean); } else { Log.d(TAG, "isThanMinMeters>>>false"); } } } }; /** * 创建InspectionLocationBean */ private InspectionLocationBean createInspectionLocation(LatLonBean latLonBean) { InspectionLocationBean inspectionLocationBean = new InspectionLocationBean(); inspectionLocationBean.setInspectId(mInspectionBean.getInspectId()); inspectionLocationBean.setLocateTime(DateUtils.getNowDateStr()); inspectionLocationBean.setPost(false); inspectionLocationBean.setInspectorId(MyApplication.myApplication.userId); inspectionLocationBean.setLng(String.valueOf(latLonBean.getLongitude())); inspectionLocationBean.setLat(String.valueOf(latLonBean.getLatitude())); return inspectionLocationBean; } /** * 修改巡检状态 */ private void chageInspecState() { Intent location = new Intent(this.getActivity(), MyLocationService.class); location.putExtra("isSingle", false); if (isStartInspec) { //添加新的巡检记录 startInspection(); //获取定位服务传过来的坐标点 LiveEventBus.get(CommonKeyName.locationData).observeForever(locationObserver); binding.stateText.setVisibility(View.VISIBLE); binding.inspectButton.setText("终"); //开启定位 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { this.getActivity().startForegroundService(location); } else { this.getActivity().startService(location); } mInspectionBean = InspectionUtils.startInspection(this.getContext()); inspectionRequest = new InspectionRequest(); } else { binding.stateText.setVisibility(View.GONE); binding.inspectButton.setText("巡"); LiveEventBus.get(CommonKeyName.locationData).removeObserver(locationObserver); //关闭定位 this.getActivity().stopService(location); } } } app/src/main/java/com/dayu/pipirrapp/fragment/MyFragment.java
@@ -19,7 +19,6 @@ import com.dayu.pipirrapp.utils.CleanDataUtils; import com.dayu.pipirrapp.utils.ToastUtil; import com.dayu.pipirrapp.view.ConfirmDialog; import com.dayu.pipirrapp.view.TitleBar; /** * author: zuo app/src/main/java/com/dayu/pipirrapp/fragment/OrderFragment.java
@@ -16,7 +16,6 @@ import com.dayu.pipirrapp.activity.OrderDetailActivity; import com.dayu.pipirrapp.adapter.OrderAdapter; import com.dayu.pipirrapp.bean.net.OrderListResult; import com.dayu.pipirrapp.bean.net.WeatherResponse; import com.dayu.pipirrapp.databinding.FragmentOrderBinding; import com.dayu.pipirrapp.net.ApiManager; import com.dayu.pipirrapp.net.BaseResponse; app/src/main/java/com/dayu/pipirrapp/net/ApiManager.java
@@ -9,11 +9,13 @@ import com.dayu.pipirrapp.MyApplication; import com.dayu.pipirrapp.bean.net.CodeResult; import com.dayu.pipirrapp.bean.net.UplodFileState; import com.dayu.pipirrapp.bean.net.WeatherResponse; import com.dayu.pipirrapp.net.subscribers.BaseProgressSubscriber; import com.dayu.pipirrapp.net.subscribers.CodeListener; import com.dayu.pipirrapp.net.subscribers.ProgressSubscriber; import com.dayu.pipirrapp.net.subscribers.SubscriberListener; import com.dayu.pipirrapp.net.upload.UploadFileListener; import com.dayu.pipirrapp.utils.MapJpgUtils; import com.dayu.pipirrapp.utils.MyJsonParser; @@ -26,9 +28,13 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.functions.Function; import io.reactivex.rxjava3.schedulers.Schedulers; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.RequestBody; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; /** @@ -285,4 +291,57 @@ return false; // 无网络连接 } /** * 上传文件 * * @param context * @param file * @param listener */ public void uploadFile(final Context context, final UplodFileState file, final UploadFileListener listener) { // 创建 RequestBody,用于封装构建RequestBody RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file.getFile()); // MultipartBody.Part 和后端约定好Key,这里的partName是用image MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getFile().getName(), requestFile); // 添加描述 String descriptionString = "hello, 这是文件描述"; RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString); apiService.uploadFile(description, body).enqueue(new Callback<BaseResponse>() { @Override public void onResponse(Call<BaseResponse> call, Response<BaseResponse> response) { if (response.body() != null) { if (response.body().isSuccess()) { file.setState(1); file.setUrl(response.body().getMsg()); listener.onBack(file); } else { if (file.getNumber() <= uplodFilerepeatSize) { file.setNumber(file.getNumber() + 1); file.setState(2); uploadFile(context, file, listener); } else { listener.onBack(file); } } } } @Override public void onFailure(Call<BaseResponse> call, Throwable t) { if (file.getNumber() <= uplodFilerepeatSize) { file.setNumber(file.getNumber() + 1); file.setState(2); uploadFile(context, file, listener); } else { listener.onBack(file); } } }); } } app/src/main/java/com/dayu/pipirrapp/net/ApiService.java
@@ -58,11 +58,11 @@ Call<BaseResponse> uploadFiles(@PartMap Map<String, RequestBody> map); @Multipart @POST(Constants.BASE_URL + "file/upload") @POST(Constants.BASE_URL + "app/webFile/upPhoto") Call<BaseResponse> uploadFile(@Part("description") RequestBody description, @Part MultipartBody.Part file); //获取验证码 @GET(Constants.BASE_URL+":8088/app/captcha/get") @GET(Constants.BASE_URL+"/app/captcha/get") Observable<CodeResult> getCode(@QueryMap Map<String, Object> params); @GET() app/src/main/java/com/dayu/pipirrapp/net/MyIntercepterApplication.java
@@ -1,11 +1,8 @@ package com.dayu.pipirrapp.net; import com.dayu.pipirrapp.MyApplication; import com.dayu.pipirrapp.utils.CommonData; import com.dayu.pipirrapp.utils.SharedPreferencesHelper; import com.dayu.pipirrapp.utils.ToastUtil; import com.tencent.bugly.crashreport.CrashReport; import java.io.IOException; import java.net.ConnectException; @@ -68,7 +65,7 @@ } } builder.addHeader("os", "app"); builder.addHeader("Authorization", SharedPreferencesHelper.getInstance(MyApplication.myApplication).get("token", "")); builder.addHeader("token", MyApplication.myApplication.token); } builder.addHeader("tag", MyApplication.myApplication.myTag); return builder.build(); app/src/main/java/com/dayu/pipirrapp/net/upload/ProgressListener.java
New file @@ -0,0 +1,5 @@ package com.dayu.pipirrapp.net.upload; public interface ProgressListener { void onProgress(long bytesWritten, long totalBytes); } app/src/main/java/com/dayu/pipirrapp/net/upload/ProgressRequestBody.java
New file @@ -0,0 +1,53 @@ package com.dayu.pipirrapp.net.upload; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import okhttp3.MediaType; import okhttp3.RequestBody; import okio.BufferedSink; import okio.BufferedSource; import okio.Okio; /** * ProgressRequestBody - * * @author zuoxiao * @version 1.0 * @since 2024-11-28 */ public class ProgressRequestBody extends RequestBody { private File file; private ProgressListener listener; private MediaType mediaType; public ProgressRequestBody(File file, ProgressListener listener, String mimeType) { this.file = file; this.listener = listener; this.mediaType = MediaType.parse(mimeType); } @Override public MediaType contentType() { return mediaType; } @Override public void writeTo(BufferedSink sink) throws IOException { try (FileInputStream fileInputStream = new FileInputStream(file); BufferedSource source = (BufferedSource) Okio.source(fileInputStream)) { long totalBytes = file.length(); long bytesWritten = 0; long read; byte[] buffer = new byte[2048]; while ((read = source.read(buffer)) != -1) { sink.write(buffer, 0, (int) read); bytesWritten += read; if (listener != null) { listener.onProgress(bytesWritten, totalBytes); } } } } } app/src/main/java/com/dayu/pipirrapp/net/upload/UploadFileListener.java
New file @@ -0,0 +1,14 @@ package com.dayu.pipirrapp.net.upload; import com.dayu.pipirrapp.bean.net.UplodFileState; /** * Copyright (C), 2023, * Author: zuo * Date: 2023-04-15 8:27 * Description: */ public interface UploadFileListener { void onBack(UplodFileState state); } app/src/main/java/com/dayu/pipirrapp/service/MyLocationService.java
@@ -225,7 +225,7 @@ if (isSingle) { stopSelf(); // 获取到经纬度以后,停止该service } ToastUtil.showToast(MyLocationService.this, "原生定位onLocationChanged: Latitude:" + latitude + " Longitude:" + longitude); // ToastUtil.showToast(MyLocationService.this, "原生定位onLocationChanged: Latitude:" + latitude + " Longitude:" + longitude); } // 状态改变时 app/src/main/java/com/dayu/pipirrapp/tool/FullyGridLayoutManager.java
@@ -10,7 +10,7 @@ /** * FullyGridLayoutManager - * * 自定义Grid用以显示 * @author zuoxiao * @version 1.0 * @since 2024-11-28 app/src/main/java/com/dayu/pipirrapp/tool/InspectionUtils.java
New file @@ -0,0 +1,112 @@ package com.dayu.pipirrapp.tool; import android.content.Context; import android.location.Location; import android.util.Log; import com.dayu.pipirrapp.bean.db.InspectionBean; import com.dayu.pipirrapp.bean.db.InspectionLocationBean; import com.dayu.pipirrapp.bean.db.LatLonBean; import com.dayu.pipirrapp.dao.DaoSingleton; import com.dayu.pipirrapp.utils.DateUtils; import java.util.UUID; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.schedulers.Schedulers; /** * InspectionUtils -巡检记录相关功能合集 * * @author zuoxiao * @version 1.0 * @since 2024-11-29 */ public class InspectionUtils { private static final String TAG = "InspectionUtils"; //打点的最小两点最小距离 private static final int MinMeters = 10; /** * 获取当前巡检记录ID * * @param context * @return */ public static String getInspectionId(Context context) { return ""; } /** * 开始巡检并插入巡检记录 * * @param context 上下文 * @return Completable 表示插入完成或失败的流 */ public static InspectionBean startInspection(Context context) { // 创建巡检记录 InspectionBean inspectionBean = new InspectionBean(); inspectionBean.setInspectId(UUID.randomUUID().toString()); inspectionBean.setStartTime(DateUtils.getNowDateStr()); // 异步插入到数据库 DaoSingleton.getAsynchInstance(context) .inspectionDao() .insert(inspectionBean) // 插入操作 .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(() -> { Log.i(TAG, "Inspection started and inserted successfully."); }, throwable -> { Log.e(TAG, "Error inserting inspection data: ", throwable); }); // 获取Dao并执行插入操作 return inspectionBean; // 插入完成后切换到主线程 } /** * 添加巡检记录坐标 * * @param context * @param locationBean */ public static void addInspectionLocationData(Context context, InspectionLocationBean locationBean) { DaoSingleton.getAsynchInstance(context).inspectionLocationDao().insert(locationBean).subscribeOn(Schedulers.io()); } /** * 修改巡检记录坐标 * * @param context * @param locationBean */ public static void updateInspectionLocationData(Context context, InspectionLocationBean locationBean) { DaoSingleton.getAsynchInstance(context).inspectionLocationDao().update(locationBean).subscribeOn(Schedulers.io()); } /** * 判断两个地点的距离是否大于设定的最小距离 * * @param lastLocation 第一个地点 * @param newLocation 第二个地点 * @return 如果距离大于10米,返回true,否则返回false */ public static boolean isThanMinMeters(LatLonBean lastLocation, LatLonBean newLocation) { //当lastLocation为null默认认为返回true if (lastLocation != null) { // 使用 Location.distanceBetween 计算两个点之间的距离,单位为米 float[] results = new float[1]; Location.distanceBetween(lastLocation.getLatitude(), lastLocation.getLongitude(), newLocation.getLatitude(), newLocation.getLongitude(), results); float distanceInMeters = results[0]; // 判断距离是否大于10米 return distanceInMeters > MinMeters; } else { return true; } } } app/src/main/java/com/dayu/pipirrapp/utils/DateUtils.java
New file @@ -0,0 +1,32 @@ package com.dayu.pipirrapp.utils; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; /** * DateUtils - 处理时间统一的类 * * @author zuoxiao * @version 1.0 * @since 2024-11-29 */ public class DateUtils { /** * 返回统一格式的当前时间 * * @return yyyy-MM-dd HH:mm:ss */ public static String getNowDateStr() { // 当前时间 Date date = new Date(); // 创建 SimpleDateFormat 对象,设置日期格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); // 格式化当前时间为字符串 return sdf.format(date); } } app/src/main/java/com/dayu/pipirrapp/view/TagDialog.java
@@ -78,6 +78,7 @@ @Override public void onClick(View v) { MyApplication.myApplication.myTag = tagBean.getTag(); tagDao.insert(tagBean); mLibraryBack.listener(type); TagDialog.this.dismiss(); app/src/main/java/com/dayu/pipirrapp/view/TitleBar.java
@@ -4,14 +4,9 @@ package com.dayu.pipirrapp.view; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; @@ -194,6 +189,7 @@ * @return */ public TitleBar setRightIcoListening(View.OnClickListener listener) { if (iv_rightIco.getVisibility() == View.VISIBLE) { iv_rightIco.setOnClickListener(listener); } app/src/main/res/layout/activity_order_deal.xml
@@ -16,6 +16,7 @@ <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/bg_color" android:orientation="vertical"> <include @@ -58,6 +59,8 @@ android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp" android:background="@color/white" android:layout_marginTop="10dp" android:overScrollMode="never" />