diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 481bb43..089bc05 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -18,4 +18,262 @@ # If you keep the line number information, uncomment this to # hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file +#-renamesourcefileattribute SourceFile + +-dontwarn java.lang.invoke.StringConcatFactory + +# 保留行号用于调试 +-keepattributes SourceFile,LineNumberTable +-renamesourcefileattribute SourceFile + +# 保留基本属性 +-keepattributes Signature +-keepattributes *Annotation* +-keepattributes Exceptions +-keepattributes InnerClasses + +-dontwarn com.github.luben.zstd.BufferPool +-dontwarn com.github.luben.zstd.ZstdInputStream +-dontwarn com.github.luben.zstd.ZstdOutputStream +-dontwarn org.brotli.dec.BrotliInputStream +-dontwarn org.objectweb.asm.AnnotationVisitor +-dontwarn org.objectweb.asm.Attribute +-dontwarn org.objectweb.asm.ClassReader +-dontwarn org.objectweb.asm.ClassVisitor +-dontwarn org.objectweb.asm.FieldVisitor +-dontwarn org.objectweb.asm.Label +-dontwarn org.objectweb.asm.MethodVisitor +-dontwarn org.objectweb.asm.Type + +# 保留R文件 +-keepclassmembers class **.R$* { + public static ; +} + +## 保留servicing模块中的所有model类 +#-keep class com.za.bean.** { *; } +#-keep class com.za.bean.db.** { *; } +#-keep class com.za.bean.request.** { *; } +# +## 保留servicing模块中的所有接口 +#-keep interface com.za.servicing.** { *; } +#-keep interface com.za.net.** { *; } +# +## 保留servicing模块中的所有枚举 +#-keepclassmembers enum com.za.** { *; } +# +## 保留Room数据库相关类 +#-keep class com.za.room.** { *; } +#-keep class com.za.room.db.** { *; } +#-keep class * extends androidx.room.RoomDatabase +#-keep @androidx.room.Entity class * +#-keep @androidx.room.Dao interface * + +# 保留Parcelable实现类 +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +# 保留Serializable实现类 +-keepnames class * implements java.io.Serializable +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} + +# 保留WebView相关 +-keepclassmembers class * extends android.webkit.WebViewClient { + public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); + public boolean *(android.webkit.WebView, java.lang.String); +} +-keepclassmembers class * extends android.webkit.WebViewClient { + public void *(android.webkit.WebView, java.lang.String); +} + +# 保留native方法 +-keepclasseswithmembernames class * { + native ; +} + +## 保留View的getter和setter +#-keepclassmembers public class * extends android.view.View { +# void set*(***); *** get*(); +#} + +# CameraX相关 +#-keep class androidx.camera.** { *; } +#-dontwarn androidx.camera.** +# +## Coil图片加载库 +#-keep class coil.** { *; } +#-dontwarn coil.** +# +## PermissionX权限库 +#-keep class com.permissionx.guolindev.** { *; } +# +## 高德地图相关 +#-keep class com.amap.api.**{*;} +#-keep class com.autonavi.**{*;} +#-keep class com.loc.**{*;} +#-dontwarn com.amap.api.** +#-dontwarn com.autonavi.** +#-dontwarn com.loc.** +# +## JPush相关 +#-dontoptimize +#-dontwarn cn.jpush.** +#-keep class cn.jpush.** { *; } +#-dontwarn cn.jcore.** +#-keep class cn.jcore.** { *; } +# +## Retrofit网络库 +#-keepattributes Signature +#-keepattributes Exceptions +#-dontwarn retrofit2.** +#-keep class retrofit2.** { *; } +#-keepclasseswithmembers class * { +# @retrofit2.http.* ; +#} +# +## OkHttp +#-dontwarn okhttp3.** +#-dontwarn okio.** +#-keep class okhttp3.** { *; } +#-keep class okio.** { *; } +# +## RxJava +#-dontwarn io.reactivex.** +#-keep class io.reactivex.** { *; } +#-dontwarn sun.misc.** +#-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { +# long producerIndex; +# long consumerIndex; +#} +# +## BlankJ工具库 +#-dontwarn com.blankj.utilcode.** +#-keep class com.blankj.utilcode.** { *; } +#-keepclassmembers class * { +# @com.blankj.utilcode.util.BusUtils$Bus ; +#} +#-keep public class * extends com.blankj.utilcode.util.ApiUtils$BaseApi +#-keep,allowobfuscation @interface com.blankj.utilcode.util.ApiUtils$Api +#-keep @com.blankj.utilcode.util.ApiUtils$Api class * +# +##mmkv +#-renamesourcefileattribute SourceFile +#-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,EnclosingMethod +#-keep public class * { +# public protected *; +#} +## +### 保留所有类的方法名 +##-keepclassmembernames class * { +## java.lang.Class class$(java.lang.String); +## java.lang.Class class$(java.lang.String, boolean); +##} +# +## 保留枚举类中的特殊静态方法 +#-keepclassmembers class * extends java.lang.Enum { +# public static **[] values(); +# public static ** valueOf(java.lang.String); +#} +# +## MQTT相关 +#-keep class org.eclipse.paho.** { *; } +#-dontwarn org.eclipse.paho.** +# +## Gson +#-keep class com.google.gson.** { *; } +#-keepattributes Signature +#-keepattributes *Annotation* +#-keep class * implements com.google.gson.TypeAdapterFactory +#-keep class * implements com.google.gson.JsonSerializer +#-keep class * implements com.google.gson.JsonDeserializer +# +### Kotlin相关 +###-keep class kotlin.** { *; } +##-keep class kotlin.Metadata { *; } +##-dontwarn kotlin.** +##-keepclassmembers class **$WhenMappings { +## ; +##} +##-keepclassmembers class kotlin.Metadata { +## public ; +##} +# +## Kotlin协程 +##-keepclassmembernames class kotlinx.** { +## volatile ; +##} +##-keepclassmembers class * { +## @kotlin.coroutines.jvm.internal.DebugMetadata *; +## @kotlin.coroutines.jvm.internal.SuspendLambda *; +##} +##-keep class kotlinx.coroutines.** { *; } +##-dontwarn kotlinx.coroutines.** +# +## Kotlin反射 +##-keep class kotlin.reflect.** { *; } +##-dontwarn kotlin.reflect.** +# +## 保留Kotlin数据类 +##-keepclassmembers class ** { +## public ** component*(); +## public ** copy(...); +##} +# +## 保留Kotlin数据类的toString/hashCode/equals方法 +##-keepclassmembers class ** { +## public java.lang.String toString(); +## public int hashCode(); +## public boolean equals(java.lang.Object); +##} +## +### 保留Compose相关 +##-keep class androidx.compose.** { *; } +##-dontwarn androidx.compose.** +## +### 保留自定义签名相关类 +##-keep class com.za.signature.** { *; } +## +### 保留Face Detection相关 +##-keep class com.google.mlkit.** { *; } +##-dontwarn com.google.mlkit.** +# +## 保留ZXing相关 +#-keep class com.google.zxing.** { *; } +#-dontwarn com.google.zxing.** +# +## 保留Glide相关 +#-keep public class * implements com.bumptech.glide.module.GlideModule +#-keep class * extends com.bumptech.glide.module.AppGlideModule { +# (...); +#} +#-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { +# **[] $VALUES; +# public *; +#} +#-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { +# *** rewind(); +#} +# +## 保留FastJSON相关 +#-keep class com.alibaba.fastjson.** { *; } +#-dontwarn com.alibaba.fastjson.** +# +## 保留Bugly相关 +#-keep class com.tencent.bugly.** { *; } +#-dontwarn com.tencent.bugly.** +## +### 保留自定义UI组件 +###-keep class com.za.ui.** { *; } +###-keep class com.za.base.** { *; } +## +### 保留Java 8 Lambda表达式 +##-dontwarn java.lang.invoke.StringConcatFactory \ No newline at end of file diff --git a/app/src/androidTest/java/com/za/sdk/demo/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/za/sdk/demo/ExampleInstrumentedTest.kt deleted file mode 100644 index 6347d32..0000000 --- a/app/src/androidTest/java/com/za/sdk/demo/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.za.sdk.demo - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.za.sdk.demo", appContext.packageName) - } -} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d08f376..e83bc5e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,4 +1,5 @@ [versions] +accompanistPager = "0.32.0" cameraCore = "1.4.1" coilCompose = "2.6.0" commonsCompress = "1.23.0" @@ -6,15 +7,13 @@ compiler = "4.14.2" converterGson = "2.9.0" core = "3.5.3" crashreport = "4.0.4" +faceDetection = "16.1.7" fastjson = "1.2.69" glide = "4.16.0" gson = "2.11.0" -jcore = "5.0.0" -faceDetection = "16.1.7" jpush = "5.6.0" location = "5.6.1" loggingInterceptor = "4.11.0" -#这是一个长期维护的版本,不建议升级 mmkv = "1.3.11" orgEclipsePahoAndroidService = "1.1.1" orgEclipsePahoClientMqttv3 = "1.2.5" @@ -39,14 +38,19 @@ rxjava = "3.1.7" search = "7.3.0" tbssdk = "44286" uiGraphics = "1.7.7" +uiTooling = "1.7.7" uiToolingPreview = "1.7.7" uiVersion = "1.7.7" utilcodex = "1.31.1" workRuntimeKtx = "2.10.0" xdmap = "8.1.0" +activity = "1.10.0" xz = "1.9" exifinterface = "1.3.7" +uiToolingVersion = "1.4.0" [libraries] +accompanist-pager = { module = "com.google.accompanist:accompanist-pager", version.ref = "accompanistPager" } +accompanist-pager-indicators = { module = "com.google.accompanist:accompanist-pager-indicators", version.ref = "accompanistPager" } adapter-rxjava3 = { module = "com.squareup.retrofit2:adapter-rxjava3", version.ref = "converterGson" } androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraCore" } androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "cameraCore" } @@ -60,6 +64,7 @@ androidx-ui = { module = "androidx.compose.ui:ui", version.ref = "uiVersion" } androidx-ui-graphics = { module = "androidx.compose.ui:ui-graphics", version.ref = "uiGraphics" } androidx-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "uiGraphics" } androidx-ui-test-manifest = { module = "androidx.compose.ui:ui-test-manifest", version.ref = "uiGraphics" } +androidx-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "uiTooling" } androidx-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "uiToolingPreview" } androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" } coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" } @@ -69,6 +74,7 @@ compiler = { module = "com.github.bumptech.glide:compiler", version.ref = "compi converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" } core = { module = "com.google.zxing:core", version.ref = "core" } crashreport = { module = "com.tencent.bugly:crashreport", version.ref = "crashreport" } +face-detection = { module = "com.google.mlkit:face-detection", version.ref = "faceDetection" } fastjson = { module = "com.alibaba:fastjson", version.ref = "fastjson" } glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" } @@ -96,12 +102,13 @@ search = { module = "com.amap.api:search", version.ref = "search" } tbssdk = { module = "com.tencent.tbs:tbssdk", version.ref = "tbssdk" } utilcodex = { module = "com.blankj:utilcodex", version.ref = "utilcodex" } xdmap = { module = "com.amap.api:3dmap", version.ref = "xdmap" } +androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } xz = { module = "org.tukaani:xz", version.ref = "xz" } androidx-exifinterface = { group = "androidx.exifinterface", name = "exifinterface", version.ref = "exifinterface" } -face-detection = { module = "com.google.mlkit:face-detection", version.ref = "faceDetection" } -ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiToolingPreview" } +ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiToolingVersion" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } android-library = { id = "com.android.library", version.ref = "agp" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } diff --git a/servicing/build.gradle b/servicing/build.gradle index b8d2164..193a911 100644 --- a/servicing/build.gradle +++ b/servicing/build.gradle @@ -31,7 +31,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } - publishNonDefault true +// publishNonDefault true } compileOptions { sourceCompatibility JavaVersion.VERSION_11 @@ -64,7 +64,7 @@ publishing { release(MavenPublication) { groupId = 'io.github.szl9' artifactId = 'zd_servicing' - version = "1.0.1.9.9.127" + version = "1.0.1.9.9.138" pom { packaging = "aar" diff --git a/servicing/proguard-rules.pro b/servicing/proguard-rules.pro index 4fff175..68adfd1 100644 --- a/servicing/proguard-rules.pro +++ b/servicing/proguard-rules.pro @@ -1,3 +1,5 @@ +-dontwarn java.lang.invoke.StringConcatFactory + # 保留行号用于调试 -keepattributes SourceFile,LineNumberTable -renamesourcefileattribute SourceFile @@ -8,19 +10,42 @@ -keepattributes Exceptions -keepattributes InnerClasses +-dontwarn com.github.luben.zstd.BufferPool +-dontwarn com.github.luben.zstd.ZstdInputStream +-dontwarn com.github.luben.zstd.ZstdOutputStream +-dontwarn org.brotli.dec.BrotliInputStream +-dontwarn org.objectweb.asm.AnnotationVisitor +-dontwarn org.objectweb.asm.Attribute +-dontwarn org.objectweb.asm.ClassReader +-dontwarn org.objectweb.asm.ClassVisitor +-dontwarn org.objectweb.asm.FieldVisitor +-dontwarn org.objectweb.asm.Label +-dontwarn org.objectweb.asm.MethodVisitor +-dontwarn org.objectweb.asm.Type + # 保留R文件 -keepclassmembers class **.R$* { public static ; } # 保留servicing模块中的所有model类 --keep class com.za.servicing.model.** { *; } +-keep class com.za.bean.** { *; } +-keep class com.za.bean.db.** { *; } +-keep class com.za.bean.request.** { *; } # 保留servicing模块中的所有接口 -keep interface com.za.servicing.** { *; } +-keep interface com.za.net.** { *; } # 保留servicing模块中的所有枚举 --keepclassmembers enum com.za.servicing.** { *; } +-keepclassmembers enum com.za.** { *; } + +# 保留Room数据库相关类 +-keep class com.za.room.** { *; } +-keep class com.za.room.db.** { *; } +-keep class * extends androidx.room.RoomDatabase +-keep @androidx.room.Entity class * +-keep @androidx.room.Dao interface * # 保留Parcelable实现类 -keep class * implements android.os.Parcelable { @@ -58,6 +83,10 @@ void set*(***); *** get*(); } +# CameraX相关 +-keep class androidx.camera.** { *; } +-dontwarn androidx.camera.** + # Coil图片加载库 -keep class coil.** { *; } -dontwarn coil.** @@ -75,7 +104,6 @@ # JPush相关 -dontoptimize --dontpreverify -dontwarn cn.jpush.** -keep class cn.jpush.** { *; } -dontwarn cn.jcore.** @@ -105,13 +133,12 @@ long consumerIndex; } -#blankJ +# BlankJ工具库 -dontwarn com.blankj.utilcode.** - +-keep class com.blankj.utilcode.** { *; } -keepclassmembers class * { @com.blankj.utilcode.util.BusUtils$Bus ; } - -keep public class * extends com.blankj.utilcode.util.ApiUtils$BaseApi -keep,allowobfuscation @interface com.blankj.utilcode.util.ApiUtils$Api -keep @com.blankj.utilcode.util.ApiUtils$Api class * @@ -122,41 +149,27 @@ -keep public class * { public protected *; } -# Preserve all .class method names. +# 保留所有类的方法名 -keepclassmembernames class * { java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String, boolean); } -# Preserve all native method names and the names of their classes. - --keepclasseswithmembernames class * { - native ; -} - -# Preserve the special static methods that are required in all enumeration -# classes. - +# 保留枚举类中的特殊静态方法 -keepclassmembers class * extends java.lang.Enum { public static **[] values(); public static ** valueOf(java.lang.String); } --keepclassmembers class * implements java.io.Serializable { - static final long serialVersionUID; - static final java.io.ObjectStreamField[] serialPersistentFields; - private void writeObject(java.io.ObjectOutputStream); - private void readObject(java.io.ObjectInputStream); - java.lang.Object writeReplace(); - java.lang.Object readResolve(); -} +# MQTT相关 +-keep class org.eclipse.paho.** { *; } +-dontwarn org.eclipse.paho.** # Gson -keep class com.google.gson.** { *; } -keepattributes Signature -keepattributes *Annotation* --keep class sun.misc.Unsafe { *; } -keep class * implements com.google.gson.TypeAdapterFactory -keep class * implements com.google.gson.JsonSerializer -keep class * implements com.google.gson.JsonDeserializer @@ -192,7 +205,7 @@ public ** component*(); public ** copy(...); } - +# # 保留Kotlin数据类的toString/hashCode/equals方法 -keepclassmembers class ** { public java.lang.String toString(); @@ -200,4 +213,45 @@ public boolean equals(java.lang.Object); } +# 保留Compose相关 +-keep class androidx.compose.** { *; } +-dontwarn androidx.compose.** + +# 保留自定义签名相关类 +-keep class com.za.signature.** { *; } + +# 保留Face Detection相关 +-keep class com.google.mlkit.** { *; } +-dontwarn com.google.mlkit.** + +# 保留ZXing相关 +-keep class com.google.zxing.** { *; } +-dontwarn com.google.zxing.** + +# 保留Glide相关 +-keep public class * implements com.bumptech.glide.module.GlideModule +-keep class * extends com.bumptech.glide.module.AppGlideModule { + (...); +} +-keep public enum com.bumptech.glide.load.ImageHeaderParser$** { + **[] $VALUES; + public *; +} +-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { + *** rewind(); +} + +# 保留FastJSON相关 +-keep class com.alibaba.fastjson.** { *; } +-dontwarn com.alibaba.fastjson.** + +# 保留Bugly相关 +-keep class com.tencent.bugly.** { *; } +-dontwarn com.tencent.bugly.** +# +# 保留自定义UI组件 +-keep class com.za.ui.** { *; } +-keep class com.za.base.** { *; } + +# 保留Java 8 Lambda表达式 -dontwarn java.lang.invoke.StringConcatFactory \ No newline at end of file diff --git a/servicing/src/main/java/com/za/base/Const.kt b/servicing/src/main/java/com/za/base/Const.kt index 9449a9c..672170c 100644 --- a/servicing/src/main/java/com/za/base/Const.kt +++ b/servicing/src/main/java/com/za/base/Const.kt @@ -61,6 +61,7 @@ object Const { const val RE_DISPATCH = "reDispatch" const val MODIFY = "modify" const val REVOKE = "revoke" + const val REPORT_HANDLE = "report_handle" const val GO_MAIN_PAGE = "goMainPage" } } \ No newline at end of file diff --git a/servicing/src/main/java/com/za/base/IServicingVm.kt b/servicing/src/main/java/com/za/base/IServicingVm.kt index 9f0f0f2..9af8614 100644 --- a/servicing/src/main/java/com/za/base/IServicingVm.kt +++ b/servicing/src/main/java/com/za/base/IServicingVm.kt @@ -40,9 +40,7 @@ abstract class IServicingVm : BaseVm() { getCurrentOrder()?.getTaskNode() ?: 0, getCurrentOrder()?.userOrderId ?: 0) success(data) - }, failed = { - failure(it) - }) + }, failed = {}) } else { success(photoTemplateList) } diff --git a/servicing/src/main/java/com/za/base/PushMessageActivity.kt b/servicing/src/main/java/com/za/base/PushMessageActivity.kt index d40f5e3..6a2f72f 100644 --- a/servicing/src/main/java/com/za/base/PushMessageActivity.kt +++ b/servicing/src/main/java/com/za/base/PushMessageActivity.kt @@ -39,6 +39,12 @@ open class PushMessageActivity : AppCompatActivity() { context = this@PushMessageActivity) } + override fun reportHandle(jpushBean : JpushBean) { + sendMessageToMainProcess(type = Const.PushMessageType.REPORT_HANDLE, + message = Gson().toJson(jpushBean), + context = this@PushMessageActivity) + } + override fun newOrderMsg(jpushBean : JpushBean) { sendMessageToMainProcess(type = Const.PushMessageType.NEW_ORDER, message = Gson().toJson(jpushBean), diff --git a/servicing/src/main/java/com/za/base/theme/Theme.kt b/servicing/src/main/java/com/za/base/theme/Theme.kt index bb1fa15..f6df5ef 100644 --- a/servicing/src/main/java/com/za/base/theme/Theme.kt +++ b/servicing/src/main/java/com/za/base/theme/Theme.kt @@ -15,7 +15,10 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.SideEffect import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.unit.Density import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat @@ -61,12 +64,17 @@ fun DealerTheme(darkTheme : Boolean = isSystemInDarkTheme(), content : @Composab } } } + val fontScale = LocalDensity.current.fontScale + val displayMetrics = LocalContext.current.resources.displayMetrics + val widthPixels = displayMetrics.widthPixels + MaterialTheme(colorScheme = colorScheme) { CompositionLocalProvider(LocalRippleConfiguration provides RippleConfiguration(rippleAlpha = RippleAlpha( 0f, 0f, 0f, - 0f))) { + 0f)), + LocalDensity provides Density(fontScale = 1f, density = widthPixels / 360f)) { ProvideTextStyle(value = MaterialTheme.typography.bodyLarge, content = content) } } diff --git a/servicing/src/main/java/com/za/bean/JpushBean.kt b/servicing/src/main/java/com/za/bean/JpushBean.kt index 097b83b..70df17d 100644 --- a/servicing/src/main/java/com/za/bean/JpushBean.kt +++ b/servicing/src/main/java/com/za/bean/JpushBean.kt @@ -174,9 +174,6 @@ data class HistoryPhotoTemplateItem( //获取拍照时间 fun getPhotoTakeTime(taskState : String, historyTaskBean : HistoryTaskBean?) : String? { - if (! takePhotoTime.isNullOrBlank()) { - return takePhotoTime - } return when (taskState) { "13001", "15001" -> historyTaskBean?.arriveTime "17001" -> { @@ -197,9 +194,6 @@ data class HistoryPhotoTemplateItem( } fun getPhotoLat(taskState : String, historyTaskBean : HistoryTaskBean?) : Double? { - if (! lat.isNullOrBlank()) { - return lat.toDouble() - } return when (taskState) { "13001", "15001" -> historyTaskBean?.lat "17001", "18001" -> { @@ -216,9 +210,6 @@ data class HistoryPhotoTemplateItem( } fun getPhotoLng(taskState : String, historyTaskBean : HistoryTaskBean?) : Double? { - if (! lon.isNullOrBlank()) { - return lon.toDouble() - } return when (taskState) { "13001", "15001" -> historyTaskBean?.lng "17001", "18001" -> { @@ -235,9 +226,6 @@ data class HistoryPhotoTemplateItem( } fun getPhotoAddress(taskState : String, historyTaskBean : HistoryTaskBean?) : String? { - if (! takeAddress?.replace("[", "")?.replace("]", "").isNullOrBlank()) { - return takeAddress - } return when (taskState) { "13001", "15001" -> historyTaskBean?.address "17001", "18001" -> { diff --git a/servicing/src/main/java/com/za/bean/bean.kt b/servicing/src/main/java/com/za/bean/bean.kt index f2e22ce..712144c 100644 --- a/servicing/src/main/java/com/za/bean/bean.kt +++ b/servicing/src/main/java/com/za/bean/bean.kt @@ -31,4 +31,14 @@ data class TaskNotesBean(val taskNotes : String? = null, //救援要求 val customerNotes : String? = null, //客户提醒 val otherNotes : String? = null, //特殊提醒 val modelVinNo : String? = null, //车型 - val contract : String? = null) //车型 \ No newline at end of file + val contract : String? = null) //车型 + + +data class UnifiedOCRWithCompressRequest( + val ocrType : Int? = null, // 4为车架号识别 5为车牌号识别 + val imageUrl : String? = null, // 图片地址 + val cardSide : String? = null, // FRONT:正面 BACK:反面 默认:FRONT +) + + +data class SaveSignatureRequest(val signatureUrl : String? = null, val driverId : Int? = null) \ No newline at end of file diff --git a/servicing/src/main/java/com/za/bean/db/order/PhotoTemplateInfo.kt b/servicing/src/main/java/com/za/bean/db/order/PhotoTemplateInfo.kt index 29afe59..4e7c3d2 100644 --- a/servicing/src/main/java/com/za/bean/db/order/PhotoTemplateInfo.kt +++ b/servicing/src/main/java/com/za/bean/db/order/PhotoTemplateInfo.kt @@ -22,6 +22,7 @@ data class PhotoTemplateInfo( val numbering : String? = null, // 图片编号 val recognizeType : Int? = null, //orc 识别类型 0 无 1 车牌号 2 车架号 //以下属性非后台返回属性 + val serviceTypeName : String? = null, //服务类型名称 val userOrderId : Int? = null, val taskCode : String? = null, val taskId : Int? = null, diff --git a/servicing/src/main/java/com/za/common/GlobalData.kt b/servicing/src/main/java/com/za/common/GlobalData.kt index ca9210f..ef02dff 100644 --- a/servicing/src/main/java/com/za/common/GlobalData.kt +++ b/servicing/src/main/java/com/za/common/GlobalData.kt @@ -7,6 +7,7 @@ import com.tencent.mmkv.MMKV import com.za.base.AppConfig import com.za.base.Const import com.za.bean.db.order.OrderInfo +import com.za.common.log.LogUtil import com.za.room.RoomHelper import com.za.room.db.user.DriverInfoBean import com.za.service.location.ZdLocationManager @@ -49,14 +50,26 @@ object GlobalData : GlobalLocalData() { var driverInfoBean : DriverInfoBean? = null get() { - if (field == null) { - field = localDriverInfoBean + return try { + val driverInfo = MMKV.defaultMMKV() + .decodeParcelable("driverInfoBean", DriverInfoBean::class.java) + field = driverInfo + field + } catch (e : Exception) { + LogUtil.print("local_driverInfoBean", "获取司机信息失败: ${e.message}") + null } - return field } set(value) { - localDriverInfoBean = value - field = value + try { + MMKV.defaultMMKV().encode("driverInfoBean", value) + if (value != null) { + lastLoginBean = value + } + field = value + } catch (e : Exception) { + LogUtil.print("set local_driverInfoBean", "保存司机信息失败: ${e.message}") + } } @@ -139,6 +152,45 @@ object GlobalData : GlobalLocalData() { mmkv.encode("isShowKeepAlive", value) } + + var lastUploadLogTime : Long + get() { + return mmkv.decodeLong("lastUploadLogTime", 0) + } + set(value) { + mmkv.encode("lastUploadLogTime", value) + } + + var vehicleId : Int? = null + get() { + field = mmkv.decodeInt("vehicleId") + return field + } + set(value) { + mmkv.encode("vehicleId", value ?: 0) + field = value + } + + var driverId : Int? = null + get() { + field = mmkv.decodeInt("driverId") + return field + } + set(value) { + mmkv.encode("driverId", value ?: 0) + field = value + } + + var deviceId : String? = null + get() { + field = mmkv.decodeString("deviceId") + return field + } + set(value) { + mmkv.encode("deviceId", value) + field = value + } + fun clearUserCache() { token = null aesKey = null @@ -147,6 +199,10 @@ object GlobalData : GlobalLocalData() { loginTime = null isLoginRecognition = null isHasShowKeepAlive = false + lastUploadLogTime = 0 + deviceId = null + vehicleId = null + driverId = null if (AppConfig.isRelease) { networkEnv = if (AppConfig.isRelease) { diff --git a/servicing/src/main/java/com/za/common/log/LogUtil.kt b/servicing/src/main/java/com/za/common/log/LogUtil.kt index 75c3b0e..7b3d571 100644 --- a/servicing/src/main/java/com/za/common/log/LogUtil.kt +++ b/servicing/src/main/java/com/za/common/log/LogUtil.kt @@ -2,69 +2,72 @@ package com.za.common.log import android.app.Application import android.content.Context +import android.os.Build import android.util.Log import androidx.work.Configuration import androidx.work.PeriodicWorkRequest import androidx.work.WorkManager import androidx.work.Worker import androidx.work.WorkerParameters -import com.blankj.utilcode.constant.MemoryConstants import com.blankj.utilcode.util.AppUtils -import com.blankj.utilcode.util.DeviceUtils import com.blankj.utilcode.util.FileUtils +import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.TimeUtils import com.za.common.GlobalData -import com.za.common.util.AppFileManager import io.reactivex.rxjava3.schedulers.Schedulers -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import okhttp3.MediaType.Companion.toMediaType import okhttp3.MultipartBody import okhttp3.RequestBody import okhttp3.RequestBody.Companion.asRequestBody import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream -import java.io.BufferedWriter import java.io.File import java.io.FileInputStream import java.io.FileOutputStream -import java.io.FileWriter import java.io.IOException import java.io.PrintWriter import java.io.StringWriter +import java.nio.file.Files +import java.nio.file.Paths +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean -import kotlin.concurrent.thread object LogUtil { private var context : Application? = null - private var logDestinationPath : String? = null - private var orderLogDirPath : String? = null + private var executors : ExecutorService? = null private var normalLogDirPath : String? = null - private val coroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) - private val logBuffer = StringBuilder() - private val isWriting = AtomicBoolean(false) + + //日志上报时间间隔 + private const val uploadTimeInterval = (30 * 60 * 1000).toLong() fun init(context : Application) { this.context = context - - logDestinationPath = AppFileManager.getLogPath(context).also { path -> - createDirectoryIfNotExists(path) - orderLogDirPath = - "$path${File.separator}order_log".also { createDirectoryIfNotExists(it) } - normalLogDirPath = - "$path${File.separator}normal_log".also { createDirectoryIfNotExists(it) } + executors = Executors.newSingleThreadExecutor() + val logDestinationPath : String = context.filesDir.absolutePath + File.separator + "Log" + val logDesFile = File(logDestinationPath) + if (! logDesFile.exists()) { + logDesFile.mkdir() } + val orderLogDirPath = logDestinationPath + File.separator + "order_log" + val orderLogFile = File(orderLogDirPath) + if (! orderLogFile.exists()) { + orderLogFile.mkdir() + } + normalLogDirPath = logDestinationPath + File.separator + "normal_log" + val normalLogFile = File(normalLogDirPath) + LogUtils.getConfig().setDir(normalLogDirPath) + LogUtils.getConfig().setBorderSwitch(false) + LogUtils.getConfig().setLog2FileSwitch(true) + LogUtils.getConfig().setStackDeep(1) + LogUtils.getConfig().setLogHeadSwitch(false) + + if (! normalLogFile.exists()) { + normalLogFile.mkdir() + } initializeWorkManager(context) } - private fun createDirectoryIfNotExists(path : String) { - File(path).apply { if (! exists()) mkdir() } - } - private fun initializeWorkManager(context : Application) { if (! WorkManager.isInitialized()) { WorkManager.initialize(context, @@ -73,183 +76,157 @@ object LogUtil { WorkManager.getInstance(context).apply { cancelAllWorkByTag("logWorkRequest") - enqueue(PeriodicWorkRequest.Builder(LogTask::class.java, 20, TimeUnit.MINUTES) + enqueue(PeriodicWorkRequest.Builder(LogTask::class.java, 80, TimeUnit.MINUTES) .addTag("logWorkRequest").build()) } } - fun print(tag : String, content : String) { - val time = getCurrentTime() - val logEntry = "$time---$tag---$content\n" - Log.e("normal", "$tag---$content") - synchronized(logBuffer) { - logBuffer.append(logEntry) + fun print(tag : String?, throwable : Throwable?) { + if (throwable == null) { + return } - - if (logBuffer.length > 4096) { - coroutineScope.launch { - flushBuffer() - } - } - } - - fun print(tag : String, throwable : Throwable) { - val content = StringWriter() - val printWriter = PrintWriter(content) - throwable.printStackTrace(printWriter) - print(tag, content.toString()) - } - - private suspend fun flushBuffer() = withContext(Dispatchers.IO) { - if (! isWriting.compareAndSet(false, true)) return@withContext - - val logContent : String - synchronized(logBuffer) { - if (logBuffer.isEmpty()) { - isWriting.set(false) - return@withContext - } - logContent = logBuffer.toString() - logBuffer.clear() - } - try { - val fileName = "normal_log.txt" - val logFile = File("$normalLogDirPath${File.separator}$fileName") - - logFile.parentFile?.mkdirs() - - if (! logFile.exists()) { - logFile.createNewFile() - addLogHead(logFile, getCurrentTime()) + val stringWriter = StringWriter() + val printWriter = PrintWriter(stringWriter) + throwable.printStackTrace(printWriter) + if (System.currentTimeMillis() - GlobalData.lastUploadLogTime > uploadTimeInterval) { + updateNormalLog() } - - BufferedWriter(FileWriter(logFile, true)).use { writer -> - writer.write(logContent) - writer.flush() - } - - if (logFile.length() >= 8 * MemoryConstants.MB) { - rotateLogFile(logFile) - } - } catch (e : IOException) { - Log.e("LogUtil", "Error in flushBuffer: ${e.message}") + LogUtils.getConfig().setFilePrefix(this.vehicleName) + LogUtils.e("$tag---$stringWriter") } catch (e : Exception) { - Log.e("LogUtil", "Error in flushBuffer: ${e.message}") - } finally { - isWriting.set(false) + e.printStackTrace() } } - private fun rotateLogFile(file : File) { - if (! file.exists()) return - - val newFileName = buildString { - append(AppUtils.getAppVersionCode()) - append("_") - append(GlobalData.driverInfoBean?.vehicleName ?: "unknown") - append("_") - append(GlobalData.driverInfoBean?.userName ?: "unknown") - append("_") - append(TimeUtils.getNowString()) - append(".txt") + fun print(tag : String?, content : String?) { + if (content == null || content.isEmpty()) { + return + } + if (GlobalData.driverInfoBean == null || GlobalData.driverInfoBean?.vehicleName.isNullOrBlank()) { + Log.e(tag, content) + return } - - val newFile = File("$normalLogDirPath${File.separator}$newFileName") - try { - if (file.renameTo(newFile)) { - compressAndUploadLog(newFile) // 创建新的日志文件 - file.createNewFile() - addLogHead(file, getCurrentTime()) - } else { - print("LogUtil", "Failed to rename log file") + if (System.currentTimeMillis() - GlobalData.lastUploadLogTime > uploadTimeInterval) { + updateNormalLog() } + LogUtils.getConfig().setFilePrefix(this.vehicleName) + LogUtils.e("$tag---$content") } catch (e : Exception) { - print("LogUtil", "Error during log rotation: ${e.message}") + e.printStackTrace() } } - private fun compressAndUploadLog(logFile : File) = coroutineScope.launch { - try { - val compressedFile = File("${logFile.absolutePath}.7z") - compress(logFile, compressedFile.absolutePath) - upload(logFile, compressedFile) - } catch (e : Exception) { - print("LogUtil", e.toString()) + private val vehicleName : String + get() { + var name : String? = "未知" + if (! GlobalData.driverInfoBean?.vehicleName.isNullOrBlank()) { + try { + name = buildString { + append(GlobalData.driverInfoBean?.vehicleName?.replace("/", "") + ?.replace(" ", "")) + append("_") + append(GlobalData.driverInfoBean?.userName ?: "未知") + } + } catch (e : Exception) { + e.printStackTrace() + } + } + return name ?: "未知" } - } private fun deleteLog(file : File) { try { - FileUtils.delete(file.absolutePath) + file.delete() } catch (e : Exception) { e.printStackTrace() } } fun updateNormalLog() { - thread { - if (GlobalData.token.isNullOrBlank()) { - return@thread - } - val fileName = "normal_log.txt" - val file = File("$normalLogDirPath${File.separator}$fileName") - val reName = - "${AppUtils.getAppVersionCode()}_${GlobalData.driverInfoBean?.vehicleName}_${GlobalData.driverInfoBean?.userName}_${TimeUtils.getNowString()}.txt" - val reNamePath = "$normalLogDirPath${File.separator}$reName" - file.renameTo(File(reNamePath)) - normalLogDirPath?.let { it -> - File(it).listFiles()?.forEach { - if (it.length() / MemoryConstants.MB >= 10) { - deleteLog(it) - return@thread - } - if (it.exists() && ! it.name.contains("normal_log")) { - if (it.name.contains("7z")) { - upload(null, desFile = it) - } else { - val zipNamePath = it.absolutePath + ".7z" - val zipFile = File(zipNamePath) - if (! zipFile.exists()) { - try { - zipFile.createNewFile() - } catch (e : IOException) { - e.printStackTrace() - } + GlobalData.lastUploadLogTime = System.currentTimeMillis() + val files = File(normalLogDirPath).listFiles() + if (files.isNullOrEmpty()) { + return + } + for (file in files) { + try { + if (file.isDirectory()) { + file.delete() + FileUtils.deleteAllInDir(file) + } else if (file.getName().endsWith("7z")) { + uploadFile(null, File(file.absolutePath)) + } else { + executors?.submit { + val vehicleName = vehicleName + val zipNamePath = + normalLogDirPath + File.separator + AppUtils.getAppVersionCode() + "_" + vehicleName + "_" + this.currentTime + ".txt.7z" + val zipFile = File(zipNamePath) + if (! zipFile.exists()) { + try { + zipFile.createNewFile() + compress(file, zipNamePath) + } catch (e : IOException) { + e.printStackTrace() } - compress(it, zipNamePath) } } } + } catch (e : Exception) { + e.printStackTrace() } } } private fun compress(srcFile : File, desFilePath : String) { try { - val out = XZCompressorOutputStream(FileOutputStream(desFilePath)) + val out = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + XZCompressorOutputStream(Files.newOutputStream(Paths.get(desFilePath))) + } else { + XZCompressorOutputStream(FileOutputStream(desFilePath)) + } addToArchiveCompression(out, srcFile, File(desFilePath)) } catch (e : Exception) { e.printStackTrace() } } + private fun uploadFile(srcFile : File?, desFile : File) { + val requestBody : RequestBody = desFile.asRequestBody("multipart/form-data".toMediaType()) + val part = MultipartBody.Part.createFormData("file", desFile.name, requestBody) + + val disposable = + LogRetrofitHelper.getDefaultService().uploadLog(part, desFile.name, "rescue-app") + .subscribeOn(Schedulers.io()).subscribe({ it -> + if (it.code == 200) { + deleteLog(desFile); + } + if (srcFile != null) { + deleteLog(srcFile); + } + }, { + if (srcFile != null) { + deleteLog(srcFile); + } + }, {}) + } + private fun addToArchiveCompression(sevenZOutputFile : XZCompressorOutputStream, srcFile : File, desFile : File) { - if (srcFile.isFile) { + if (srcFile.isFile()) { var inputStream : FileInputStream? = null try { inputStream = FileInputStream(srcFile) val b = ByteArray(2048) var count : Int - while (inputStream.read(b).also { count = it } != - 1) { + while ((inputStream.read(b).also { count = it }) != - 1) { sevenZOutputFile.write(b, 0, count) } sevenZOutputFile.close() inputStream.close() - upload(srcFile, desFile) + uploadFile(srcFile, desFile) } catch (e : Exception) { e.printStackTrace() } finally { @@ -263,42 +240,8 @@ object LogUtil { } } - private fun upload(srcFile : File?, desFile : File) { - val requestBody : RequestBody = desFile.asRequestBody("multipart/form-data".toMediaType()) - val part = MultipartBody.Part.createFormData("file", desFile.name, requestBody) - - val disposable = - LogRetrofitHelper.getDefaultService().uploadLog(part, desFile.name, "rescue-app") - .subscribeOn(Schedulers.io()).subscribe({ it -> - if (it.code == 200) { - deleteLog(desFile) - } - srcFile?.let { - deleteLog(it) - } - }, {}, {}) - } - - private fun addLogHead(file : File, time : String) { - file.appendBytes("${time}---应用版本---${AppUtils.getAppVersionName()}".toByteArray()) - file.appendBytes("\n".toByteArray()) - file.appendBytes("$time---系统版本---Android${DeviceUtils.getSDKVersionName()} ${DeviceUtils.getSDKVersionCode()}".toByteArray()) - file.appendBytes("\n".toByteArray()) - file.appendBytes("$time---ROM---${DeviceUtils.getManufacturer()} ${DeviceUtils.getModel()}".toByteArray()) - file.appendBytes("\n".toByteArray()) - file.appendBytes("$time---build---${AppUtils.getAppVersionCode()}".toByteArray()) - file.appendBytes("\n".toByteArray()) - file.appendBytes("$time---APP名称---中道救援-司机端".toByteArray()) - file.appendBytes("\n".toByteArray()) - file.appendBytes("$time---车辆名称---${GlobalData.driverInfoBean?.vehicleName}".toByteArray()) - file.appendBytes("\n".toByteArray()) - file.appendBytes("$time---司机名称---${GlobalData.driverInfoBean?.userName ?: GlobalData.driverInfoBean?.userName}".toByteArray()) - file.appendBytes("\n".toByteArray()) - } - - private fun getCurrentTime() : String { - return TimeUtils.millis2String(System.currentTimeMillis(), "yyyy/MM/dd HH:mm:ss.SSS") - } + private val currentTime : String? + get() = TimeUtils.millis2String(System.currentTimeMillis(), "yyyy_MM_dd HH:mm:ss:SS") class LogTask(appContext : Context, workerParams : WorkerParameters) : Worker(appContext, workerParams) { @@ -307,4 +250,11 @@ object LogUtil { return Result.success() } } -} \ No newline at end of file + +} + + + + + + diff --git a/servicing/src/main/java/com/za/common/speech/SpeechManager.kt b/servicing/src/main/java/com/za/common/speech/SpeechManager.kt index c338860..9593a38 100644 --- a/servicing/src/main/java/com/za/common/speech/SpeechManager.kt +++ b/servicing/src/main/java/com/za/common/speech/SpeechManager.kt @@ -5,7 +5,6 @@ import android.media.AudioAttributes import android.media.AudioManager import android.media.MediaPlayer import androidx.core.content.ContextCompat -import com.za.base.AppConfig import com.za.bean.request.AppNewOrderVoiceRequest import com.za.common.GlobalData import com.za.common.log.LogUtil @@ -61,18 +60,21 @@ object SpeechManager { } - private var originVolume = 0 + private var defaultVolume = 10 + private var originVolume = defaultVolume + private var audioManager : AudioManager? = null private fun setMaxAudioVolume() { try { - if (! AppConfig.isRelease) { + audioManager = + ContextCompat.getSystemService(GlobalData.application, AudioManager::class.java) + + if (audioManager == null) { return } - val audioManager = - ContextCompat.getSystemService(GlobalData.application, AudioManager::class.java) - originVolume = audioManager?.getStreamVolume(AudioManager.STREAM_MUSIC) ?: 0 + originVolume = audioManager?.getStreamVolume(AudioManager.STREAM_MUSIC) ?: defaultVolume val maxVolume = audioManager?.getStreamMaxVolume(AudioManager.STREAM_MUSIC) audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, - maxVolume ?: 1, + maxVolume ?: defaultVolume, AudioManager.FLAG_PLAY_SOUND) } catch (e : Exception) { LogUtil.print("setMaxAudioVolume", e) @@ -80,15 +82,12 @@ object SpeechManager { } private fun resetAudioVolume() { - try { - if (! AppConfig.isRelease) { - return - } - val audioManager = - ContextCompat.getSystemService(GlobalData.application, AudioManager::class.java) - audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, - originVolume, - AudioManager.FLAG_PLAY_SOUND) + try { // val audioManager = + // ContextCompat.getSystemService(GlobalData.application, AudioManager::class.java) + // audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, + // originVolume, + // AudioManager.FLAG_PLAY_SOUND) + LogUtil.print("resetAudioVolume", "resetAudioVolume") } catch (e : Exception) { LogUtil.print("resetAudioVolume", e) } @@ -153,9 +152,7 @@ object SpeechManager { } // 设置最大音量 - setMaxAudioVolume() - - // 开始播放 + setMaxAudioVolume() // 开始播放 mediaPlayer?.start() } catch (e : Exception) { LogUtil.print("playNewOrder", "播放出错: ${e.message}") @@ -174,7 +171,7 @@ object SpeechManager { mediaPlayer?.setDataSource(url) mediaPlayer?.setOnPreparedListener { // 设置最大音量 - setMaxAudioVolume() // 准备完成后开始播放 + // 准备完成后开始播放 it.start() } mediaPlayer?.setOnCompletionListener { // 播放完成后释放资源 @@ -185,8 +182,7 @@ object SpeechManager { releaseMediaPlayer() true } - - // 异步准备,避免阻塞UI线程 + setMaxAudioVolume() // 异步准备,避免阻塞UI线程 mediaPlayer?.prepareAsync() } catch (e : Exception) { LogUtil.print("playNewOrderFromNet", "播放出错: ${e.message}") diff --git a/servicing/src/main/java/com/za/common/speech/TTSManager.kt b/servicing/src/main/java/com/za/common/speech/TTSManager.kt index c0a27f5..ea135b3 100644 --- a/servicing/src/main/java/com/za/common/speech/TTSManager.kt +++ b/servicing/src/main/java/com/za/common/speech/TTSManager.kt @@ -2,80 +2,89 @@ package com.za.common.speech import android.annotation.SuppressLint import android.content.Context +import android.media.AudioManager +import android.os.Bundle import android.speech.tts.TextToSpeech +import android.speech.tts.TextToSpeech.Engine.KEY_PARAM_VOLUME import android.speech.tts.UtteranceProgressListener import com.za.common.log.LogUtil import java.util.Locale + @SuppressLint("StaticFieldLeak") object TTSManager { - private var tts: TextToSpeech? = null - private var context: Context? = null - private var listener: OnTTSListener? = null + private var tts : TextToSpeech? = null + private var context : Context? = null + private var listener : OnTTSListener? = null - fun init(context: Context?, onTTSListener: OnTTSListener) { - this.context = context - this.listener = onTTSListener - initTTS() - } + fun init(context : Context?, onTTSListener : OnTTSListener) { + this.context = context + this.listener = onTTSListener + initTTS() + } - private fun initTTS() { - tts = TextToSpeech(context) { status -> - if (status == TextToSpeech.SUCCESS) { - val result = tts?.setLanguage(Locale.getDefault()) - if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { - LogUtil.print("TTS", "Language not supported") - listener?.onTTSFailed("Language not supported") - } else { - LogUtil.print("TTS", "TTS initialized successfully") - listener?.onTTSInitialized() - } - } else { - LogUtil.print("TTS", "Initialization failed") - listener?.onTTSFailed("Initialization failed") - } - } + private fun initTTS() { + tts = TextToSpeech(context) { status -> + if (status == TextToSpeech.SUCCESS) { + val result = tts?.setLanguage(Locale.getDefault()) + if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { + LogUtil.print("TTS", "Language not supported") + listener?.onTTSFailed("Language not supported") + } else { + LogUtil.print("TTS", "TTS initialized successfully") + listener?.onTTSInitialized() + } + } else { + LogUtil.print("TTS", "Initialization failed") + listener?.onTTSFailed("Initialization failed") + } + } - tts?.setOnUtteranceProgressListener(object : UtteranceProgressListener() { - override fun onStart(utteranceId: String) { - LogUtil.print("TTS", "Speech started") - } + tts?.setOnUtteranceProgressListener(object : UtteranceProgressListener() { + override fun onStart(utteranceId : String) { + LogUtil.print("TTS", "Speech started") + } - override fun onDone(utteranceId: String) { - LogUtil.print("TTS", "Speech completed") - listener?.onTTSSuccess() - } + override fun onDone(utteranceId : String) { + LogUtil.print("TTS", "Speech completed") + listener?.onTTSSuccess() + } - override fun onError(utteranceId: String) { - LogUtil.print("TTS", "Speech error") - listener?.onTTSFailed("Speech error") - } - }) - } + override fun onError(utteranceId : String) { + LogUtil.print("TTS", "Speech error") + listener?.onTTSFailed("Speech error") + } + }) + } - fun speak(text: String?) { - if (tts != null && tts?.isSpeaking == false) { - tts?.speak(text, TextToSpeech.QUEUE_FLUSH, null, "uniqueId") - } - } + fun speak(text : String?) { + if (tts != null && tts?.isSpeaking == false) { //设置最大音量 + val am = context?.getSystemService(Context.AUDIO_SERVICE) as AudioManager + val sb2value = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC) + am.setStreamVolume(AudioManager.STREAM_MUSIC, sb2value, 0) + val bundle = Bundle() + bundle.putFloat(KEY_PARAM_VOLUME, 1.0f) + tts?.speak(text, TextToSpeech.QUEUE_FLUSH, bundle, "uniqueId") + } + } - fun stop() { - tts?.takeIf { it.isSpeaking }?.stop() - } + fun stop() { + tts?.takeIf { it.isSpeaking }?.stop() + } - fun shutdown() { - tts?.apply { - stop() - shutdown() - } - tts = null - } + fun shutdown() { + tts?.apply { + stop() + shutdown() + } + tts = null + } } interface OnTTSListener { - fun onTTSInitialized() - fun onTTSSuccess() - fun onTTSFailed(errorMessage: String?) + fun onTTSInitialized() + fun onTTSSuccess() + fun onTTSFailed(errorMessage : String?) } \ No newline at end of file diff --git a/servicing/src/main/java/com/za/net/ApiService.kt b/servicing/src/main/java/com/za/net/ApiService.kt index f90c550..8fbba8a 100644 --- a/servicing/src/main/java/com/za/net/ApiService.kt +++ b/servicing/src/main/java/com/za/net/ApiService.kt @@ -22,9 +22,11 @@ import com.za.bean.ReportHistoryBean import com.za.bean.ReportHistoryRequest import com.za.bean.ReportInfoRequest import com.za.bean.ReportItem +import com.za.bean.SaveSignatureRequest import com.za.bean.SettleInfoRequest import com.za.bean.TaskNotesBean import com.za.bean.TaskSettlementAndTraceBean +import com.za.bean.UnifiedOCRWithCompressRequest import com.za.bean.UpdateVersionBean import com.za.bean.UpdateVersionRequest import com.za.bean.UploadChangeBatteryRequest @@ -289,4 +291,12 @@ interface ApiService { @POST("driverApp/task/getTaskNotes") fun getTaskNotes(@Body request : TaskNotesRequest) : Observable> + + @POST("driverApp/supplier/unifiedOCRWithCompress") + fun unifiedOCRWithCompress(@Body request : UnifiedOCRWithCompressRequest) : Observable> + + @POST("driverApp/v2/user/saveSignature") + fun saveSignature(@Body request : SaveSignatureRequest) : Observable> + + } diff --git a/servicing/src/main/java/com/za/net/BaseObserver.kt b/servicing/src/main/java/com/za/net/BaseObserver.kt index 1d0ac56..de383aa 100644 --- a/servicing/src/main/java/com/za/net/BaseObserver.kt +++ b/servicing/src/main/java/com/za/net/BaseObserver.kt @@ -11,6 +11,7 @@ import com.za.base.view.warnBean import com.za.bean.BaseResponse import com.za.common.GlobalData import com.za.common.log.LogUtil +import com.za.offline.OfflineService import com.za.service.location.ZdLocationManager import io.reactivex.rxjava3.core.Observer import io.reactivex.rxjava3.disposables.Disposable @@ -128,6 +129,7 @@ abstract class BaseObserver : Observer> { ToastUtils.showShort("登陆信息已过期,请重新登录") ZdLocationManager.stopContinuousLocation() GlobalData.clearUserCache() + OfflineService.stop() ActivityUtils.startLauncherActivity() } catch (e : Exception) { LogUtil.print("handlerTokenExpired", e) diff --git a/servicing/src/main/java/com/za/net/CommonMethod.kt b/servicing/src/main/java/com/za/net/CommonMethod.kt index 87c3ac0..4a0ec48 100644 --- a/servicing/src/main/java/com/za/net/CommonMethod.kt +++ b/servicing/src/main/java/com/za/net/CommonMethod.kt @@ -113,16 +113,15 @@ object CommonMethod { }) } - private var lastFetchGenerateInfoTime : Long = 0L - fun getGenerateInfo(vehicleId : Int? = null, - userId : Int? = null, - success : (DriverInfoBean) -> Unit = {}, - failed : (String?) -> Unit = {}) { + fun getGenerateInfo(success : (DriverInfoBean) -> Unit = {}, failed : (String?) -> Unit = {}) { val generalInfoRequest = - GeneralInfoRequest(vehicleId = vehicleId ?: GlobalData.driverInfoBean?.vehicleId, - driverId = userId ?: GlobalData.driverInfoBean?.userId, - deviceId = DeviceUtil.getAndroidId(ActivityUtils.getTopActivity())) + GeneralInfoRequest(vehicleId = GlobalData.vehicleId.takeIf { it != null && it != 0 } + ?: GlobalData.driverInfoBean?.vehicleId, + driverId = GlobalData.driverId.takeIf { it != null && it != 0 } + ?: GlobalData.driverInfoBean?.userId, + deviceId = GlobalData.deviceId + ?: DeviceUtil.getAndroidId(ActivityUtils.getTopActivity())) LogUtil.print("getGenerateInfo", "request=${generalInfoRequest.toJson()}") RetrofitHelper.getDefaultService().generalInfo(generalInfoRequest) @@ -130,21 +129,39 @@ object CommonMethod { .subscribe(object : BaseObserver() { override fun doSuccess(it : DriverInfoBean?) { if (it == null) { - failed("获取车辆信息失败") + if (GlobalData.driverInfoBean != null) { + success(GlobalData.driverInfoBean !!) + } else { + failed("获取车辆信息失败") + } + LogUtil.print("getGenerateInfo", "获取车辆信息失败") return } + + + if (GlobalData.driverId == null || GlobalData.driverId == 0) { + GlobalData.driverId = it.userId + } + + if (GlobalData.vehicleId == null || GlobalData.vehicleId == 0) { + GlobalData.vehicleId = it.vehicleId + } + + if (GlobalData.deviceId.isNullOrBlank()) { + GlobalData.deviceId = it.deviceId + } + if (GlobalData.driverInfoBean != null && (System.currentTimeMillis() - lastFetchGenerateInfoTime < 1000 * 10)) { - LogUtil.print("getGenerateInfo", - "获取车辆信息成功,但是时间间隔小于10秒,不更新车辆信息") success(it) return } - GlobalData.driverInfoBean = it - lastFetchGenerateInfoTime = System.currentTimeMillis() - LogUtil.print("GlobalData.driverInfoBean", - "${GlobalData.driverInfoBean?.toJson()}}") + GlobalData.driverInfoBean = it + + + lastFetchGenerateInfoTime = System.currentTimeMillis() + LogUtil.print("GlobalData.driverInfoBean", "${it.toJson()}}") success(it) } @@ -197,7 +214,7 @@ object CommonMethod { } override fun doFailure(code : Int, msg : String?) { - + LogUtil.print("getNewOrder", "doFailure=$msg") } }) } @@ -233,92 +250,45 @@ object CommonMethod { ?.getOfflineTaskFromTaskId(inServicingOrder.taskId ?: 0).isNullOrEmpty() ) { LogUtil.print("queryOrderList", "走离线任务逻辑") - inServicingOrder = inServicingOrder.copy(taskState = RoomHelper.db?.orderDao() - ?.getCurrentOrder()?.taskState) - - if (GlobalData.currentOrder?.serviceTypeName != inServicingOrder.serviceTypeName) { - LogUtil.print("queryOrderList", "订单类型发生变化") - RoomHelper.db?.photoTemplateDao() - ?.deleteOrderPhotoTemplateFromTaskId(taskId = inServicingOrder.taskId - ?: 0) - fetchPhotoTemplate(orderInfo = inServicingOrder, - isNeedUpload = true, - success = { - GlobalData.currentOrder = inServicingOrder - - OfflineManager.start(GlobalData.currentOrder?.taskId) - - context?.let { - ReportFloatingManager.startService(it) - } - success(inServicingOrder, waitServiceOrders) - }, - failed = { - GlobalData.currentOrder = inServicingOrder - - OfflineManager.start(GlobalData.currentOrder?.taskId) - - context?.let { - ReportFloatingManager.startService(it) - } - success(inServicingOrder, waitServiceOrders) - }) - } - return - } - - if (GlobalData.currentOrder?.serviceTypeName != inServicingOrder.serviceTypeName) { - LogUtil.print("queryOrderList", "订单类型发生变化") - RoomHelper.db?.photoTemplateDao() - ?.deleteOrderPhotoTemplateFromTaskId(taskId = inServicingOrder.taskId - ?: 0) - fetchPhotoTemplate(orderInfo = inServicingOrder, - isNeedUpload = true, - success = { - GlobalData.currentOrder = inServicingOrder - - OfflineManager.start(GlobalData.currentOrder?.taskId) - - context?.let { - ReportFloatingManager.startService(it) - } - success(inServicingOrder, waitServiceOrders) - }, - failed = { - GlobalData.currentOrder = inServicingOrder - - OfflineManager.start(GlobalData.currentOrder?.taskId) - - context?.let { - ReportFloatingManager.startService(it) - } - success(inServicingOrder, waitServiceOrders) - }) - return + val offlineTaskState = + RoomHelper.db?.orderDao()?.getCurrentOrder()?.taskState + ?: inServicingOrder.taskState + inServicingOrder = inServicingOrder.copy(taskState = offlineTaskState) } GlobalData.currentOrder = inServicingOrder + success(inServicingOrder, waitServiceOrders) + + + val listData = RoomHelper.db?.photoTemplateDao() + ?.queryCurrentOrderHasTaskNode(inServicingOrder.userOrderId ?: 0) + LogUtil.print("queryOrderList", "listData=${listData.toJson()}") + if (listData.isNullOrEmpty() || (! listData[0].serviceTypeName.isNullOrBlank() && listData[0].serviceTypeName != inServicingOrder.serviceTypeName)) { + RoomHelper.db?.photoTemplateDao() + ?.deleteOrderPhotoTemplateFromTaskId(taskId = inServicingOrder.taskId + ?: 0) + fetchPhotoTemplate(orderInfo = inServicingOrder) + LogUtil.print("queryOrderList", "照片模版为空,重新获取照片模版") + } + it.forEach { - if (RoomHelper.db?.orderDao() - ?.getOrderInfoFromTaskId(it.taskId ?: 0) != null - ) { - RoomHelper.db?.orderDao()?.update(orderInfo = it) + val task = RoomHelper.db?.orderDao()?.getOrderInfoFromTaskId(it.taskId ?: 0) + if (task != null) { + RoomHelper.db?.orderDao() + ?.update(orderInfo = it.copy(taskState = task.taskState)) } else { RoomHelper.db?.orderDao()?.insertOrder(orderInfo = it) } } - fetchPhotoTemplate(inServicingOrder) + queryElectronOrder(orderInfo = inServicingOrder) WaterMarkerTemplateManager.fetchWaterTemplate(inServicingOrder.taskCode ?: "", taskId = inServicingOrder.taskId ?: 0, inServicingOrder.userOrderId ?: 0) OfflineManager.start(GlobalData.currentOrder?.taskId) - context?.let { ReportFloatingManager.startService(it) } - - success(inServicingOrder, waitServiceOrders) } override fun doFailure(code : Int, msg : String?) { @@ -334,7 +304,6 @@ object CommonMethod { } fun fetchPhotoTemplate(orderInfo : OrderInfo?, - isNeedUpload : Boolean? = false, success : () -> Unit = {}, failed : (String?) -> Unit = {}) { val photoTemplateRequest = PhotoTemplateRequest(orderInfo?.userOrderId) @@ -343,13 +312,6 @@ object CommonMethod { .subscribe(object : BaseObserver>() { override fun doSuccess(it : List?) { if (it.isNullOrEmpty()) { - LogUtil.print("fetchPhotoTemplate", - "模板为null ${photoTemplateRequest.toJson()}") - failed("未找到模版") - return - } - - if (isNeedUpload == false) { val listData = RoomHelper.db?.photoTemplateDao() ?.queryCurrentOrderHasTaskNode(orderInfo?.userOrderId ?: 0) if (! listData.isNullOrEmpty()) { @@ -358,6 +320,31 @@ object CommonMethod { success() return } + + val list = LocalPhotoTemplateControl.buildPhotoTemplate(orderInfo) + list.forEachIndexed { _, item -> + val photoTemplateInfo = item.copy(userOrderId = orderInfo?.userOrderId, + taskCode = orderInfo?.taskCode, + myCustomPhotoType = Const.PhotoType.InServicing, + advanceTime = orderInfo?.advanceTime, + taskId = orderInfo?.taskId, + serviceTypeName = orderInfo?.serviceTypeName, + needWaterMarker = orderInfo?.needWaterMarker, + needShowPhoneBrand = orderInfo?.needShowPhoneBrand, + photoSource = 0) + RoomHelper.db?.photoTemplateDao()?.insert(photoTemplateInfo) + } + LogUtil.print("queryPhotoTemplate", "使用本地模版==${listData.toJson()}") + success() + return + } + + val listData = RoomHelper.db?.photoTemplateDao() + ?.queryCurrentOrderHasTaskNode(orderInfo?.userOrderId ?: 0) + if (! listData.isNullOrEmpty()) { + LogUtil.print("queryPhotoTemplate", "模板已经存在==${listData.toJson()}") + success() + return } it.forEachIndexed { _, item -> @@ -365,6 +352,7 @@ object CommonMethod { taskCode = orderInfo?.taskCode, myCustomPhotoType = Const.PhotoType.InServicing, advanceTime = orderInfo?.advanceTime, + serviceTypeName = orderInfo?.serviceTypeName, taskId = orderInfo?.taskId, needWaterMarker = orderInfo?.needWaterMarker, needShowPhoneBrand = orderInfo?.needShowPhoneBrand, @@ -377,7 +365,30 @@ object CommonMethod { override fun doFailure(code : Int, msg : String?) { LogUtil.print("fetchPhotoTemplate", "err==$msg") - failed(msg) + val listData = RoomHelper.db?.photoTemplateDao() + ?.queryCurrentOrderHasTaskNode(orderInfo?.userOrderId ?: 0) + if (! listData.isNullOrEmpty()) { + LogUtil.print("queryPhotoTemplate", "模板已经存在==${listData.toJson()}") + success() + return + } + + val list = LocalPhotoTemplateControl.buildPhotoTemplate(orderInfo) + list.forEachIndexed { _, item -> + val photoTemplateInfo = item.copy(userOrderId = orderInfo?.userOrderId, + taskCode = orderInfo?.taskCode, + myCustomPhotoType = Const.PhotoType.InServicing, + advanceTime = orderInfo?.advanceTime, + serviceTypeName = orderInfo?.serviceTypeName, + taskId = orderInfo?.taskId, + needWaterMarker = orderInfo?.needWaterMarker, + needShowPhoneBrand = orderInfo?.needShowPhoneBrand, + photoSource = 0) + RoomHelper.db?.photoTemplateDao()?.insert(photoTemplateInfo) + } + LogUtil.print("queryPhotoTemplate", "使用本地模版==${listData.toJson()}") + success() + return } }) } @@ -406,7 +417,8 @@ object CommonMethod { carVin = it?.vinNo, serviceContent = it?.serviceTerm, serverAcceptCarSignPath = it?.recipientSignPath, - serverServicePeopleSignPath = it?.waitstaffSignPath, + serverServicePeopleSignPath = it?.waitstaffSignPath + ?: GlobalData.driverInfoBean?.signatureUrl, orderType = it?.serviceName) it?.damageFileList?.forEach { item -> val damagePhotoBean = EleCarDamagePhotoBean(userOrderId = it.userOrderId, @@ -417,6 +429,7 @@ object CommonMethod { RoomHelper.db?.eleCarDamagePhotoDao()?.insert(damagePhotoBean) } RoomHelper.db?.eleWorkOrderDao()?.insertEleWorkOrder(temp) + LogUtil.print("queryElectronOrder", "插入成功 ${temp.toJson()}") success(temp) } diff --git a/servicing/src/main/java/com/za/net/LocalPhotoTemplateControl.kt b/servicing/src/main/java/com/za/net/LocalPhotoTemplateControl.kt new file mode 100644 index 0000000..9ae3012 --- /dev/null +++ b/servicing/src/main/java/com/za/net/LocalPhotoTemplateControl.kt @@ -0,0 +1,1121 @@ +package com.za.net + +import com.za.base.Const +import com.za.bean.db.order.OrderInfo +import com.za.bean.db.order.PhotoTemplateInfo +import com.za.common.log.LogUtil +import com.za.servicing.R + +object LocalPhotoTemplateControl { + + fun buildPhotoTemplate(orderInfo : OrderInfo?) : List { + if (orderInfo == null) { + LogUtil.print("buildPhotoTemplate", "订单信息为空") + return emptyList() + } + val checkVehicleList = buildCheckVehiclePhotoTemplate(orderInfo) + val operationList = buildOperationPhotoTemplate(orderInfo) + val operationPhot = buildArriveDestinationPhotoTemplate(orderInfo) + val orderConfirmList = buildOrderConfirmPhotoTemplate(orderInfo) + val giveUpList = buildGiveUpPhotoTemplate() + + val list = arrayListOf() + + checkVehicleList.forEach { + list.add(it) + } + + operationList.forEach { + list.add(it) + } + + operationPhot.forEach { + list.add(it) + } + + orderConfirmList.forEach { + list.add(it) + } + + giveUpList.forEach { + list.add(it) + } + + return list + } + + private fun buildCheckVehiclePhotoTemplate(orderInfoBean : OrderInfo) : List { + val flowType = orderInfoBean.flowType + var orderType = orderInfoBean.serviceTypeName + if (orderType == "移动充电(搭电)") { + orderType = "移动充电" + } + val list = arrayListOf() + + if (flowType == Const.TUO_CHE) { + if (orderInfoBean.orderSource?.contains("人保") == true) { // 人保案件 拍摄四角照片 + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "被救车辆左前角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_car_left_front}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "被救车辆右前角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_car_right_front}", + doHaveFilm = 1, + sort = 2, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "被救车辆右后角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_car_right_back}", + doHaveFilm = 1, + sort = 3, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "被救车辆左后角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_car_right_back}", + doHaveFilm = 1, + sort = 4, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "被救车辆车架号码照片", + imageDescription = "照片要清晰显示被救车辆车架号码", + photoUrl = "${R.mipmap.vin_photo}", + doHaveFilm = 1, + sort = 5, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + list.add(photoTemplateInfo5) + } else { + val photoTemplateInfo1 = + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == true || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "照片要清晰显示被救车车牌号,救援师傅需穿平安专用橙色马甲(拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算)", + photoUrl = "${R.mipmap.car_and_driver_pingan}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "照片要清晰显示被救车车牌号(拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算)", + photoUrl = "${R.mipmap.car_and_driver}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "被救车辆正面照片", + imageDescription = "车头正前方2-3米拍摄整车照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_front}", + doHaveFilm = 1, + sort = 2, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "被救车辆车架号码照片", + imageDescription = "照片要清晰显示被救车辆车架号码", + photoUrl = "${R.mipmap.vin_photo}", + doHaveFilm = 1, + sort = 3, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "被救车辆损伤照片", + imageDescription = "在验车时如发现被救车辆有车损/划痕的,需拍摄实际损伤部位", + photoUrl = "${R.mipmap.damage_photo}", + doHaveFilm = 1, + sort = 4, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + } + } else if (orderType?.contains("困境") == true) { + if (orderInfoBean.orderSource?.contains("人保") == true) { + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "被救车辆左前角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_dilemma_left_front}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "被救车辆右前角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_dilemma_right_front}", + doHaveFilm = 1, + sort = 2, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "被救车辆右后角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_car_right_back}", + doHaveFilm = 1, + sort = 3, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "被救车辆左后角照片", + imageDescription = "照片要清晰显示被救车车牌号,拖车B点照片不得出现修理厂、4S店等车辆维修场所,否则会影响结算(免拖50公里车辆不受此限制)", + photoUrl = "${R.mipmap.bg_car_left_back}", + doHaveFilm = 1, + sort = 4, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + } else { + val photoTemplateInfo1 = + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == true || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片,救援师傅需穿平安专用橙色马甲(特殊情况造成无法合影的除外)", + photoUrl = "${R.mipmap.car_and_driver_pingan}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片(特殊情况造成无法合影的除外)", + photoUrl = "${R.mipmap.car_and_driver}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "被救车辆正面照片", + imageDescription = "车头正前方2-3米拍摄整车照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_front}", + doHaveFilm = 1, + sort = 2, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "整车处于困境中的照片", + imageDescription = "照片要清晰显示车牌号码及周边环境", + photoUrl = "${R.mipmap.plight_vehicle}", + doHaveFilm = 1, + sort = 3, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "被救车辆损伤照片", + imageDescription = "在验车时如发现被救车辆有车损/划痕的,需拍摄实际损伤部位", + photoUrl = "${R.mipmap.damage_photo}", + doHaveFilm = 0, + sort = 4, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + } + } else if (orderType?.contains("移动充电") == true) { + + val photoTemplateInfo1 = + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == true || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片,照片要清晰显示被救车车牌号,救援师傅需穿平安专用橙色马甲", + photoUrl = "${R.mipmap.car_and_driver_pingan}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_and_driver}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "被救车辆车架号码照片", + imageDescription = "照片要清晰显示被救车辆车架号码", + photoUrl = "${R.mipmap.vin_photo}", + doHaveFilm = 1, + sort = 2, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "充电前仪表盘照片", + imageDescription = "需体现充电前,客户车辆仪表盘的剩余电量和剩余公里数", + photoUrl = "${R.mipmap.mobile_charging_dashboard_photo}", + doHaveFilm = 1, + sort = 3, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "被救车辆正面照片", + imageDescription = "车头正前方2-3米拍摄整车照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_front}", + doHaveFilm = 1, + sort = 4, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + + } else if (orderType?.contains("搭电") == true) { + + val photoTemplateInfo1 = + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == true || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片,照片要清晰显示被救车车牌号,救援师傅需穿平安专用橙色马甲", + photoUrl = "${R.mipmap.car_and_driver_pingan}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_and_driver}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "被救车辆车架号码照片", + imageDescription = "照片要清晰显示被救车辆车架号码", + photoUrl = "${R.mipmap.vin_photo}", + doHaveFilm = 1, + sort = 2, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "搭电前仪表盘照片", + imageDescription = "让客户启动一下车辆,拍摄仪表盘点亮后的照片(搭电前务必关闭电门)", + photoUrl = "${R.mipmap.dashboard_photo}", + doHaveFilm = 1, + sort = 3, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "被救车辆正面照片", + imageDescription = "车头正前方2-3米拍摄整车照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_front}", + doHaveFilm = 1, + sort = 4, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + + } else { + val photoTemplateInfo1 = + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == true || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片,照片要清晰显示被救车车牌号,救援师傅需穿平安专用橙色马甲", + photoUrl = "${R.mipmap.car_and_driver_pingan}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "救援师傅人车合影", + imageDescription = "救援师傅与被救车辆合影照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_and_driver}", + doHaveFilm = 1, + sort = 1, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + } + + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "被救车辆车架号码照片", + imageDescription = "照片要清晰显示被救车辆车架号码", + photoUrl = "${R.mipmap.vin_photo}", + doHaveFilm = 1, + sort = 2, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "被救车辆损伤照片", + imageDescription = "在验车时如发现被救车辆有车损/划痕的,需拍摄实际损伤部位", + photoUrl = "${R.mipmap.damage_photo}", + doHaveFilm = 1, + sort = 3, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "被救车辆正面照片", + imageDescription = "车头正前方2-3米拍摄整车照片,照片要清晰显示被救车车牌号", + photoUrl = "${R.mipmap.car_front}", + doHaveFilm = 1, + sort = 4, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + } + + if (orderInfoBean.orderSource?.contains("永安") == true) { + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "被救车辆行驶证和驾驶证照片", + imageDescription = "", + photoUrl = "${R.mipmap.bg_licenses}", + doHaveFilm = 1, + sort = 5, + taskNode = 13001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } + return list + } + + private fun buildOperationPhotoTemplate(orderInfoBean : OrderInfo) : List { + val flowType = orderInfoBean.flowType + var orderType = orderInfoBean.serviceTypeName + if (orderType == "移动充电(搭电)") { + orderType = "移动充电" + } + val list = arrayListOf() + + if (flowType == Const.TUO_CHE) { + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "仪表盘照片", + imageDescription = "背车前拍摄清晰的仪表盘照片。燃油耗尽或新能源车辆电量耗尽需要拖车、仪表盘须体现燃油耗尽或续航里程不足20KM。", + photoUrl = "${R.mipmap.no_oil}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "完成装车照片", + imageDescription = "车辆正后方2-3米拍摄被救车辆已上车的照片,照片要清晰显示被救车辆和施救车辆车牌号", + photoUrl = "${R.mipmap.finish_loading}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "架小轮照片", + imageDescription = "须清晰体现抛锚车架小轮后,在拖车上板之后的情况以及小轮数量", + photoUrl = "${R.mipmap.ferry_sample}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = if (orderInfoBean.addressProperty == "地下车库") { + PhotoTemplateInfo(imageTitle = "地库案件照片", + imageDescription = "须清晰体现车辆车牌、地库环境,地库救援车辆的照片", + photoUrl = "${R.mipmap.bg_underground}", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 4, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + } + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + + } else if (orderType?.contains("困境") == true) { + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "救援过程照片", + imageDescription = "能清晰反映救援项目,被救车车牌号,救援过程中使用的救援车辆、救援设备", + photoUrl = "${R.mipmap.kunjing}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "整车脱离困境的照片", + imageDescription = "照片要清晰显示车牌号码及周边环境", + photoUrl = "${R.mipmap.vehicle_escape}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "被救车辆车架号码照片", + imageDescription = "照片要清晰显示被救车辆车架号码", + photoUrl = "${R.mipmap.vin_photo}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.bg_underground}", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 2, + recognizeType = 0) + + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + if (orderInfoBean.orderSource?.startsWith("太保") == true) { + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "搭电后被救车辆仪表盘照片", + imageDescription = "清晰拍摄车辆成功发动状态下的仪表盘照片", + photoUrl = "${R.mipmap.dadianhou}", + doHaveFilm = 1, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } else { + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + photoUrl = "${R.mipmap.bg_underground}", + doHaveFilm = 0, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } + } else if (orderType?.contains("移动充电") == true) { + + val photoTemplateInfo1 = + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == true || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + PhotoTemplateInfo(imageTitle = "充电前仪表盘照片", + imageDescription = "需体现充电前,客户车辆仪表盘的剩余电量和剩余公里数".takeIf { orderInfoBean.ECDeviceString.isNullOrBlank() } + ?: orderInfoBean.ECDeviceString, + photoUrl = "${R.mipmap.car_and_driver_pingan}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "充电前仪表盘照片", + imageDescription = "需体现充电前,客户车辆仪表盘的剩余电量和剩余公里数", + photoUrl = "${R.mipmap.car_and_driver_pingan}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + } + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "充电过程照片", + imageDescription = "能清晰反映客户车牌,能体现移动充电的状态", + photoUrl = "${R.mipmap.mobile_charing_process_photo}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "充电后仪表盘照片", + imageDescription = "需体现充电结束后,客户和车辆仪表盘的剩余电量和剩余公里数", + photoUrl = "${R.mipmap.mobile_charging_dashboard_photo}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 2, + recognizeType = 0) + + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + list.add(photoTemplateInfo5) + + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == false || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + val photoTemplateInfo6 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 6, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo6) + } + + } else if (orderType?.contains("搭电") == true) { + val photoTemplateInfo1 = + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == true || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + PhotoTemplateInfo(imageTitle = "电瓶检测照片(平安搭电案件要求)", + imageDescription = "需体现充电前,客户车辆仪表盘的剩余电量和剩余公里数".takeIf { orderInfoBean.ECDeviceString.isNullOrBlank() } + ?: orderInfoBean.ECDeviceString, + photoUrl = "${R.mipmap.dadian_device}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + } else { + PhotoTemplateInfo(imageTitle = "电瓶检测照片(平安搭电案件要求)", + imageDescription = "正面拍摄电瓶检测仪显示屏测试结果照片,需体现夹子夹在正负极;显示屏需清晰体现设置值、测试值、寿命及测试结果;拍摄时间需在搭电过程照之前;如果搭电前电瓶检测仪无显示,需在搭电完成后再拍摄一次电瓶检测仪", + photoUrl = "${R.mipmap.dadian_device}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + } + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "搭电接线状态照片", + imageDescription = "在被救车辆正前方2-3米拍摄整车,拍摄时被救援车辆引擎盖必须是打开状态,能清晰反映被救车车牌,能体现接线状态", + photoUrl = "${R.mipmap.dadian}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "搭电后仪表盘照片", + imageDescription = "搭电结束后,仪表盘点亮的照片", + photoUrl = "${R.mipmap.dadianhou}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 2, + recognizeType = 0) + + + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + list.add(photoTemplateInfo5) + + if (orderInfoBean.orderSource?.contains("平安财险非事故道路救援") == false || orderInfoBean.orderSource?.contains( + "CYY") == true + ) { + val photoTemplateInfo6 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 6, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo6) + } + + } else if (orderType?.contains("换胎") == true) { + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "换胎前照片", + imageDescription = "须体现轮胎损坏情况和被救车车牌号", + photoUrl = "${R.mipmap.tyre_pre}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "换胎中照片", + imageDescription = "轮胎必须是卸下 状态,和备胎放在一起拍摄,须体现被救车车牌号", + photoUrl = "${R.mipmap.huantai_photo}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "轮胎更换完成照片", + imageDescription = "需清晰拍摄轮胎更换完成照片,体现出被救车车牌号", + photoUrl = "${R.mipmap.huantai_success}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${ + R.mipmap.work_order1 + }", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 2, + recognizeType = 0) + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + if (orderInfoBean.orderSource?.startsWith("太保") == true) { + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "搭电后被救车辆仪表盘照片", + imageDescription = "清晰拍摄车辆成功发动状态下的仪表盘照片", + photoUrl = "${R.mipmap.dadianhou}", + doHaveFilm = 1, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } else { + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + photoUrl = "${R.mipmap.bg_underground}", + doHaveFilm = 0, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } + } else if (orderType?.contains("充气") == true) { + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "充气前照片", + imageDescription = "需体现轮胎没气和车牌号", + photoUrl = "${R.mipmap.tyre_inflate_pre}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "充气中照片", + imageDescription = "需显示充气设备和轮胎充气口相连接(未断开)", + photoUrl = "${R.mipmap.tyre_inflate_ing}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "充气完成照片", + imageDescription = "需清晰拍摄轮胎充气完成照片,体现出被救车车牌号。", + photoUrl = "${R.mipmap.tyre_inflate_ing_success}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 2, + recognizeType = 0) + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + if (orderInfoBean.orderSource?.startsWith("太保") == true) { + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "搭电后被救车辆仪表盘照片", + imageDescription = "清晰拍摄车辆成功发动状态下的仪表盘照片", + photoUrl = "${R.mipmap.dadianhou}", + doHaveFilm = 1, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } else { + val photoTemplateInfo5 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + photoUrl = "${R.mipmap.bg_underground}", + doHaveFilm = 0, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } + + } else { + if (orderInfoBean.orderSource?.contains("人保") == true && (orderType?.contains("送水") == true || orderType?.contains( + "送防冻液") == true) + ) { + + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "救援现场照片", + imageDescription = "在被救车辆正前方2-3米处45度角拍摄整车,被救援车辆机盖必须是打开状态", + photoUrl = "${R.mipmap.huantai_photo}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "加液前防冻液壶照片", + imageDescription = "", + photoUrl = "${R.mipmap.bg_water_tank_empty}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "加液后防冻液壶照片", + imageDescription = "", + photoUrl = "${R.mipmap.bg_water_tank_full}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 2, + recognizeType = 0) + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + + } else { + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "救援现场照片", + imageDescription = "在被救车辆正前方2-3米处45度角拍摄整车,照片必须清晰反映救援项目、被救车辆车牌号码与车辆外观(现场抢修、加水、加油照片拍摄时被救援车辆机盖必须是打开状态)", + photoUrl = "${R.mipmap.huantai_photo}", + doHaveFilm = 1, + sort = 1, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "加液后防冻液壶照片", + imageDescription = "", + photoUrl = "${R.mipmap.bg_water_tank_full}", + doHaveFilm = 1, + sort = 2, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 3, + taskNode = 15001, + photoType = 2, + recognizeType = 0) + + val photoTemplateInfo4 = + PhotoTemplateInfo(imageTitle = "防冻液/水购买凭证或发票照片", + imageDescription = "若没有此照片,相关的购买费用不得报销", + doHaveFilm = 1, + sort = 4, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + + if (orderInfoBean.orderSource?.startsWith("太保") == true) { + val photoTemplateInfo5 = + PhotoTemplateInfo(imageTitle = "搭电后被救车辆仪表盘照片", + imageDescription = "清晰拍摄车辆成功发动状态下的仪表盘照片", + photoUrl = "${R.mipmap.dadianhou}", + doHaveFilm = 1, + sort = 5, + taskNode = 15001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo5) + } + } + } + return list + } + + private fun buildArriveDestinationPhotoTemplate(orderInfoBean : OrderInfo) : List { + val list = arrayListOf() + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "拖车终点(C点)照片", + imageDescription = "在拖车终点,对被救援车辆整车进行拍照, 须显示被救车车牌号,并能反映出 修理厂、4S店等车辆维修场所", + photoUrl = "${R.mipmap.trailer_3}", + doHaveFilm = 1, + sort = 1, + taskNode = 17001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo1) + if (orderInfoBean.orderSource?.contains("比亚迪") == true) { + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "接车人合影照片", + imageDescription = "工作时间接车拍摄:救援人员、交接服务顾问及故障车辆合影照片;\n" + "非工作时间接车拍摄:救援人员、交接值班人员及故障车辆合影照片", + photoUrl = "${R.mipmap.bg_byd_dest_car_mans}", + doHaveFilm = 1, + sort = 2, + taskNode = 17001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 3, + taskNode = 17001, + photoType = 2, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 4, + taskNode = 17001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + } else if (orderInfoBean.orderSource?.contains("人保") == true) { + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "车辆加油/充电照片", + imageDescription = "车辆加油/充电案件,到达C点(加油站/充电桩)后,须增加拍摄车辆加油/充电照片", + photoUrl = "${R.mipmap.bg_byd_dest_car_mans}", + doHaveFilm = 0, + sort = 2, + taskNode = 17001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 3, + taskNode = 17001, + photoType = 2, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 4, + taskNode = 17001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + + } else { + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "车辆状况检查表照片", + imageDescription = "要求有客户签字确认,否则按照放空结算。", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 2, + taskNode = 17001, + photoType = 2, + recognizeType = 0) + + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 3, + taskNode = 17001, + photoType = 1, + recognizeType = 0) + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 4, + taskNode = 17001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + } + return list + } + + private fun buildOrderConfirmPhotoTemplate(orderInfoBean : OrderInfo) : List { + val flowType = orderInfoBean.flowType + val list = arrayListOf() + if (flowType == Const.TUO_CHE) { + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "AB段路桥费", + imageDescription = "拍摄相对应的路桥费照片,客户已支付的路桥费无需提供照片。电子路桥费,不能只提供支付凭证照片,一定要提供发票照片。", + photoUrl = "${R.mipmap.invoice_sample}", + doHaveFilm = 0, + sort = 1, + numbering = "P.1", + taskNode = 18001, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "BC段路桥费", + imageDescription = "拍摄相对应的路桥费照片,客户已支付的路桥费无需提供照片。电子路桥费,不能只提供支付凭证照片,一定要提供发票照片。", + photoUrl = "${R.mipmap.invoice_sample}", + doHaveFilm = 0, + sort = 1, + numbering = "P.2", + taskNode = 18001, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + } + + return list + } + + private fun buildGiveUpPhotoTemplate() : List { + val list = arrayListOf() + val photoTemplateInfo1 = PhotoTemplateInfo(imageTitle = "空驶案件照片", + imageDescription = "半途放空:需体现救援车和放空时行驶停止点的周边环境,如路标、路牌等\n到达现场放空:需拍摄被救援车辆照片", + photoUrl = "${R.mipmap.work_order1}", + doHaveFilm = 1, + sort = 1, + taskNode = 18100, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo2 = PhotoTemplateInfo(imageTitle = "工单照片", + imageDescription = "要求有客户签字确认", + doHaveFilm = 0, + sort = 2, + taskNode = 18100, + photoType = 2, + recognizeType = 0) + val photoTemplateInfo3 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 3, + taskNode = 18100, + photoType = 1, + recognizeType = 0) + + val photoTemplateInfo4 = PhotoTemplateInfo(imageTitle = "其他", + imageDescription = "", + doHaveFilm = 0, + sort = 4, + taskNode = 18100, + photoType = 1, + recognizeType = 0) + list.add(photoTemplateInfo1) + list.add(photoTemplateInfo2) + list.add(photoTemplateInfo3) + list.add(photoTemplateInfo4) + return list + } +} \ No newline at end of file diff --git a/servicing/src/main/java/com/za/offline/OfflineManager.kt b/servicing/src/main/java/com/za/offline/OfflineManager.kt index 905d6a9..f9999bc 100644 --- a/servicing/src/main/java/com/za/offline/OfflineManager.kt +++ b/servicing/src/main/java/com/za/offline/OfflineManager.kt @@ -91,7 +91,7 @@ object OfflineManager { } } - private fun stop() { + fun stop() { uploadDispose?.dispose() uploadDispose = null isUploading = false diff --git a/servicing/src/main/java/com/za/room/RoomHelper.kt b/servicing/src/main/java/com/za/room/RoomHelper.kt index 07a47a0..b4764e3 100644 --- a/servicing/src/main/java/com/za/room/RoomHelper.kt +++ b/servicing/src/main/java/com/za/room/RoomHelper.kt @@ -11,7 +11,7 @@ import com.za.room.db.GlobalRoom @SuppressLint("StaticFieldLeak") object RoomHelper { - const val VERSION: Int = 41 + const val VERSION: Int = 43 private lateinit var mContext: Context var db: GlobalRoom? = null diff --git a/servicing/src/main/java/com/za/room/db/order/OrderDao.kt b/servicing/src/main/java/com/za/room/db/order/OrderDao.kt index 56385ce..32520bf 100644 --- a/servicing/src/main/java/com/za/room/db/order/OrderDao.kt +++ b/servicing/src/main/java/com/za/room/db/order/OrderDao.kt @@ -16,6 +16,9 @@ interface OrderDao { @Query("select * from order_info where taskId =:taskId") fun getOrderInfoFromTaskId(taskId: Int): OrderInfo? + @Query("select * from order_info where taskCode =:taskCode") + fun getOrderInfoFromTaskCode(taskCode: String): OrderInfo? + //获取当前正在执行的订单 @Query("select * from order_info where isCurrent ==1") fun getCurrentOrder(): OrderInfo? diff --git a/servicing/src/main/java/com/za/room/db/user/DriverInfoBean.kt b/servicing/src/main/java/com/za/room/db/user/DriverInfoBean.kt index b6aafe3..ff5fda8 100644 --- a/servicing/src/main/java/com/za/room/db/user/DriverInfoBean.kt +++ b/servicing/src/main/java/com/za/room/db/user/DriverInfoBean.kt @@ -23,4 +23,5 @@ data class DriverInfoBean( val vehicleState : Int? = null, //车辆状态 0 空闲 1 忙碌 val plateNumber : String? = null, //车牌号 val deviceId : String? = null, + val signatureUrl : String? = null, //手写签名照地址 ) : Parcelable \ No newline at end of file diff --git a/servicing/src/main/java/com/za/service/ServiceManager.kt b/servicing/src/main/java/com/za/service/ServiceManager.kt index 9e4b5b4..81f199d 100644 --- a/servicing/src/main/java/com/za/service/ServiceManager.kt +++ b/servicing/src/main/java/com/za/service/ServiceManager.kt @@ -30,6 +30,7 @@ interface PushListener { fun reDispatchOrder(jpushBean : JpushBean) fun broadcast(string : String) fun importantTip(jpushBean : JpushBean) + fun reportHandle(jpushBean : JpushBean) } data class LastJPushBean(val msg : String, val time : Long = System.currentTimeMillis()) @@ -67,33 +68,49 @@ object ServiceManager { private fun setupPushMessageReceiver(context : Context) { // 注册推送消息接收器 registerPushListener(object : PushListener { override fun broadcast(msg : String) { - sendMessageToMainProcess(context = context, "broadcast", msg) + sendMessageToMainProcess(context = context, Const.PushMessageType.BROADCAST, msg) } override fun giveUpOrder(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, "giveUp", Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.GIVE_UP, + Gson().toJson(jpushBean)) } override fun importantTip(jpushBean : JpushBean) { sendMessageToMainProcess(context = context, - "importantTip", + Const.PushMessageType.IMPORTANT_TIP, Gson().toJson(jpushBean)) } override fun newOrderMsg(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, "newOrder", Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.NEW_ORDER, + Gson().toJson(jpushBean)) } override fun reDispatchOrder(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, "reDispatch", Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.RE_DISPATCH, + Gson().toJson(jpushBean)) } override fun revokeOrder(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, "revoke", Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.REVOKE, + Gson().toJson(jpushBean)) } override fun modifyOrder(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, "modify", Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.MODIFY, + Gson().toJson(jpushBean)) + } + + override fun reportHandle(jpushBean : JpushBean) { + sendMessageToMainProcess(context = context, + Const.PushMessageType.REPORT_HANDLE, + Gson().toJson(jpushBean)) } }) } @@ -145,6 +162,7 @@ object ServiceManager { 1 -> handleTypeOneMessage(jpushOrderInfoBean) 2 -> handlerModifyOrderMessage(jpushOrderInfoBean) 3 -> importantTip(jpushOrderInfoBean) + 4 -> reportHandler(jpushOrderInfoBean) else -> LogUtil.print("JpushMessage", "Unknown push type: ${jpushOrderInfoBean.pushType}") } @@ -171,9 +189,9 @@ object ServiceManager { // Handle type one messages private fun handleTypeOneMessage(jpushOrderBean : JpushBean) { when (jpushOrderBean.typeDesc) { - "giveUp" -> giveUpOrder(jpushOrderBean) - "revoke" -> revokeOrder(jpushOrderBean) - "reDispatch" -> reDispatchOrder(jpushOrderBean) + Const.PushMessageType.GIVE_UP -> giveUpOrder(jpushOrderBean) + Const.PushMessageType.REVOKE -> revokeOrder(jpushOrderBean) + Const.PushMessageType.RE_DISPATCH -> reDispatchOrder(jpushOrderBean) else -> LogUtil.print("JpushMessage", "Unknown typeDesc: ${jpushOrderBean.typeDesc}") } } @@ -218,6 +236,10 @@ object ServiceManager { pushListener?.importantTip(jpushOrderBean) } + private fun reportHandler(jpushOrderBean : JpushBean) { + pushListener?.reportHandle(jpushOrderBean) + } + // Disconnect from JPush and MQTT fun disconnect(context : Context) { Handler(Looper.getMainLooper()).post { @@ -259,13 +281,13 @@ object ServiceManager { 1 -> { when (jpushOrderInfoBean.typeDesc) { - "giveUp" -> sendNotification(GlobalData.application, + Const.PushMessageType.GIVE_UP -> sendNotification(GlobalData.application, "订单:${jpushOrderInfoBean.taskCode ?: ""}已被放弃!") - "revoke" -> sendNotification(GlobalData.application, + Const.PushMessageType.REVOKE -> sendNotification(GlobalData.application, "订单:${jpushOrderInfoBean.taskCode ?: ""}已被撤回!") - "reDispatch" -> sendNotification(GlobalData.application, + Const.PushMessageType.RE_DISPATCH -> sendNotification(GlobalData.application, "订单:${jpushOrderInfoBean.taskCode ?: ""}被改派!") else -> {} diff --git a/servicing/src/main/java/com/za/service/ZdPushServiceReceive.kt b/servicing/src/main/java/com/za/service/ZdPushServiceReceive.kt index b1209ad..151e332 100644 --- a/servicing/src/main/java/com/za/service/ZdPushServiceReceive.kt +++ b/servicing/src/main/java/com/za/service/ZdPushServiceReceive.kt @@ -22,7 +22,9 @@ import com.za.bean.JpushBean import com.za.common.GlobalData import com.za.common.log.LogUtil import com.za.common.speech.SpeechManager +import com.za.room.RoomHelper import com.za.servicing.R +import com.za.ui.order_report.ReportFloatingManager import com.za.ui.servicing.order_give_up.OrderGiveUpActivity import com.za.ui.view.CommonDialogFragment @@ -113,6 +115,20 @@ class ZdPushServiceReceive : BroadcastReceiver() { } } + Const.PushMessageType.REPORT_HANDLE -> { + try { + val jpushBean = Gson().fromJson(message, JpushBean::class.java) + val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity() + ?: ActivityUtils.getTopActivity() + if (activity is AppCompatActivity) { + handeReportMessage(jpushBean = jpushBean) + } + } catch (e : Exception) { + LogUtil.print("PushActivityLifecycleCallbacks", + "处理重要提示消息失败: ${e.message}") + } + } + } } } @@ -183,6 +199,24 @@ class ZdPushServiceReceive : BroadcastReceiver() { } } + private fun handeReportMessage(jpushBean : JpushBean) { + SpeechManager.speech("您提交的报批已经处理!") + BaseActivityLifecycleCallbacks.getCurrentActivity()?.let { currentActivity -> + if (currentActivity is AppCompatActivity) { + AlertDialog.Builder(currentActivity).setTitle("提醒") + .setMessage("您提交的报批已经处理,是否前往查看?") + .setPositiveButton("确定") { dialog, _ -> + dialog.dismiss() + currentActivity.finish() + val order = RoomHelper.db?.orderDao() + ?.getOrderInfoFromTaskCode(taskCode = jpushBean.taskCode ?: "") + ReportFloatingManager.goReportPage(context = currentActivity, + orderInfo = order) + }.show() + } + } + } + // Handle broadcast messages private fun handleBroadcast(msg : String) { try { diff --git a/servicing/src/main/java/com/za/service/mqtt/ConnectionOptionWrapper.kt b/servicing/src/main/java/com/za/service/mqtt/ConnectionOptionWrapper.kt index 2f82ea9..56b1a26 100644 --- a/servicing/src/main/java/com/za/service/mqtt/ConnectionOptionWrapper.kt +++ b/servicing/src/main/java/com/za/service/mqtt/ConnectionOptionWrapper.kt @@ -21,6 +21,7 @@ class ConnectionOptionWrapper( isCleanSession = true keepAliveInterval = 90 // Keep alive interval in seconds isAutomaticReconnect = true + maxInflight = 1000 mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1 connectionTimeout = 30 // Connection timeout in seconds } diff --git a/servicing/src/main/java/com/za/service/mqtt/MyMqttClient.kt b/servicing/src/main/java/com/za/service/mqtt/MyMqttClient.kt index 351b9b9..8c25784 100644 --- a/servicing/src/main/java/com/za/service/mqtt/MyMqttClient.kt +++ b/servicing/src/main/java/com/za/service/mqtt/MyMqttClient.kt @@ -1,67 +1,54 @@ package com.za.service.mqtt -import android.os.Handler -import android.os.Looper -import android.util.Log +import android.annotation.SuppressLint import com.za.common.GlobalData import com.za.common.log.LogUtil +import com.za.common.util.DeviceUtil +import com.za.common.util.Tools.macSignature import com.za.service.ServiceManager -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import org.eclipse.paho.android.service.MqttAndroidClient +import org.eclipse.paho.client.mqttv3.IMqttActionListener import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken -import org.eclipse.paho.client.mqttv3.MqttCallbackExtended -import org.eclipse.paho.client.mqttv3.MqttClient +import org.eclipse.paho.client.mqttv3.IMqttToken +import org.eclipse.paho.client.mqttv3.MqttCallback +import org.eclipse.paho.client.mqttv3.MqttConnectOptions import org.eclipse.paho.client.mqttv3.MqttException import org.eclipse.paho.client.mqttv3.MqttMessage import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence +import kotlin.concurrent.Volatile + object MyMqttClient { private lateinit var clientId : String private lateinit var topic : String - private val mqttClient : MqttClient by lazy { - MqttClient("tcp://${MqttConfig.END_POINT}:1883", clientId, MemoryPersistence()) - } - - private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) - private val _connectionState = MutableStateFlow(false) - private val connectionState : StateFlow = _connectionState + @SuppressLint("StaticFieldLeak") + private var mqttClient : MqttAndroidClient? = null fun initialize(deviceId : String?) { clientId = "${MqttConfig.GROUP_ID}@@@$deviceId" topic = "${MqttConfig.TOPIC_PREFIX}/$clientId" + mqttClient = MqttAndroidClient(GlobalData.application, + "tcp://${MqttConfig.END_POINT}:1883", + clientId, + MemoryPersistence()) setupMqttCallbacks() connect() LogUtil.print("MyMqttClient ", "initialize success") - Log.e("MyMqttClient ", "initialize success") } private fun setupMqttCallbacks() { - mqttClient.setCallback(object : MqttCallbackExtended { - override fun connectComplete(reconnect : Boolean, serverURI : String) { - val status = if (reconnect) "Reconnected" else "Connected" - LogUtil.print("MyMqttClient ", "$status to: $serverURI") - _connectionState.value = true - subscribeTopic() - } + mqttClient?.setCallback(object : MqttCallback { override fun connectionLost(throwable : Throwable) { - LogUtil.print("MyMqttClient ", "Connection lost: ${throwable.message}") - _connectionState.value = false + LogUtil.print("MyMqttClient ", + "Connection lost: ${throwable.message}") // connect() } override fun messageArrived(topic : String, mqttMessage : MqttMessage) { - Handler(Looper.getMainLooper()).post { - val message = String(mqttMessage.payload) - LogUtil.print("MyMqttClient ", "Message arrived: $message") - ServiceManager.handlerPushMsg(message) - } + val message = String(mqttMessage.payload) + LogUtil.print("MyMqttClient ", "Message arrived: $message") + ServiceManager.handlerPushMsg(message) } override fun deliveryComplete(token : IMqttDeliveryToken) { @@ -70,64 +57,102 @@ object MyMqttClient { }) } + + @Volatile + private var isConnecting : Boolean? = null private fun connect() { - if (connectionState.value && mqttClient.isConnected) { - LogUtil.print("MyMqttClient ", "Already connected") + if (isConnecting == true) { return } + try { + isConnecting = true - coroutineScope.launch { - try { - val options = ConnectionOptionWrapper(MqttConfig.INSTANCE_ID, - MqttConfig.ACCESS_KEY, - clientId, - MqttConfig.SECRET_KEY).mqttConnectOptions + val mqttConnectOption = MqttConnectOptions() + mqttConnectOption.userName = + "Signature|" + MqttConfig.ACCESS_KEY + "|" + MqttConfig.INSTANCE_ID + mqttConnectOption.password = macSignature(clientId, MqttConfig.SECRET_KEY).toCharArray() + mqttConnectOption.isCleanSession = true + mqttConnectOption.keepAliveInterval = 90 + mqttConnectOption.isAutomaticReconnect = true + mqttConnectOption.maxInflight = 1000 + mqttConnectOption.maxReconnectDelay = 30 * 1000 + mqttConnectOption.mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1 + mqttConnectOption.connectionTimeout = 30 - withContext(Dispatchers.IO) { - mqttClient.connect(options) + mqttClient?.connect(mqttConnectOption, null, object : IMqttActionListener { + override fun onSuccess(asyncActionToken : IMqttToken?) { + isConnecting = false + LogUtil.print("MyMqttClient ", "connect success==") + subscribeTopic() } - _connectionState.value = true // Update connection state after successful connection - } catch (e : MqttException) { - LogUtil.print("MyMqttClient ", "Connection failed: ${e.message}") - _connectionState.value = false // Update connection state on failure - } + + override fun onFailure(asyncActionToken : IMqttToken?, exception : Throwable?) { + isConnecting = false + LogUtil.print("MyMqttClient ", "connect failed== ${exception?.message}") + } + }) + } catch (e : MqttException) { + LogUtil.print("MyMqttClient ", "Connection failed2: ${e.message}") } } + //检测mqtt连接状态 fun publishMessage() { - if (mqttClient.isConnected) { + + if (mqttClient == null) { + initialize(deviceId = DeviceUtil.getAndroidId(GlobalData.application)) + return + } + + if (mqttClient?.isConnected == true) { LogUtil.print("MyMqttClient ", "mqttClient.hasConnected") return } + + connect() LogUtil.print("MyMqttClient ", "mqttClient 断开重新初始化") - ServiceManager.initialize(GlobalData.application) } private fun subscribeTopic() { - coroutineScope.launch { - try { - mqttClient.subscribe(topic, MqttConfig.QOS_LEVEL) - LogUtil.print("MyMqttClient ", "Subscribed to topic: $topic") - } catch (e : MqttException) { - LogUtil.print("MyMqttClient ", "Subscribe failed: ${e.message}") + try { + if (mqttClient?.isConnected == true) { + mqttClient?.subscribe(topic, + MqttConfig.QOS_LEVEL, + null, + object : IMqttActionListener { + override fun onSuccess(asyncActionToken : IMqttToken?) { + LogUtil.print("MyMqttClient ", "Subscribed to topic: $topic") + } + + override fun onFailure(asyncActionToken : IMqttToken?, + exception : Throwable) { + LogUtil.print("MyMqttClient ", "Subscribe failed: ${exception.message}") + } + }) + } else { + LogUtil.print("MyMqttClient ", "Cannot subscribe: MQTT client is not connected") } + } catch (e : MqttException) { + LogUtil.print("MyMqttClient ", "Subscribe failed2: ${e.message}") } } fun disconnect() { - coroutineScope.launch { - try { - if (connectionState.value) { - mqttClient.disconnect() - _connectionState.value = false - LogUtil.print("MyMqttClient ", "Disconnected successfully") - } - } catch (e : MqttException) { - LogUtil.print("MyMqttClient ", "Disconnect failed: ${e.message}") - } finally { - coroutineScope.cancel() + try { + if (mqttClient?.isConnected == true) { + mqttClient?.disconnect(null, object : IMqttActionListener { + override fun onSuccess(asyncActionToken : IMqttToken?) { + LogUtil.print("MyMqttClient ", "Disconnected") + } + + override fun onFailure(asyncActionToken : IMqttToken?, exception : Throwable) { + LogUtil.print("MyMqttClient ", "Disconnect failed") + } + }) } + } catch (e : MqttException) { + LogUtil.print("MyMqttClient ", "Disconnect failed: ${e.message}") } } } diff --git a/servicing/src/main/java/com/za/ui/h5/CommonH5Activity.kt b/servicing/src/main/java/com/za/ui/h5/CommonH5Activity.kt index d97e7d6..01ae4ed 100644 --- a/servicing/src/main/java/com/za/ui/h5/CommonH5Activity.kt +++ b/servicing/src/main/java/com/za/ui/h5/CommonH5Activity.kt @@ -6,11 +6,13 @@ import android.graphics.Color import android.view.ViewGroup import android.webkit.JavascriptInterface import androidx.activity.compose.BackHandler +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable @@ -23,6 +25,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.net.toUri +import coil.compose.AsyncImage import com.blankj.utilcode.util.ToastUtils import com.tencent.smtt.sdk.WebChromeClient import com.tencent.smtt.sdk.WebSettings @@ -35,6 +39,7 @@ import com.za.base.view.HeadView import com.za.common.GlobalData import com.za.common.log.LogUtil import com.za.ext.finish +import com.za.servicing.R class CommonH5Activity : BaseActivity() { private var webView : WebView? = null @@ -45,7 +50,6 @@ class CommonH5Activity : BaseActivity() { val url = intent.getStringExtra(EXTRA_URL) val title = intent.getStringExtra(EXTRA_TITLE) val isCanBack = intent.getBooleanExtra(EXTRA_CAN_BACK, true) - if (url.isNullOrBlank()) { ToastUtils.showLong("无效的URL") finish() @@ -165,7 +169,15 @@ private fun CommonH5Screen(url : String, Scaffold(topBar = { if (title.isNotBlank()) { - HeadView(title = title, onBack = { handleBackPress(context, webView) }) + HeadView(title = title, onBack = { handleBackPress(context, webView) }, action = { + AsyncImage(model = R.drawable.sv_browth, + contentDescription = "", + modifier = Modifier.size(24.dp).clickable{ + val intent = Intent(Intent.ACTION_VIEW) + intent.setData(url.toUri()) + context.startActivity(intent) + }) + }) } }) { paddingValues -> Box(modifier = Modifier @@ -186,6 +198,7 @@ private fun CommonH5Screen(url : String, webView = this onWebViewCreated(this) loadUrl(url) + LogUtil.print("H5Activity url", url) } }) @@ -228,6 +241,7 @@ private fun setupWebViewClients(webView : WebView, } override fun shouldOverrideUrlLoading(p0 : WebView?, p1 : String?) : Boolean { + LogUtil.print("H5Activity url", "$p1") p0?.loadUrl(p1) return false } diff --git a/servicing/src/main/java/com/za/ui/main/ServicingMainActivity.kt b/servicing/src/main/java/com/za/ui/main/ServicingMainActivity.kt index eed5310..98c2831 100644 --- a/servicing/src/main/java/com/za/ui/main/ServicingMainActivity.kt +++ b/servicing/src/main/java/com/za/ui/main/ServicingMainActivity.kt @@ -104,20 +104,34 @@ class ServicingMainActivity : BaseActivity() { Gson().toJson(jpushBean)) } + override fun reportHandle(jpushBean : JpushBean) { + sendMessageToMainProcess(context = context, + Const.PushMessageType.REPORT_HANDLE, + Gson().toJson(jpushBean)) + } + override fun newOrderMsg(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, Const.PushMessageType.NEW_ORDER, Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.NEW_ORDER, + Gson().toJson(jpushBean)) } override fun reDispatchOrder(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, Const.PushMessageType.RE_DISPATCH, Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.RE_DISPATCH, + Gson().toJson(jpushBean)) } override fun revokeOrder(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, Const.PushMessageType.REVOKE, Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.REVOKE, + Gson().toJson(jpushBean)) } override fun modifyOrder(jpushBean : JpushBean) { - sendMessageToMainProcess(context = context, Const.PushMessageType.MODIFY, Gson().toJson(jpushBean)) + sendMessageToMainProcess(context = context, + Const.PushMessageType.MODIFY, + Gson().toJson(jpushBean)) } }) } diff --git a/servicing/src/main/java/com/za/ui/main/ServicingMainVm.kt b/servicing/src/main/java/com/za/ui/main/ServicingMainVm.kt index 985c072..f0a23fc 100644 --- a/servicing/src/main/java/com/za/ui/main/ServicingMainVm.kt +++ b/servicing/src/main/java/com/za/ui/main/ServicingMainVm.kt @@ -87,9 +87,7 @@ class ServicingMainVm : BaseVm( return } GlobalData.token = it.token - CommonMethod.getGenerateInfo(vehicleId = it.vehicleId, - userId = it.userId, - success = { success() }, + CommonMethod.getGenerateInfo(success = { success() }, failed = { failure(it ?: "") }) } diff --git a/servicing/src/main/java/com/za/ui/order_report/ReportFloatingManager.kt b/servicing/src/main/java/com/za/ui/order_report/ReportFloatingManager.kt index 7f1c316..56a0971 100644 --- a/servicing/src/main/java/com/za/ui/order_report/ReportFloatingManager.kt +++ b/servicing/src/main/java/com/za/ui/order_report/ReportFloatingManager.kt @@ -26,8 +26,12 @@ import android.widget.ImageView import androidx.core.app.NotificationCompat import com.blankj.utilcode.util.ActivityUtils import com.blankj.utilcode.util.ServiceUtils +import com.za.base.AppConfig +import com.za.bean.db.order.OrderInfo +import com.za.common.GlobalData import com.za.common.log.LogUtil import com.za.servicing.R +import com.za.ui.h5.CommonH5Activity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -66,7 +70,7 @@ class ReportFloatingManager : Service() { } } - override fun onBind(intent : Intent?) : IBinder?{ + override fun onBind(intent : Intent?) : IBinder? { LogUtil.print("ReportFloatingManager service", "onBind") return null } @@ -183,7 +187,7 @@ class ReportFloatingManager : Service() { if (! isMoving && System.currentTimeMillis() - startClickTime < CLICK_THRESHOLD) { openMainActivity() - } else if (isDragging) { // 只保存位置,不执行吸附 + } else if (isDragging) { savePosition() } @@ -195,9 +199,11 @@ class ReportFloatingManager : Service() { if (ActivityUtils.getTopActivity() is OrderReportActivity) { return } - val intent = Intent(this, OrderReportActivity::class.java).apply { - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP - } + +// goReportPage(orderInfo = GlobalData.currentOrder, context = this) + val intent = Intent(this, OrderReportActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP + } startActivity(intent) } @@ -296,6 +302,13 @@ class ReportFloatingManager : Service() { ServiceUtils.stopService(ReportFloatingManager::class.java) } } + + fun goReportPage(orderInfo : OrderInfo?, context : Context) { + val url = + "${AppConfig.Resource_URL.replace("/res","")}/h5/supplier/dispatch/reportIndex?userOrderId=${orderInfo?.userOrderId}&type=2&userOrderCode=${orderInfo?.taskCode}&driverId=${GlobalData.driverInfoBean?.userId}" + CommonH5Activity.goH5Activity(context, url, "") + + } } } \ No newline at end of file diff --git a/servicing/src/main/java/com/za/ui/servicing/InServicingPhotoView.kt b/servicing/src/main/java/com/za/ui/servicing/InServicingPhotoView.kt index 6c3718d..87a6003 100644 --- a/servicing/src/main/java/com/za/ui/servicing/InServicingPhotoView.kt +++ b/servicing/src/main/java/com/za/ui/servicing/InServicingPhotoView.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -392,7 +393,11 @@ fun InServicingPhotoView(modifier : Modifier = Modifier, Text(text = photoTemplateInfo.imageTitle ?: "其他", fontWeight = FontWeight.Medium, fontSize = 14.sp, - color = Color.Black) + maxLines = 2, + overflow = TextOverflow.Ellipsis, + color = Color.Black, + modifier = Modifier.wrapContentWidth().takeIf { photoTemplateInfo.doHaveFilm == 1 } + ?: Modifier.fillMaxWidth(0.7f)) Spacer(modifier = Modifier.width(5.dp)) if (photoTemplateInfo.doHaveFilm == 1) { Text(text = "* 必拍", @@ -474,10 +479,12 @@ fun InServicingPhotoViewIsCanClick(modifier : Modifier = Modifier, Text(text = photoTemplateInfo.imageTitle ?: "其他", fontWeight = FontWeight.Medium, - maxLines = 1, - overflow = TextOverflow.Ellipsis, fontSize = 14.sp, - color = Color.Black) + maxLines = 2, + overflow = TextOverflow.Ellipsis, + color = Color.Black, + modifier = Modifier.wrapContentWidth().takeIf { photoTemplateInfo.doHaveFilm == 1 } + ?: Modifier.fillMaxWidth(0.7f)) Spacer(modifier = Modifier.width(5.dp)) if (photoTemplateInfo.doHaveFilm == 1 && isCanClick) { Text(text = "* 必拍", @@ -722,7 +729,8 @@ fun InServicingPhotoItemView(modifier : Modifier = Modifier, .clip(shape = RoundedCornerShape(3.dp)), contentScale = ContentScale.FillBounds) } else { - AsyncImage(model = photoTemplateInfo.getFormatPhotoUrl(), + AsyncImage(model = photoTemplateInfo.getFormatPhotoUrl()?.toIntOrNull() + ?: photoTemplateInfo.getFormatPhotoUrl(), contentDescription = "", modifier = Modifier .fillMaxSize() @@ -746,16 +754,16 @@ fun InServicingPhotoItemView(modifier : Modifier = Modifier, contentDescription = "", modifier = Modifier .fillMaxSize() - .clickable { + .noDoubleClick { if (! isCanClick) { - return@clickable + return@noDoubleClick } if (photoTemplateInfo.photoLocalPath.isNullOrBlank()) { if (! PermissionX.isGranted(context, android.Manifest.permission.ACCESS_FINE_LOCATION) ) { ToastUtils.showShort("定位权限未开启!") - return@clickable + return@noDoubleClick } LoadingManager.showLoading() ZdLocationManager.getSingleLocation(isNeedAddress = true, success = { @@ -771,7 +779,7 @@ fun InServicingPhotoItemView(modifier : Modifier = Modifier, LogUtil.print("上传图片定位获取失败", "使用全局定位,location==${GlobalData.currentLocation.toJson()}") }) - return@clickable + return@noDoubleClick } showReTakePhotoDialog.value = true } diff --git a/servicing/src/main/java/com/za/ui/servicing/check_vehicle/CheckVehicleVm.kt b/servicing/src/main/java/com/za/ui/servicing/check_vehicle/CheckVehicleVm.kt index 019e051..26afe2c 100644 --- a/servicing/src/main/java/com/za/ui/servicing/check_vehicle/CheckVehicleVm.kt +++ b/servicing/src/main/java/com/za/ui/servicing/check_vehicle/CheckVehicleVm.kt @@ -88,6 +88,7 @@ class CheckVehicleVm : IServicingVm( address = it?.address, templatePhotoInfoList = tempPhotoList.toList()) - if (! getCurrentOrderOfflineTask().isNullOrEmpty()) { - val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = taskRequest.type, - taskId = taskRequest.taskId, - userId = taskRequest.userId, - vehicleId = taskRequest.vehicleId, - currentState = taskRequest.currentState, - offlineMode = 1, - operateTime = taskRequest.operateTime, - updateTaskLat = taskRequest.lat, - updateTaskLng = taskRequest.lng, - flowType = taskRequest.flowType, - templatePhotoInfoList = taskRequest.templatePhotoInfoList, - updateTaskAddress = taskRequest.address, - advanceTime = uiState.value.orderInfo?.advanceTime, - taskCode = uiState.value.orderInfo?.taskCode, - userOrderId = uiState.value.orderInfo?.userOrderId, - offlineTitle = "准备拖车", - offlineType = 1) - insertOfflineTask(offlineUpdateTaskBean) - - updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus())) - updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState), - orderInfo = getCurrentOrder())) - } + val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = taskRequest.type, + taskId = taskRequest.taskId, + userId = taskRequest.userId, + vehicleId = taskRequest.vehicleId, + currentState = taskRequest.currentState, + offlineMode = 1, + operateTime = taskRequest.operateTime, + updateTaskLat = taskRequest.lat, + updateTaskLng = taskRequest.lng, + flowType = taskRequest.flowType, + templatePhotoInfoList = taskRequest.templatePhotoInfoList, + updateTaskAddress = taskRequest.address, + advanceTime = uiState.value.orderInfo?.advanceTime, + taskCode = uiState.value.orderInfo?.taskCode, + userOrderId = uiState.value.orderInfo?.userOrderId, + offlineTitle = "准备拖车", + offlineType = 1) + insertOfflineTask(offlineUpdateTaskBean) + updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus())) + updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState), + orderInfo = getCurrentOrder())) } private fun updateTask() { diff --git a/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleScreen.kt b/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleScreen.kt index a89b50b..23dd43e 100644 --- a/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleScreen.kt +++ b/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleScreen.kt @@ -50,7 +50,6 @@ import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel import coil.compose.AsyncImage -import com.blankj.utilcode.util.FileUtils import com.blankj.utilcode.util.TimeUtils import com.blankj.utilcode.util.ToastUtils import com.za.base.Const @@ -64,14 +63,12 @@ import com.za.base.view.HeadView import com.za.bean.db.ele.EleCarDamagePhotoBean import com.za.bean.db.ele.EleWorkOrderBean import com.za.common.GlobalData -import com.za.common.util.AppFileManager import com.za.common.util.ServicingSpeechManager import com.za.ext.finish import com.za.ext.getLastSix import com.za.ext.goNextPage import com.za.servicing.R import com.za.ui.view.SignatureView -import java.io.File import kotlin.math.ceil @Preview @@ -127,33 +124,6 @@ fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) { }) } - if (uiState.value.showServicePeopleSignDialog == true) { - CommonDialog(cancelText = "取消", - confirmText = "保存", - title = "是否将签名保存,以后的工单中默认使用此签名", - cancelEnable = true, - cancel = { - vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy( - showServicePeopleSignDialog = false))) - }, - dismiss = { - vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy( - showServicePeopleSignDialog = false))) - }, - confirm = { - if (uiState.value.eleWorkOrderBean?.localServicePeopleSignPath.isNullOrEmpty()) { - ToastUtils.showShort("请先进行签名") - vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy( - showServicePeopleSignDialog = false))) - return@CommonDialog - } - File(uiState.value.eleWorkOrderBean?.localServicePeopleSignPath ?: "").copyTo(File( - AppFileManager.getDriverSignPath(context)), true) - vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy( - showServicePeopleSignDialog = false))) - }) - } - if (uiState.value.showServiceSignatureUploadFailedDialog == true) { CommonDialog(cancelText = "取消", confirmText = "离线上传", @@ -408,8 +378,8 @@ fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) { } vm.dispatch(ConfirmEleVm.Action.UpdateAcceptSignature(it)) }, - serverPath = uiState.value.eleWorkOrderBean?.serverAcceptCarSignPath - ?: uiState.value.eleWorkOrderBean?.localAcceptCarSignPath) + serverPath = uiState.value.eleWorkOrderBean?.localAcceptCarSignPath + ?: uiState.value.eleWorkOrderBean?.serverAcceptCarSignPath) } } @@ -442,15 +412,9 @@ fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) { return@SignatureView } vm.dispatch(ConfirmEleVm.Action.UploadServiceSignature(it)) - - if (! FileUtils.isFileExists(File(AppFileManager.getDriverSignPath( - context))) - ) { - vm.updateState(uiState.value.copy(showServicePeopleSignDialog = true)) - } }, - serverPath = uiState.value.eleWorkOrderBean?.serverServicePeopleSignPath - ?: uiState.value.eleWorkOrderBean?.localServicePeopleSignPath) + serverPath = uiState.value.eleWorkOrderBean?.localServicePeopleSignPath + ?: uiState.value.eleWorkOrderBean?.serverServicePeopleSignPath) } } } diff --git a/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleVm.kt b/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleVm.kt index a503601..1d7ecc0 100644 --- a/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleVm.kt +++ b/servicing/src/main/java/com/za/ui/servicing/order_confirm/ConfirmEleVm.kt @@ -3,8 +3,6 @@ package com.za.ui.servicing.order_confirm import androidx.lifecycle.viewModelScope import com.amap.api.location.AMapLocation -import com.blankj.utilcode.util.ActivityUtils -import com.blankj.utilcode.util.FileUtils import com.blankj.utilcode.util.NetworkUtils import com.blankj.utilcode.util.ToastUtils import com.za.base.Const @@ -17,7 +15,6 @@ import com.za.bean.request.SaveEleOrderRequest import com.za.bean.request.UpdateTaskBean import com.za.common.GlobalData import com.za.common.log.LogUtil -import com.za.common.util.AppFileManager import com.za.ext.toJson import com.za.net.BaseObserver import com.za.net.CommonMethod @@ -186,7 +183,8 @@ class ConfirmEleVm : IServicingVm() { } else null, hasSuccess = eleWorkOrderBean.isSuccess, recipientSignPath = eleWorkOrderBean.serverAcceptCarSignPath, - waitstaffSignPath = eleWorkOrderBean.serverServicePeopleSignPath, + waitstaffSignPath = eleWorkOrderBean.serverServicePeopleSignPath + ?: GlobalData.driverInfoBean?.signatureUrl, eleState = 3, userOrderId = getCurrentOrder()?.userOrderId) insertOfflineTask(offlineUpdateTaskBean) @@ -206,7 +204,8 @@ class ConfirmEleVm : IServicingVm() { } else null, hasSuccess = eleWorkOrderBean.isSuccess, recipientSignPath = eleWorkOrderBean.serverAcceptCarSignPath, - waitstaffSignPath = eleWorkOrderBean.serverServicePeopleSignPath, + waitstaffSignPath = eleWorkOrderBean.serverServicePeopleSignPath + ?: GlobalData.driverInfoBean?.signatureUrl, eleState = 3, userOrderId = getCurrentOrder()?.userOrderId) insertOfflineTask(offlineUpdateTaskBean) @@ -223,11 +222,12 @@ class ConfirmEleVm : IServicingVm() { return } - if (getCurrentOrder()?.flowType != 2 && eleWorkOrderBean.isSuccess == null) { + if (getCurrentOrder()?.flowType != Const.TUO_CHE && eleWorkOrderBean.isSuccess == null) { showTipDialog("请选择服务是否成功!") return } + if (uiState.value.isAddSmallWheel == true && uiState.value.wheelNum == null || uiState.value.wheelNum == 0) { showTipDialog("请输入辅助轮个数") return @@ -243,11 +243,16 @@ class ConfirmEleVm : IServicingVm() { return } - if (eleWorkOrderBean.localAcceptCarSignPath.isNullOrBlank() || eleWorkOrderBean.localServicePeopleSignPath.isNullOrBlank()) { + if (eleWorkOrderBean.localAcceptCarSignPath.isNullOrBlank()) { showTipDialog("请先上传签名!") return } + if (eleWorkOrderBean.serverServicePeopleSignPath.isNullOrBlank() && eleWorkOrderBean.localServicePeopleSignPath.isNullOrBlank()) { + showTipDialog("请上传服务人员签名!") + return + } + LoadingManager.showLoading() ZdLocationManager.getSingleLocation(success = { LoadingManager.hideLoading() @@ -314,14 +319,7 @@ class ConfirmEleVm : IServicingVm() { orderInfo = getCurrentOrder())) LogUtil.print("电子表单更新车辆损伤照片", "eleWorkOrderBean==${photoList.toJson()}") - - if (! it.localServicePeopleSignPath.isNullOrBlank() || ! it.serverServicePeopleSignPath.isNullOrBlank()) { - return@queryElectronOrder - } - - if (FileUtils.isFileExists(File(AppFileManager.getDriverSignPath(context = ActivityUtils.getTopActivity())))) { - updateServiceSignature(AppFileManager.getDriverSignPath(context = ActivityUtils.getTopActivity())) - } + LogUtil.print("电子表单", "eleWorkOrderBean==${it.toJson()}") }, failed = { LoadingManager.hideLoading() @@ -354,6 +352,5 @@ class ConfirmEleVm : IServicingVm() { val showOfflineDialog : Boolean? = null, val showAcceptCarSignUploadFailedDialog : Boolean? = null, val showServiceSignatureUploadFailedDialog : Boolean? = null, - val showServicePeopleSignDialog : Boolean? = null, //服务人员签名弹窗 ) } \ No newline at end of file diff --git a/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderActivity.kt b/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderActivity.kt index ee7b3c5..7aa2fa6 100644 --- a/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderActivity.kt +++ b/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderActivity.kt @@ -21,9 +21,12 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -35,7 +38,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -44,6 +49,7 @@ import coil.compose.AsyncImage import com.blankj.utilcode.util.ConvertUtils import com.blankj.utilcode.util.ToastUtils import com.za.base.BaseActivity +import com.za.base.theme.bgColor import com.za.base.theme.black65 import com.za.base.theme.buttonBgColor import com.za.base.view.CommonDialog @@ -195,6 +201,9 @@ fun VerifyOrderScreen(vm : VerifyOrderVm = viewModel()) { VerifyCarView(orderInfo = uiState.value.orderInfo, newCarVin = uiState.value.newCarVin, newCarVinPath = uiState.value.newCarPhotoPath, + newCarChanged = { + vm.updateState(uiState.value.copy(newCarVin = it)) + }, recognize = { vm.dispatch(VerifyOrderVm.Action.Recognize(it)) }) @@ -237,6 +246,7 @@ fun VerifyOrderScreen(vm : VerifyOrderVm = viewModel()) { private fun VerifyCarView( orderInfo : OrderInfo?, newCarVin : String? = null, + newCarChanged : (String?) -> Unit, newCarVinPath : String? = null, recognize : (String) -> Unit, ) { @@ -298,10 +308,19 @@ private fun VerifyCarView( fontSize = 13.sp, fontWeight = FontWeight.Medium) Spacer(modifier = Modifier.width(10.dp)) - Text(text = newCarVin ?: "", - fontWeight = FontWeight.Medium, - fontSize = 16.sp, - color = Color.Black) + TextField(value = newCarVin ?: "", + onValueChange = { newCarChanged(it) }, + modifier = Modifier.background(color = bgColor, + shape = RoundedCornerShape(4.dp)), + colors = TextFieldDefaults.colors() + .copy(focusedContainerColor = Color.Transparent, + focusedIndicatorColor = Color.Transparent, + unfocusedIndicatorColor = Color.Transparent, + unfocusedContainerColor = Color.Transparent), + keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text), + textStyle = TextStyle.Default.copy(fontSize = 16.sp, + color = Color.Black, + fontWeight = FontWeight.Medium)) } Spacer(modifier = Modifier.height(10.dp)) diff --git a/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderVm.kt b/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderVm.kt index e71fb30..6d6cf25 100644 --- a/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderVm.kt +++ b/servicing/src/main/java/com/za/ui/servicing/verify/VerifyOrderVm.kt @@ -5,6 +5,7 @@ import com.blankj.utilcode.util.ToastUtils import com.za.base.Const import com.za.base.IServicingVm import com.za.base.view.LoadingManager +import com.za.bean.UnifiedOCRWithCompressRequest import com.za.bean.db.order.OrderInfo import com.za.bean.request.OrderPhotoOcrRecognizeRequest import com.za.bean.request.UpdateTaskBean @@ -45,7 +46,7 @@ class VerifyOrderVm : IServicingVm( LoadingManager.showLoading() CommonMethod.uploadImage(file = File(localPath), success = { LoadingManager.hideLoading() - if (it.isNullOrBlank() == true) { + if (it.isNullOrBlank()) { return@uploadImage } doRecognize(it) @@ -60,7 +61,8 @@ class VerifyOrderVm : IServicingVm( val orderPhotoOcrRecognizeRequest = OrderPhotoOcrRecognizeRequest(GlobalData.currentOrder?.userOrderId, 2, uploadPath) LogUtil.print("$tag doRecognize", "请求参数==${orderPhotoOcrRecognizeRequest.toJson()}") - RetrofitHelper.getDefaultService().orderPhotoOcrRecognize(orderPhotoOcrRecognizeRequest) + val unifiedOCRWithCompressRequest= UnifiedOCRWithCompressRequest(ocrType = 4, imageUrl = uploadPath) + RetrofitHelper.getDefaultService().unifiedOCRWithCompress(unifiedOCRWithCompressRequest) .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) .subscribe(object : BaseObserver() { override fun doSuccess(it : String?) { diff --git a/servicing/src/main/java/com/za/ui/servicing/view/InServicingBottomView.kt b/servicing/src/main/java/com/za/ui/servicing/view/InServicingBottomView.kt index 57fbbac..7cd8264 100644 --- a/servicing/src/main/java/com/za/ui/servicing/view/InServicingBottomView.kt +++ b/servicing/src/main/java/com/za/ui/servicing/view/InServicingBottomView.kt @@ -13,12 +13,13 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.KeyboardArrowLeft import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -27,6 +28,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -40,7 +42,6 @@ import com.za.base.view.CommonDialog import com.za.bean.db.order.OrderInfo import com.za.common.util.MapUtil import com.za.ext.callPhone -import com.za.ext.finish import com.za.servicing.R import com.za.ui.servicing.in_servicing_setting.OrderRequirementsActivity import com.za.ui.servicing.order_give_up.OrderGiveUpActivity @@ -207,23 +208,25 @@ fun InServicingHeadView(title : String, } } - Column { - CenterAlignedTopAppBar(modifier = Modifier.fillMaxWidth(), - colors = TopAppBarDefaults.centerAlignedTopAppBarColors() - .copy(containerColor = headBgColor, titleContentColor = Color.White), - title = { Text(text = title, fontSize = 15.sp, fontWeight = FontWeight.Medium) }, - navigationIcon = { + Column { + Box(modifier = Modifier + .fillMaxWidth() + .background(color = headBgColor) + .padding(horizontal = 10.dp, vertical = 5.dp), contentAlignment = Alignment.Center) { + + Row(modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween) { + if (isCanBack) { - AsyncImage(model = R.drawable.sv_back, + Icon(Icons.Default.KeyboardArrowLeft, contentDescription = "", modifier = Modifier - .size(40.dp) .clickable { onBack() } - .padding(10.dp)) + .padding(5.dp), + tint = Color.White) } - }, - actions = { Box(modifier = Modifier .size(46.dp) .clickable { @@ -236,7 +239,16 @@ fun InServicingHeadView(title : String, contentDescription = "", modifier = Modifier.fillMaxSize()) } - }) + } + + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + Text(text = title, + fontSize = 16.sp, + color = Color.White.copy(alpha = 0.95f), + fontWeight = FontWeight.Medium, + style = TextStyle.Default.copy()) + } + } AppTipsView() } diff --git a/servicing/src/main/res/drawable/sv_browth.xml b/servicing/src/main/res/drawable/sv_browth.xml new file mode 100644 index 0000000..9ce8b0d --- /dev/null +++ b/servicing/src/main/res/drawable/sv_browth.xml @@ -0,0 +1,12 @@ + + + + diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_car_left_back.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_car_left_back.jpg new file mode 100644 index 0000000..fe7dabd Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_car_left_back.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_car_left_front.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_car_left_front.jpg new file mode 100644 index 0000000..14a4944 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_car_left_front.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_car_right_back.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_car_right_back.jpg new file mode 100644 index 0000000..c8defe7 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_car_right_back.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_car_right_front.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_car_right_front.jpg new file mode 100644 index 0000000..9356774 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_car_right_front.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_dest_car_oil.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_dest_car_oil.jpg new file mode 100644 index 0000000..463390a Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_dest_car_oil.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_left_back.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_left_back.jpg new file mode 100644 index 0000000..a6cfb9c Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_left_back.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_left_front.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_left_front.jpg new file mode 100644 index 0000000..582ee58 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_left_front.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_right_back.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_right_back.jpg new file mode 100644 index 0000000..b7cb506 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_right_back.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_right_front.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_right_front.jpg new file mode 100644 index 0000000..41a8803 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_dilemma_right_front.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_licenses.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_licenses.jpg new file mode 100644 index 0000000..71d3038 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_licenses.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_water_tank_empty.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_water_tank_empty.jpg new file mode 100644 index 0000000..2e9d1b2 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_water_tank_empty.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/bg_water_tank_full.jpg b/servicing/src/main/res/mipmap-xhdpi/bg_water_tank_full.jpg new file mode 100644 index 0000000..b15994d Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/bg_water_tank_full.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/car_and_driver.jpg b/servicing/src/main/res/mipmap-xhdpi/car_and_driver.jpg new file mode 100644 index 0000000..7e88e54 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/car_and_driver.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/car_and_driver_pingan.jpg b/servicing/src/main/res/mipmap-xhdpi/car_and_driver_pingan.jpg new file mode 100644 index 0000000..b77460b Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/car_and_driver_pingan.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/car_front.jpg b/servicing/src/main/res/mipmap-xhdpi/car_front.jpg new file mode 100644 index 0000000..fbdaabf Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/car_front.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/dadian.png b/servicing/src/main/res/mipmap-xhdpi/dadian.png new file mode 100644 index 0000000..c1293a1 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/dadian.png differ diff --git a/servicing/src/main/res/mipmap-xhdpi/dadian_device.jpg b/servicing/src/main/res/mipmap-xhdpi/dadian_device.jpg new file mode 100644 index 0000000..8355b0e Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/dadian_device.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/dashboard_photo.jpg b/servicing/src/main/res/mipmap-xhdpi/dashboard_photo.jpg new file mode 100644 index 0000000..58b71e2 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/dashboard_photo.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/ferry_sample.jpg b/servicing/src/main/res/mipmap-xhdpi/ferry_sample.jpg new file mode 100644 index 0000000..2726ce8 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/ferry_sample.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/finish_loading.jpg b/servicing/src/main/res/mipmap-xhdpi/finish_loading.jpg new file mode 100644 index 0000000..e4f3dc0 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/finish_loading.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/huantai_photo.png b/servicing/src/main/res/mipmap-xhdpi/huantai_photo.png new file mode 100644 index 0000000..0119280 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/huantai_photo.png differ diff --git a/servicing/src/main/res/mipmap-xhdpi/huantai_success.jpg b/servicing/src/main/res/mipmap-xhdpi/huantai_success.jpg new file mode 100644 index 0000000..b23a6bf Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/huantai_success.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/invoice_sample.png b/servicing/src/main/res/mipmap-xhdpi/invoice_sample.png new file mode 100644 index 0000000..e8521f7 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/invoice_sample.png differ diff --git a/servicing/src/main/res/mipmap-xhdpi/kunjing.jpg b/servicing/src/main/res/mipmap-xhdpi/kunjing.jpg new file mode 100644 index 0000000..615efdc Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/kunjing.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/mobile_charging_dashboard_photo.png b/servicing/src/main/res/mipmap-xhdpi/mobile_charging_dashboard_photo.png new file mode 100644 index 0000000..013b493 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/mobile_charging_dashboard_photo.png differ diff --git a/servicing/src/main/res/mipmap-xhdpi/mobile_charing_process_photo.png b/servicing/src/main/res/mipmap-xhdpi/mobile_charing_process_photo.png new file mode 100644 index 0000000..8e2c011 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/mobile_charing_process_photo.png differ diff --git a/servicing/src/main/res/mipmap-xhdpi/no_oil.jpg b/servicing/src/main/res/mipmap-xhdpi/no_oil.jpg new file mode 100644 index 0000000..7c7cdc3 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/no_oil.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/plight_vehicle.png b/servicing/src/main/res/mipmap-xhdpi/plight_vehicle.png new file mode 100644 index 0000000..a8a6453 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/plight_vehicle.png differ diff --git a/servicing/src/main/res/mipmap-xhdpi/trailer_3.jpg b/servicing/src/main/res/mipmap-xhdpi/trailer_3.jpg new file mode 100644 index 0000000..71417b2 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/trailer_3.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_ing.jpg b/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_ing.jpg new file mode 100644 index 0000000..b78cf58 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_ing.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_ing_success.jpg b/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_ing_success.jpg new file mode 100644 index 0000000..a1d9d3c Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_ing_success.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_pre.jpg b/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_pre.jpg new file mode 100644 index 0000000..aece41d Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/tyre_inflate_pre.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/tyre_pre.jpg b/servicing/src/main/res/mipmap-xhdpi/tyre_pre.jpg new file mode 100644 index 0000000..51da697 Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/tyre_pre.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/vehicle_escape.png b/servicing/src/main/res/mipmap-xhdpi/vehicle_escape.png new file mode 100644 index 0000000..9e903fe Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/vehicle_escape.png differ diff --git a/servicing/src/main/res/mipmap-xhdpi/vin_photo.jpg b/servicing/src/main/res/mipmap-xhdpi/vin_photo.jpg new file mode 100644 index 0000000..f13d4ae Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/vin_photo.jpg differ diff --git a/servicing/src/main/res/mipmap-xhdpi/work_order1.png b/servicing/src/main/res/mipmap-xhdpi/work_order1.png new file mode 100644 index 0000000..463d34e Binary files /dev/null and b/servicing/src/main/res/mipmap-xhdpi/work_order1.png differ diff --git a/servicing/src/main/res/mipmap-xxhdpi/bg_byd_dest_car_mans.jpg b/servicing/src/main/res/mipmap-xxhdpi/bg_byd_dest_car_mans.jpg new file mode 100644 index 0000000..822708a Binary files /dev/null and b/servicing/src/main/res/mipmap-xxhdpi/bg_byd_dest_car_mans.jpg differ diff --git a/servicing/src/main/res/mipmap-xxhdpi/bg_underground.jpg b/servicing/src/main/res/mipmap-xxhdpi/bg_underground.jpg new file mode 100644 index 0000000..cb0cc35 Binary files /dev/null and b/servicing/src/main/res/mipmap-xxhdpi/bg_underground.jpg differ diff --git a/servicing/src/main/res/mipmap-xxhdpi/damage_photo.jpg b/servicing/src/main/res/mipmap-xxhdpi/damage_photo.jpg new file mode 100644 index 0000000..63c1835 Binary files /dev/null and b/servicing/src/main/res/mipmap-xxhdpi/damage_photo.jpg differ