管灌系统巡查员智能手机App
zuoxiao
2024-12-02 3ac1a2854f23f61c61e537ea6a7add0c9a70438e
1.上传巡检定位点相关功能
2.上传文件相关
21个文件已修改
12个文件已添加
1108 ■■■■■ 已修改文件
app/build.gradle 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/assets/js/map.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/MyApplication.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/activity/LoginActivity.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/activity/MainActivity.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/activity/OrderDealActivity.java 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/activity/OrderDetailActivity.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/activity/SplashScreenActivity.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/bean/db/InspectionBean.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/bean/db/InspectionLocationBean.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/bean/net/BaseRequest.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/bean/net/InspectionRequest.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/bean/net/UplodFileState.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/dao/AppDatabase.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/dao/DaoSingleton.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/dao/InspectionDao.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/dao/InspectionLocationDao.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/fragment/MapFragment.java 176 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/fragment/MyFragment.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/fragment/OrderFragment.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/net/ApiManager.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/net/ApiService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/net/MyIntercepterApplication.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/net/upload/ProgressListener.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/net/upload/ProgressRequestBody.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/net/upload/UploadFileListener.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/service/MyLocationService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/tool/FullyGridLayoutManager.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/tool/InspectionUtils.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/utils/DateUtils.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/view/TagDialog.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/pipirrapp/view/TitleBar.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_order_deal.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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" />