feat(servicing): 优化订单详情页面布局和功能

-调整订单信息显示布局,增加订单来源显示
- 优化地图标记添加逻辑,提高地图展示效果
- 改进路径规划功能,优化预计到达时间计算方式- 更新车辆损伤照片加载逻辑,提高数据展示效率
- 修复部分页面样式问题,提升用户体验
This commit is contained in:
songzhiling
2025-04-25 18:01:44 +08:00
parent c606ed95cd
commit b0c2f7352d
20 changed files with 794 additions and 851 deletions

View File

@ -33,15 +33,8 @@ android {
] ]
} }
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
signingConfigs { signingConfigs {
release { config {
storeFile file('E:\\workspace\\study\\zd_sdk_demo\\zd_sdk_demo.jks') storeFile file('E:\\workspace\\study\\zd_sdk_demo\\zd_sdk_demo.jks')
storePassword '123456' storePassword '123456'
keyAlias 'key0' keyAlias 'key0'
@ -49,6 +42,18 @@ android {
} }
} }
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.config
}
debug {
minifyEnabled false // 开启混淆
signingConfig signingConfigs.config
}
}
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_11 sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11

View File

@ -44,6 +44,10 @@
android:name="android.app.lib_name" android:name="android.app.lib_name"
android:value="" /> android:value="" />
</activity> </activity>
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="ca9429157ac6a0fb3f331b95817b3ca6" />
</application> </application>
</manifest> </manifest>

View File

@ -27,7 +27,7 @@ class MainActivity : ComponentActivity() {
.fillMaxSize() .fillMaxSize()
.clickable { .clickable {
val uri = val uri =
"zd.assist://app?taskCode=ZD250422100056&driverName=宋志领&driverPhone=17630035658&rescueVehicle=沪88888".toUri() "zd.assist://app?taskCode=ZD250425100361&driverName=宋志领&driverPhone=17630035658&rescueVehicle=沪88888".toUri()
val intent = Intent(Intent.ACTION_VIEW, uri) val intent = Intent(Intent.ACTION_VIEW, uri)
startActivity(intent) startActivity(intent)
} }

View File

@ -73,7 +73,7 @@ publishing {
release(MavenPublication) { release(MavenPublication) {
groupId = 'io.github.szl9' groupId = 'io.github.szl9'
artifactId = 'zd_servicing' artifactId = 'zd_servicing'
version = "1.0.1.9" version = "1.0.1.9.9.4"
pom { pom {
packaging = "aar" packaging = "aar"

View File

@ -9,6 +9,7 @@
android:protectionLevel="signature" /> <!-- 位置相关权限 --> android:protectionLevel="signature" /> <!-- 位置相关权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <!-- 存储相关权限 --> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <!-- 存储相关权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@ -75,7 +76,10 @@
</intent> </intent>
</queries> </queries>
<application> <application
android:networkSecurityConfig="@xml/network_security_config"
android:usesCleartextTraffic="true"
tools:targetApi="24">
<activity <activity
android:name="com.za.ui.main.ServiceLauncherActivity" android:name="com.za.ui.main.ServiceLauncherActivity"
android:exported="true" android:exported="true"
@ -115,16 +119,19 @@
<service <service
android:name="com.za.ui.order_report.ReportFloatingManager" android:name="com.za.ui.order_report.ReportFloatingManager"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false"
android:foregroundServiceType="location" />
<activity <activity
android:name="com.za.ui.order_report.HistoryReportActivity" android:name="com.za.ui.order_report.HistoryReportActivity"
android:exported="false" android:exported="false"
android:screenOrientation="portrait" /> android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity <activity
android:name="com.za.ui.order_report.OrderReportActivity" android:name="com.za.ui.order_report.OrderReportActivity"
android:exported="false" android:exported="false"
android:screenOrientation="portrait" /> android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity <activity
android:name="com.za.ui.h5.CommonH5Activity" android:name="com.za.ui.h5.CommonH5Activity"
android:exported="false" android:exported="false"
@ -152,7 +159,8 @@
android:theme="@style/Theme.Dealer" /> android:theme="@style/Theme.Dealer" />
<activity <activity
android:name="com.za.signature.GridPaintActivity" android:name="com.za.signature.GridPaintActivity"
android:exported="false" /> android:exported="false"
android:theme="@style/Theme.Dealer" />
<activity <activity
android:name="com.za.ui.servicing.operation.InOperationActivity" android:name="com.za.ui.servicing.operation.InOperationActivity"
android:exported="false" android:exported="false"
@ -161,8 +169,8 @@
<activity <activity
android:name="com.za.ui.camera.ZdCameraXActivity" android:name="com.za.ui.camera.ZdCameraXActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.Dealer" android:screenOrientation="portrait"
android:screenOrientation="portrait"> android:theme="@style/Theme.Dealer">
<meta-data <meta-data
android:name="android.app.lib_name" android:name="android.app.lib_name"
android:value="" /> android:value="" />

View File

@ -35,6 +35,8 @@ data class JpushBean(
val distLng: Double? = null, val distLng: Double? = null,
val importantTip: String? = null, val importantTip: String? = null,
val tipContent: String? = null, val tipContent: String? = null,
val settleType: Int?=null,//结算类型 1 月结 2 现金
var orderSource: String? = null, // "orderSource":"中道救援-比亚迪道路救援项目"
val hasReplaceBatteryCapable: Int? = null ,//是否有更换电瓶的能力 1 搭电可以更换电瓶 2搭电不可以更换电瓶 其他的不展示 val hasReplaceBatteryCapable: Int? = null ,//是否有更换电瓶的能力 1 搭电可以更换电瓶 2搭电不可以更换电瓶 其他的不展示
var voiceType : Int?=null //语音提示类型 1小修单 2拖车单 3困境单 var voiceType : Int?=null //语音提示类型 1小修单 2拖车单 3困境单
) : Serializable { ) : Serializable {

View File

@ -2,6 +2,7 @@ package com.za.net
import android.net.ParseException import android.net.ParseException
import com.blankj.utilcode.util.ActivityUtils import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.ThreadUtils
import com.blankj.utilcode.util.ToastUtils import com.blankj.utilcode.util.ToastUtils
import com.google.gson.JsonParseException import com.google.gson.JsonParseException
import com.za.base.Const import com.za.base.Const
@ -22,90 +23,95 @@ import javax.net.ssl.SSLHandshakeException
* Created by DoggieX on 2017/7/26. * Created by DoggieX on 2017/7/26.
*/ */
abstract class BaseObserver<T> : Observer<BaseResponse<T>> { abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
override fun onSubscribe(d: Disposable) { override fun onSubscribe(d : Disposable) { // if (!NetworkUtils.isAvailable()) {
// if (!NetworkUtils.isAvailable()) { // doFailure(999, "网络无法使用")
// doFailure(999, "网络无法使用") // d.dispose()
// d.dispose() // }
// } }
}
override fun onNext(tBaseResponse: BaseResponse<T>) { override fun onNext(tBaseResponse : BaseResponse<T>) {
if (tBaseResponse.isOk) { if (tBaseResponse.isOk) {
doSuccess(tBaseResponse.result) doSuccess(tBaseResponse.result)
} else { } else {
when (tBaseResponse.code) { when (tBaseResponse.code) {
3, 401 -> handlerTokenExpired() 3, 401 -> handlerTokenExpired()
// 4 -> RsaRouter.navigate(context, "/page/Standby") }
} val errMsg = if (null != tBaseResponse.msg) {
if (null != tBaseResponse.msg) { tBaseResponse.msg
doFailure(tBaseResponse.code, tBaseResponse.msg) } else if (null != tBaseResponse.message) {
} else if (null != tBaseResponse.message) { tBaseResponse.message
doFailure(tBaseResponse.code, tBaseResponse.message) } else {
} else { "error"
doFailure(tBaseResponse.code, "error") }
} doFailure(tBaseResponse.code, errMsg)
} if (errMsg?.contains("请下载新版本app!") == true) {
} handlerTokenExpired()
}
}
}
override fun onError(e: Throwable) { override fun onError(e : Throwable) {
LogUtil.print("net error", e) LogUtil.print("net error", e)
when (e) { when (e) {
is JsonParseException -> { is JsonParseException -> {
doFailure(1, "数据解析错误") doFailure(1, "数据解析错误")
} }
is JSONException -> { is JSONException -> {
doFailure(1, "数据解析错误") doFailure(1, "数据解析错误")
} }
is ParseException -> { is ParseException -> {
doFailure(1, "数据解析错误") doFailure(1, "数据解析错误")
} }
is ConnectException -> { is ConnectException -> {
doFailure(Const.NetWorkException, "与服务器断开连接") doFailure(Const.NetWorkException, "与服务器断开连接")
} }
is UnknownHostException -> { is UnknownHostException -> {
doFailure(Const.NetWorkException, "与服务器断开连接") doFailure(Const.NetWorkException, "与服务器断开连接")
} }
is SSLHandshakeException -> { is SSLHandshakeException -> {
doFailure(1, "证书验证失败") doFailure(1, "证书验证失败")
LogUtil.print("SSLHandshakeException", e) LogUtil.print("SSLHandshakeException", e)
} }
is TimeoutException -> { is TimeoutException -> {
doFailure(Const.NetWorkException, "网络连接超时1") doFailure(Const.NetWorkException, "网络连接超时1")
LogUtil.print("TimeoutException", e) LogUtil.print("TimeoutException", e)
} }
is SocketTimeoutException -> { is SocketTimeoutException -> {
doFailure(Const.NetWorkException, "网络连接超时2") doFailure(Const.NetWorkException, "网络连接超时2")
LogUtil.print("SocketTimeoutException2", e) LogUtil.print("SocketTimeoutException2", e)
} }
else -> {
doFailure(1, "error:" + e.message)
LogUtil.print("other error", e)
}
}
}
override fun onComplete() { else -> {
} doFailure(1, "error:" + e.message)
LogUtil.print("other error", e)
}
}
}
abstract fun doSuccess(it: T?) override fun onComplete() {
}
abstract fun doFailure(code: Int, msg: String?) abstract fun doSuccess(it : T?)
private fun handlerTokenExpired() { abstract fun doFailure(code : Int, msg : String?)
ToastUtils.showShort("登陆信息已过期,请重新登录")
try { private fun handlerTokenExpired() {
GlobalData.clearUserCache() ThreadUtils.runOnUiThread {
ZdLocationManager.stopContinuousLocation() try {
ActivityUtils.finishAllActivities() ToastUtils.showShort("登陆信息已过期,请重新登录")
} catch (e: Exception) { GlobalData.clearUserCache()
LogUtil.print("handlerTokenExpired", e) ZdLocationManager.stopContinuousLocation()
} ActivityUtils.startLauncherActivity()
} } catch (e : Exception) {
LogUtil.print("handlerTokenExpired", e)
}
}
}
} }

View File

@ -16,7 +16,6 @@ import com.za.common.log.LogUtil
import com.za.common.util.DeviceUtil import com.za.common.util.DeviceUtil
import com.za.service.mqtt.MyMqttClient import com.za.service.mqtt.MyMqttClient
import com.za.servicing.R import com.za.servicing.R
import java.util.concurrent.atomic.AtomicReference
interface PushListener { interface PushListener {
fun newOrderMsg(jpushBean : JpushBean) fun newOrderMsg(jpushBean : JpushBean)
@ -30,7 +29,7 @@ interface PushListener {
data class LastJPushBean(val msg : Int, val time : Long = System.nanoTime()) data class LastJPushBean(val msg : Int, val time : Long = System.nanoTime())
object ServiceManager { object ServiceManager {
private val pushListener = AtomicReference<PushListener>() private var pushListener : PushListener? = null
private var lastJPushBean : LastJPushBean? = null private var lastJPushBean : LastJPushBean? = null
private const val DUPLICATE_MSG_THRESHOLD = 3000L // 3秒 private const val DUPLICATE_MSG_THRESHOLD = 3000L // 3秒
@ -56,16 +55,15 @@ object ServiceManager {
// Register push listener // Register push listener
fun registerPushListener(listener : PushListener?) { fun registerPushListener(listener : PushListener?) {
listener?.let { this.pushListener = listener
pushListener.set(it) LogUtil.print("ServiceManager",
LogUtil.print("ServiceManager", "Registered push listener: ${it.javaClass.simpleName}") "Registered push listener: ${pushListener?.javaClass?.simpleName}")
}
} }
// Handle incoming push messages // Handle incoming push messages
@Synchronized @Synchronized
fun handlerPushMsg(msg : String) { fun handlerPushMsg(msg : String) {
LogUtil.print("JpushMessage", "Received push message: $msg") LogUtil.print("handlerPushMsg", "Received push message: $msg")
// 优化后的重复消息判断 // 优化后的重复消息判断
lastJPushBean?.let { lastJPushBean?.let {
@ -76,12 +74,12 @@ object ServiceManager {
} }
if (msg.startsWith("broadcast:")) { if (msg.startsWith("broadcast:")) {
lastJPushBean = LastJPushBean(msg.hashCode()) lastJPushBean = LastJPushBean(msg = msg.hashCode())
handleBroadcast(msg) handleBroadcast(msg)
return return
} }
try { try {
lastJPushBean = LastJPushBean(msg.hashCode()) lastJPushBean = LastJPushBean(msg = msg.hashCode())
val jpushOrderInfoBean = Gson().fromJson(msg, JpushBean::class.java) val jpushOrderInfoBean = Gson().fromJson(msg, JpushBean::class.java)
sendSystemNotificationFromMessage(jpushOrderInfoBean) sendSystemNotificationFromMessage(jpushOrderInfoBean)
when (jpushOrderInfoBean.pushType) { when (jpushOrderInfoBean.pushType) {
@ -103,7 +101,7 @@ object ServiceManager {
private fun handleBroadcast(msg : String) { private fun handleBroadcast(msg : String) {
try { try {
val content = msg.substring(10) val content = msg.substring(10)
pushListener.get()?.broadcast(content) pushListener?.broadcast(content)
sendNotification(GlobalData.application, content) sendNotification(GlobalData.application, content)
LogUtil.print("JpushMessage", "Broadcast content: $content") LogUtil.print("JpushMessage", "Broadcast content: $content")
} catch (e : Exception) { } catch (e : Exception) {
@ -124,7 +122,9 @@ object ServiceManager {
// Handle new order messages // Handle new order messages
private fun newOrderMsg(jpushOrderBean : JpushBean) { private fun newOrderMsg(jpushOrderBean : JpushBean) {
try { try {
pushListener.get()?.newOrderMsg(jpushOrderBean) LogUtil.print("JpushMessage",
"Handling new order message: $pushListener ${pushListener?.javaClass?.simpleName}")
pushListener?.newOrderMsg(jpushOrderBean)
} catch (e : Exception) { } catch (e : Exception) {
LogUtil.print("JpushMessage", "Failed to handle new order message: ${e.message}") LogUtil.print("JpushMessage", "Failed to handle new order message: ${e.message}")
} }
@ -132,22 +132,22 @@ object ServiceManager {
// Handle give up order messages // Handle give up order messages
private fun giveUpOrder(jpushOrderBean : JpushBean) { private fun giveUpOrder(jpushOrderBean : JpushBean) {
pushListener.get()?.giveUpOrder(jpushOrderBean) pushListener?.giveUpOrder(jpushOrderBean)
} }
// Handle revoke order messages // Handle revoke order messages
private fun revokeOrder(jpushOrderBean : JpushBean) { private fun revokeOrder(jpushOrderBean : JpushBean) {
pushListener.get()?.revokeOrder(jpushOrderBean) pushListener?.revokeOrder(jpushOrderBean)
} }
// Handle re-dispatch order messages // Handle re-dispatch order messages
private fun reDispatchOrder(jpushOrderBean : JpushBean) { private fun reDispatchOrder(jpushOrderBean : JpushBean) {
pushListener.get()?.reDispatchOrder(jpushOrderBean) pushListener?.reDispatchOrder(jpushOrderBean)
} }
// Handle important tip messages // Handle important tip messages
private fun importantTip(jpushOrderBean : JpushBean) { private fun importantTip(jpushOrderBean : JpushBean) {
pushListener.get()?.importantTip(jpushOrderBean) pushListener?.importantTip(jpushOrderBean)
} }
// Disconnect from JPush and MQTT // Disconnect from JPush and MQTT

View File

@ -20,7 +20,6 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Done
import androidx.compose.material.icons.filled.Menu import androidx.compose.material.icons.filled.Menu
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
@ -50,7 +49,9 @@ import com.blankj.utilcode.util.ActivityUtils
import com.za.base.BaseActivity import com.za.base.BaseActivity
import com.za.base.theme.bgColor import com.za.base.theme.bgColor
import com.za.base.view.CommonButton import com.za.base.view.CommonButton
import com.za.base.view.EmptyView
import com.za.base.view.HeadView import com.za.base.view.HeadView
import com.za.base.view.LoadError
import com.za.bean.db.order.OrderInfo import com.za.bean.db.order.OrderInfo
import com.za.common.GlobalData import com.za.common.GlobalData
import com.za.common.util.DeviceUtil import com.za.common.util.DeviceUtil
@ -129,23 +130,35 @@ private fun ServicingMainScreen(jobCode : String? = null,
.fillMaxSize() .fillMaxSize()
.background(bgColor) .background(bgColor)
.padding(it)) { .padding(it)) {
if (uiState.value.state == 2) { when (uiState.value.state) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { 1 -> {
CommonButton(text = "订单获取异常,点击重新获取") { Box(modifier = Modifier
vm.dispatch(ServicingMainVm.Action.Init(jobCode, .fillMaxSize()
phone, .padding(top = 10.dp),
taskCode, contentAlignment = Alignment.TopCenter) {
vehicleId, OrderItemView(GlobalData.currentOrder)
deviceId,
rescueVehicle))
} }
} }
} else {
Box(modifier = Modifier 2 -> {
.fillMaxSize() Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
.padding(top = 10.dp), LoadError(message = "订单获取异常", onRetry = {
contentAlignment = Alignment.TopCenter) { vm.dispatch(ServicingMainVm.Action.Init(jobCode,
OrderItemView(GlobalData.currentOrder) phone,
taskCode,
vehicleId,
deviceId,
rescueVehicle))
})
}
}
3 -> { //
EmptyView()
}
else -> {
} }
} }
} }

View File

@ -46,11 +46,14 @@ class ServicingMainVm : BaseVm<ServicingMainVm.Action, ServicingMainVm.UiState>(
CommonMethod.queryOrderList(context = ActivityUtils.getTopActivity(), CommonMethod.queryOrderList(context = ActivityUtils.getTopActivity(),
success = { orderInfo : OrderInfo?, orderInfos : List<OrderInfo>? -> success = { orderInfo : OrderInfo?, orderInfos : List<OrderInfo>? ->
LoadingManager.hideLoading() LoadingManager.hideLoading()
if (orderInfo == null) {
ToastUtils.showShort("未查询到订单")
GlobalData.clearAllOrderCache()
updateState(uiState.value.copy(state = 3))
return@queryOrderList
}
GlobalData.currentOrder = orderInfo GlobalData.currentOrder = orderInfo
updateState(uiState.value.copy(state = 1)) updateState(uiState.value.copy(state = 1))
if (orderInfos.isNullOrEmpty()) {
ToastUtils.showShort("未查询到订单")
}
}, },
failed = { failed = {
updateState(uiState.value.copy(state = 2)) updateState(uiState.value.copy(state = 2))
@ -106,6 +109,6 @@ class ServicingMainVm : BaseVm<ServicingMainVm.Action, ServicingMainVm.UiState>(
} }
data class UiState( data class UiState(
val state : Int? = null, //1 成功 2 失败 val state : Int? = null, //1 成功 2 失败 3:订单为空
) )
} }

View File

@ -57,6 +57,7 @@ import coil.compose.AsyncImage
import com.amap.api.location.AMapLocationClient import com.amap.api.location.AMapLocationClient
import com.amap.api.maps.CameraUpdateFactory import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.MapView import com.amap.api.maps.MapView
import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.LatLng import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.LatLngBounds import com.amap.api.maps.model.LatLngBounds
import com.amap.api.maps.model.MarkerOptions import com.amap.api.maps.model.MarkerOptions
@ -234,18 +235,18 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
} }
// 添加距离和时间信息 // 添加距离和时间信息
// 距离和时间信息
Row(modifier = Modifier Row(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp), .padding(horizontal = 16.dp, vertical = 12.dp),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically) { verticalAlignment = Alignment.CenterVertically) {
Text(text = "预计到达: ${uiState.value.estimatedArrivalTime}", Text(text = if (uiState.value.estimatedArrivalTime.isNotEmpty()) "预计到达: ${uiState.value.estimatedArrivalTime}"
color = Color(0xFF666666), else "计算中...", color = Color(0xFF666666), fontSize = 14.sp)
fontSize = 14.sp)
Text(text = "总里程: %.1fkm".format(uiState.value.remainingDistance / 1000f), Text(text = if (uiState.value.remainingDistance > 0) "距离救援地: %.1fkm".format(
color = Color(0xFFFF4D4F), uiState.value.remainingDistance / 1000f)
fontSize = 14.sp) else "计算中...", color = Color(0xFFFF4D4F), fontSize = 14.sp)
} }
HorizontalDivider(modifier = Modifier HorizontalDivider(modifier = Modifier
@ -256,8 +257,26 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
Column(modifier = Modifier Column(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp)) { // 订单标签 .padding(horizontal = 16.dp, vertical = 12.dp)) { // 订单标签
Text(text = uiState.value.jpushBean?.serviceTypeName ?: "",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Color.Black)
Spacer(modifier = Modifier.height(8.dp))
// 订单标签
Row(verticalAlignment = Alignment.CenterVertically, Row(verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)) { horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Box(modifier = Modifier
.background(Color(0xFF9BA1B2), RoundedCornerShape(4.dp))
.padding(horizontal = 6.dp, vertical = 2.dp)) {
Text(text = "月结".takeIf { uiState.value.jpushBean?.settleType == 1 }
?: "现金", color = Color.White, fontSize = 12.sp)
}
Text(text = uiState.value.jpushBean?.orderSource ?: "",
color = Color.Black,
fontSize = 12.sp)
Text(text = uiState.value.jpushBean?.addressProperty ?: "", Text(text = uiState.value.jpushBean?.addressProperty ?: "",
color = Color(0xFFFD8205), color = Color(0xFFFD8205),
@ -416,10 +435,9 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
// 绘制路线 // 绘制路线
uiState.value.routePoints?.let { points -> uiState.value.routePoints?.let { points ->
if (points.isNotEmpty()) { mapView.map.addPolyline(PolylineOptions().addAll(points).width(15f)
mapView.map.addPolyline(PolylineOptions().addAll(points).width(15f) .setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.icon_road_green_arrow))
.color(Color(0xFF3D4B7C).toArgb()).zIndex(1f)) .zIndex(1f))
}
} }
// 添加标记点 // 添加标记点

View File

@ -157,7 +157,7 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
val photoList = RoomHelper.db?.eleCarDamagePhotoDao()?.getEleCarDamagePhotos(getCurrentOrder()?.taskId val photoList = RoomHelper.db?.eleCarDamagePhotoDao()?.getEleCarDamagePhotos(getCurrentOrder()?.taskId
?: 0) ?: 0)
updateState(uiState.value.copy(eleWorkOrderBean = it, damagePhoto = photoList, orderInfo = getCurrentOrder())) updateState(uiState.value.copy(eleWorkOrderBean = it, damagePhoto = photoList, orderInfo = getCurrentOrder()))
LogUtil.print("电子表单更新车辆损伤照片", "eleWorkOrderBean==${photoList.toJson()}") LogUtil.print("电子表单更新车辆损伤照片", "eleWorkOrderBean==${it.toJson()}")
}, },
failed = { failed = {
LoadingManager.hideLoading() LoadingManager.hideLoading()

View File

@ -170,30 +170,33 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
Column(modifier = Modifier Column(modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp)) { .padding(horizontal = 16.dp, vertical = 12.dp)) {
Row(modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically) {
Text(text = uiState.value.orderInfo?.serviceTypeName ?: "",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Color.Black)
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), Text(text = uiState.value.orderInfo?.serviceTypeName ?: "",
verticalAlignment = Alignment.CenterVertically) { fontSize = 18.sp,
Box(modifier = Modifier fontWeight = FontWeight.Bold,
.background(Color(0xFF9BA1B2), RoundedCornerShape(4.dp)) color = Color.Black)
.padding(horizontal = 6.dp, vertical = 2.dp)) {
Text(text = "月结".takeIf { uiState.value.orderInfo?.settleType == 1 }
?: "现金", color = Color.White, fontSize = 12.sp)
}
Text(text = uiState.value.orderInfo?.addressProperty ?: "", Spacer(modifier = Modifier.height(8.dp))
color = Color(0xFFFD8205),
fontSize = 12.sp, // 订单标签
fontWeight = FontWeight.Medium) Row(verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Box(modifier = Modifier
.background(Color(0xFF9BA1B2), RoundedCornerShape(4.dp))
.padding(horizontal = 6.dp, vertical = 2.dp)) {
Text(text = "月结".takeIf { uiState.value.orderInfo?.settleType == 1 }
?: "现金", color = Color.White, fontSize = 12.sp)
} }
}
Text(text = uiState.value.orderInfo?.orderSource ?: "",
color = Color.Black,
fontSize = 12.sp)
Text(text = uiState.value.orderInfo?.addressProperty ?: "",
color = Color(0xFFFD8205),
fontSize = 12.sp,
fontWeight = FontWeight.Medium)
}
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
Row(verticalAlignment = Alignment.CenterVertically, Row(verticalAlignment = Alignment.CenterVertically,
@ -333,7 +336,7 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
// 添加当前位置标记 // 添加当前位置标记
if (GlobalData.currentLocation != null) { if (GlobalData.currentLocation != null) {
mapView.map.addMarker(MarkerOptions().position(LatLng(GlobalData.currentLocation?.latitude !!, mapView.map.addMarker(MarkerOptions().position(LatLng(GlobalData.currentLocation?.latitude !!,
GlobalData.currentLocation?.longitude !!)).title("当前位置") GlobalData.currentLocation?.longitude !!)).title("当前位置")
.icon(ImageUtil.vectorToBitmap(context, R.drawable.ic_current_location)) .icon(ImageUtil.vectorToBitmap(context, R.drawable.ic_current_location))
.anchor(0.5f, 0.5f).visible(true)) .anchor(0.5f, 0.5f).visible(true))
} }
@ -342,7 +345,7 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
uiState.value.orderInfo?.let { order -> uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) { if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
mapView.map.addMarker(MarkerOptions().position(LatLng(order.lat !!, mapView.map.addMarker(MarkerOptions().position(LatLng(order.lat !!,
order.lng !!)).title("救援地点") order.lng !!)).title("救援地点")
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map)) .icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
.anchor(0.5f, 0.5f)) .anchor(0.5f, 0.5f))
} }
@ -350,7 +353,7 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
// 添加目的地标记 // 添加目的地标记
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) { if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
mapView.map.addMarker(MarkerOptions().position(LatLng(order.distLat !!, mapView.map.addMarker(MarkerOptions().position(LatLng(order.distLat !!,
order.distLng !!)).title("目的地") order.distLng !!)).title("目的地")
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map)) .icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map))
.anchor(0.5f, 0.5f)) .anchor(0.5f, 0.5f))
} }

View File

@ -34,6 +34,7 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date
import java.util.Locale import java.util.Locale
class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.UiState>() { class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.UiState>() {
@ -136,7 +137,7 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
updateState(uiState = uiState.value.copy(orderInfo = getCurrentOrder())) updateState(uiState = uiState.value.copy(orderInfo = getCurrentOrder()))
buildMarkers(getCurrentOrder()) buildMarkers(getCurrentOrder())
searchDrivingRoute(getCurrentOrder()) searchDrivingRoute(getCurrentOrder())
// dispatch(Action.StartTimer) startTimer()
} }
private fun buildMarkers(orderInfo : OrderInfo?) { private fun buildMarkers(orderInfo : OrderInfo?) {
@ -182,14 +183,13 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
val points = path.steps.flatMap { step -> val points = path.steps.flatMap { step ->
step.polyline.map { LatLng(it.latitude, it.longitude) } step.polyline.map { LatLng(it.latitude, it.longitude) }
} }
val durationInSeconds = path.duration val duration = path.duration
val arrivalTime = SimpleDateFormat("HH:mm:ss", val arrivalTime = System.currentTimeMillis() + duration * 1000
Locale.getDefault()).format(System.currentTimeMillis() + durationInSeconds * 1000) val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val estimatedTime = dateFormat.format(Date(arrivalTime))
updateState(uiState.value.copy(routePoints = points,
LogUtil.print("arrivalTime", "arrivalTime: arrivalTime=$arrivalTime") estimatedArrivalTime = estimatedTime,
LogUtil.print("distance", "distance: distance=${path.distance.div(1000)}km") remainingDistance = path.distance))
updateState(uiState.value.copy(routePoints = points, estimatedArrivalTime = arrivalTime, remainingDistance = path.distance))
} else { } else {
LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode") LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode")
} }
@ -233,16 +233,16 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
private var timerJob : Job? = null private var timerJob : Job? = null
private fun startTimer() { private fun startTimer() {
timerJob?.cancel() // timerJob?.cancel()
timerJob = viewModelScope.launch { // timerJob = viewModelScope.launch {
while (isActive) { // while (isActive) {
val (distance, arrivalTime) = calculateRemainingDistance() // val (distance, arrivalTime) = calculateRemainingDistance()
_uiState.update { // _uiState.update {
it.copy(remainingDistance = distance, estimatedArrivalTime = arrivalTime) // it.copy(remainingDistance = distance, estimatedArrivalTime = arrivalTime)
} // }
delay(1000) // delay(1000)
} // }
} // }
} }
override fun onCleared() { override fun onCleared() {

View File

@ -70,488 +70,370 @@ import com.za.servicing.R
import com.za.ui.servicing.view.InServicingHeadView import com.za.ui.servicing.view.InServicingHeadView
class GoToDestinationActivity : BaseActivity() { class GoToDestinationActivity : BaseActivity() {
@Composable @Composable
override fun ContentView() { override fun ContentView() {
GoToDestinationScreen() GoToDestinationScreen()
} }
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun GoToDestinationScreen(vm: GoToDestinationVm = viewModel()) { fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle() val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current val lifecycleOwner = LocalLifecycleOwner.current
val mapView = remember { MapView(context) } val mapView = remember { MapView(context) }
// 添加协程作用域
val scope = rememberCoroutineScope()
// 修改 BottomSheet 状态 // 添加协程作用域
val bottomSheetState = rememberStandardBottomSheetState( val scope = rememberCoroutineScope()
initialValue = SheetValue.PartiallyExpanded,
confirmValueChange = { true }
)
val scaffoldState = rememberBottomSheetScaffoldState(
bottomSheetState = bottomSheetState
)
// 优化状态管理 // 修改 BottomSheet 状态
val isExpanded by remember { val bottomSheetState =
derivedStateOf { bottomSheetState.currentValue == SheetValue.Expanded } rememberStandardBottomSheetState(initialValue = SheetValue.PartiallyExpanded,
} confirmValueChange = { true })
val scaffoldState = rememberBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
// 记忆化常用值,减少重组 // 优化状态管理
val orderInfo = remember(uiState.value.orderInfo) { uiState.value.orderInfo } val isExpanded by remember {
val estimatedTime = remember(uiState.value.estimatedArrivalTime) { uiState.value.estimatedArrivalTime } derivedStateOf { bottomSheetState.currentValue == SheetValue.Expanded }
val remainingDistance = remember(uiState.value.remainingDistance) { uiState.value.remainingDistance } }
DisposableEffect(key1 = lifecycleOwner) { // 记忆化常用值,减少重组
val observer = LifecycleEventObserver { _, event -> val orderInfo = remember(uiState.value.orderInfo) { uiState.value.orderInfo }
when (event) { val estimatedTime =
Lifecycle.Event.ON_CREATE -> { remember(uiState.value.estimatedArrivalTime) { uiState.value.estimatedArrivalTime }
mapView.onCreate(Bundle()) val remainingDistance =
vm.dispatch(GoToDestinationVm.Action.Init) remember(uiState.value.remainingDistance) { uiState.value.remainingDistance }
}
Lifecycle.Event.ON_RESUME -> mapView.onResume() DisposableEffect(key1 = lifecycleOwner) {
Lifecycle.Event.ON_PAUSE -> mapView.onPause() val observer = LifecycleEventObserver { _, event ->
Lifecycle.Event.ON_DESTROY -> mapView.onDestroy() when (event) {
else -> {} Lifecycle.Event.ON_CREATE -> {
} mapView.onCreate(Bundle())
} vm.dispatch(GoToDestinationVm.Action.Init)
}
lifecycleOwner.lifecycle.addObserver(observer) Lifecycle.Event.ON_RESUME -> mapView.onResume()
onDispose { Lifecycle.Event.ON_PAUSE -> mapView.onPause()
lifecycleOwner.lifecycle.removeObserver(observer) Lifecycle.Event.ON_DESTROY -> mapView.onDestroy()
} else -> {}
} }
}
// 对话框处理 lifecycleOwner.lifecycle.addObserver(observer)
if (uiState.value.goNextPage != null) { onDispose {
goNextPage(uiState.value.goNextPage?.nextState, context) lifecycleOwner.lifecycle.removeObserver(observer)
} }
}
if (uiState.value.isGoNextPageDialog == true) { // 对话框处理
CommonDialog( if (uiState.value.goNextPage != null) {
cancelText = "取消", goNextPage(uiState.value.goNextPage?.nextState, context)
confirmText = "前往下一步", }
title = "是否前往下一步?",
cancelEnable = true,
cancel = {
vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
},
dismiss = { vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false))) },
confirm = {
vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
vm.dispatch(GoToDestinationVm.Action.UpdateTask)
}
)
}
if (uiState.value.showOfflineDialog == true) { if (uiState.value.isGoNextPageDialog == true) {
CommonDialog( CommonDialog(cancelText = "取消",
cancelText = "取消", confirmText = "前往下一步",
confirmText = "离线上传", title = "是否前往下一步?",
title = "任务提交失败,是否离线提交?", cancelEnable = true,
cancelEnable = true, cancel = {
cancel = { vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false))) isGoNextPageDialog = false)))
}, },
dismiss = { vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false))) }, dismiss = {
confirm = { vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false))) isGoNextPageDialog = false)))
vm.dispatch(GoToDestinationVm.Action.UploadOffline) },
} confirm = {
) vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
} isGoNextPageDialog = false)))
vm.dispatch(GoToDestinationVm.Action.UpdateTask)
})
}
BottomSheetScaffold( if (uiState.value.showOfflineDialog == true) {
scaffoldState = scaffoldState, CommonDialog(cancelText = "取消",
topBar = { confirmText = "离线上传",
InServicingHeadView( title = "任务提交失败,是否离线提交?",
title = "作业完成,正在拖往目的地", cancelEnable = true,
onBack = { context.finish() }, cancel = {
orderInfo = orderInfo vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
) showOfflineDialog = false)))
}, },
sheetContent = { dismiss = {
Column( vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
modifier = Modifier showOfflineDialog = false)))
.fillMaxWidth() },
.wrapContentHeight() confirm = {
.verticalScroll(rememberScrollState()) vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
) { showOfflineDialog = false)))
// 滑动指示器 vm.dispatch(GoToDestinationVm.Action.UploadOffline)
Box( })
modifier = Modifier }
.fillMaxWidth()
.padding(vertical = 8.dp),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.width(32.dp)
.height(4.dp)
.background(
color = Color(0xFFE0E0E0),
shape = RoundedCornerShape(2.dp)
)
)
}
// 距离和时间信息 BottomSheetScaffold(scaffoldState = scaffoldState,
Row( topBar = {
modifier = Modifier InServicingHeadView(title = "作业完成,正在拖往目的地",
.fillMaxWidth() onBack = { context.finish() },
.padding(horizontal = 16.dp, vertical = 12.dp), orderInfo = orderInfo)
horizontalArrangement = Arrangement.SpaceBetween, },
verticalAlignment = Alignment.CenterVertically sheetContent = {
) { Column(modifier = Modifier
Text( .fillMaxWidth()
text = if (estimatedTime.isNotEmpty()) .wrapContentHeight()
"预计到达: $estimatedTime" .verticalScroll(rememberScrollState())) { // 滑动指示器
else Box(modifier = Modifier
"计算中...", .fillMaxWidth()
color = Color(0xFF666666), .padding(vertical = 8.dp),
fontSize = 14.sp contentAlignment = Alignment.Center) {
) Box(modifier = Modifier
.width(32.dp)
.height(4.dp)
.background(color = Color(0xFFE0E0E0), shape = RoundedCornerShape(2.dp)))
}
Text( // 距离和时间信息
text = if (remainingDistance > 0) Row(modifier = Modifier
"目的地距离: %.1fkm".format(remainingDistance / 1000f) .fillMaxWidth()
else .padding(horizontal = 16.dp, vertical = 12.dp),
"计算中...", horizontalArrangement = Arrangement.SpaceBetween,
color = Color(0xFFFF4D4F), verticalAlignment = Alignment.CenterVertically) {
fontSize = 14.sp Text(text = if (estimatedTime.isNotEmpty()) "预计到达: $estimatedTime"
) else "计算中...", color = Color(0xFF666666), fontSize = 14.sp)
}
// 使用 HorizontalDivider 替代 Box Text(text = if (remainingDistance > 0) "目的地距离: %.1fkm".format(
HorizontalDivider( remainingDistance / 1000f)
modifier = Modifier else "计算中...", color = Color(0xFFFF4D4F), fontSize = 14.sp)
.fillMaxWidth() }
.alpha(0.1f)
)
// 订单信息 // 使用 HorizontalDivider 替代 Box
Column( HorizontalDivider(modifier = Modifier
modifier = Modifier .fillMaxWidth()
.fillMaxWidth() .alpha(0.1f))
.padding(horizontal = 16.dp, vertical = 12.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = uiState.value.orderInfo?.serviceTypeName ?: "",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Color.Black
)
Row( // 订单信息
horizontalArrangement = Arrangement.spacedBy(8.dp), Column(modifier = Modifier
verticalAlignment = Alignment.CenterVertically .fillMaxWidth()
) { .padding(horizontal = 16.dp, vertical = 12.dp)) {
Box( Text(text = uiState.value.orderInfo?.serviceTypeName ?: "",
modifier = Modifier fontSize = 18.sp,
.background(Color(0xFF9BA1B2), RoundedCornerShape(4.dp)) fontWeight = FontWeight.Bold,
.padding(horizontal = 6.dp, vertical = 2.dp) color = Color.Black)
) { Spacer(modifier = Modifier.height(8.dp))
Text( // 订单标签
text = "月结".takeIf { uiState.value.orderInfo?.settleType == 1 } Row(verticalAlignment = Alignment.CenterVertically,
?: "现金", horizontalArrangement = Arrangement.spacedBy(8.dp)) {
color = Color.White, Box(modifier = Modifier
fontSize = 12.sp .background(Color(0xFF9BA1B2), RoundedCornerShape(4.dp))
) .padding(horizontal = 6.dp, vertical = 2.dp)) {
} Text(text = "月结".takeIf { uiState.value.orderInfo?.settleType == 1 }
?: "现金", color = Color.White, fontSize = 12.sp)
}
Text( Text(text = uiState.value.orderInfo?.orderSource ?: "",
text = uiState.value.orderInfo?.addressProperty ?: "", color = Color.Black,
color = Color(0xFFFD8205), fontSize = 12.sp)
fontSize = 12.sp,
fontWeight = FontWeight.Medium
)
}
}
Spacer(modifier = Modifier.height(12.dp)) Text(text = uiState.value.orderInfo?.addressProperty ?: "",
color = Color(0xFFFD8205),
fontSize = 12.sp,
fontWeight = FontWeight.Medium)
}
// 订单号 Spacer(modifier = Modifier.height(12.dp))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable { uiState.value.orderInfo?.taskCode?.copy(context) }
) {
Text(
text = "单号",
color = Color(0xFF999999),
fontSize = 13.sp
)
Spacer(modifier = Modifier.width(8.dp)) // 订单号
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable {
uiState.value.orderInfo?.taskCode?.copy(context)
}) {
Text(text = "单号", color = Color(0xFF999999), fontSize = 13.sp)
Text( Spacer(modifier = Modifier.width(8.dp))
text = uiState.value.orderInfo?.taskCode ?: "",
color = Color(0xFF666666),
fontSize = 14.sp
)
Spacer(modifier = Modifier.width(8.dp)) Text(text = uiState.value.orderInfo?.taskCode ?: "",
color = Color(0xFF666666),
fontSize = 14.sp)
AsyncImage( Spacer(modifier = Modifier.width(8.dp))
model = R.drawable.sv_copy,
contentDescription = "copy",
modifier = Modifier.size(16.dp)
)
}
Spacer(modifier = Modifier.height(12.dp)) AsyncImage(model = R.drawable.sv_copy,
contentDescription = "copy",
modifier = Modifier.size(16.dp))
}
// 地址信息 Spacer(modifier = Modifier.height(12.dp))
Column(
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
// 救援地
Row(
verticalAlignment = Alignment.Top,
modifier = Modifier
.fillMaxWidth()
.clickable {
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 &&
order.lng != null && order.lng != 0.0
) {
mapView.map.animateCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(order.lat!!, order.lng!!),
16f
)
)
}
}
}
) {
AsyncImage(
model = R.drawable.sv_rescuing,
contentDescription = "rescue",
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(8.dp)) // 地址信息
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { // 救援地
Row(verticalAlignment = Alignment.Top,
modifier = Modifier
.fillMaxWidth()
.clickable {
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(
LatLng(order.lat !!, order.lng !!),
16f))
}
}
}) {
AsyncImage(model = R.drawable.sv_rescuing,
contentDescription = "rescue",
modifier = Modifier.size(16.dp))
Text( Spacer(modifier = Modifier.width(8.dp))
text = uiState.value.orderInfo?.address ?: "",
color = Color.Black,
fontSize = 15.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier.weight(1f)
)
}
// 目的地 Text(text = uiState.value.orderInfo?.address ?: "",
if (!uiState.value.orderInfo?.distAddress.isNullOrBlank()) { color = Color.Black,
Row( fontSize = 15.sp,
verticalAlignment = Alignment.Top, fontWeight = FontWeight.Medium,
modifier = Modifier modifier = Modifier.weight(1f))
.fillMaxWidth() }
.clickable {
uiState.value.orderInfo?.let { order ->
if (order.distLat != null && order.distLat != 0.0 &&
order.distLng != null && order.distLng != 0.0
) {
mapView.map.animateCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(order.distLat!!, order.distLng!!),
16f
)
)
}
}
}
) {
AsyncImage(
model = R.drawable.sv_dist,
contentDescription = "destination",
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(8.dp)) // 目的地
if (! uiState.value.orderInfo?.distAddress.isNullOrBlank()) {
Row(verticalAlignment = Alignment.Top,
modifier = Modifier
.fillMaxWidth()
.clickable {
uiState.value.orderInfo?.let { order ->
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(
LatLng(order.distLat !!, order.distLng !!),
16f))
}
}
}) {
AsyncImage(model = R.drawable.sv_dist,
contentDescription = "destination",
modifier = Modifier.size(16.dp))
Text( Spacer(modifier = Modifier.width(8.dp))
text = uiState.value.orderInfo?.distAddress ?: "",
color = Color.Black,
fontSize = 15.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier.weight(1f)
)
}
}
}
}
// 到达按钮 - 移除外层 Column简化布局 Text(text = uiState.value.orderInfo?.distAddress ?: "",
Button( color = Color.Black,
onClick = { fontSize = 15.sp,
vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = true))) fontWeight = FontWeight.Medium,
}, modifier = Modifier.weight(1f))
modifier = Modifier }
.fillMaxWidth() }
.height(44.dp) }
.padding(horizontal = 16.dp), }
colors = ButtonDefaults.buttonColors(
containerColor = headBgColor
),
shape = RoundedCornerShape(8.dp)
) {
Text(
text = "到达目的地",
color = Color.White,
fontSize = 16.sp,
fontWeight = FontWeight.Medium
)
}
Spacer(modifier = Modifier.height(16.dp)) // 到达按钮 - 移除外层 Column简化布局
} Button(onClick = {
}, vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
sheetPeekHeight = 180.dp, isGoNextPageDialog = true)))
sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp), },
sheetContainerColor = Color.White, modifier = Modifier
sheetDragHandle = null, .fillMaxWidth()
sheetSwipeEnabled = true .height(44.dp)
) { paddingValues -> .padding(horizontal = 16.dp),
Box( colors = ButtonDefaults.buttonColors(containerColor = headBgColor),
modifier = Modifier shape = RoundedCornerShape(8.dp)) {
.fillMaxSize() Text(text = "到达目的地",
.padding(paddingValues) color = Color.White,
) { fontSize = 16.sp,
AndroidView( fontWeight = FontWeight.Medium)
modifier = Modifier }
.fillMaxSize(),
factory = {
AMapLocationClient.updatePrivacyShow(context, true, true)
AMapLocationClient.updatePrivacyAgree(context, true)
mapView.apply {
map.apply {
isTrafficEnabled = false
isMyLocationEnabled = false
uiSettings.isMyLocationButtonEnabled = false
uiSettings.setLogoBottomMargin(-100)
uiSettings.isZoomControlsEnabled = false
// 添加标记点点击事件 Spacer(modifier = Modifier.height(16.dp))
setOnMarkerClickListener { marker -> }
marker.showInfoWindow() },
Handler(Looper.getMainLooper()).postDelayed({ sheetPeekHeight = 180.dp,
marker.hideInfoWindow() sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
}, 800) sheetContainerColor = Color.White,
true sheetDragHandle = null,
} sheetSwipeEnabled = true) { paddingValues ->
} Box(modifier = Modifier
} .fillMaxSize()
}, .padding(paddingValues)) {
update = { AndroidView(modifier = Modifier.fillMaxSize(), factory = {
// 清除旧标记和路线 AMapLocationClient.updatePrivacyShow(context, true, true)
mapView.map.clear() AMapLocationClient.updatePrivacyAgree(context, true)
mapView.apply {
map.apply {
isTrafficEnabled = false
isMyLocationEnabled = false
uiSettings.isMyLocationButtonEnabled = false
uiSettings.setLogoBottomMargin(- 100)
uiSettings.isZoomControlsEnabled = false
// 先绘制路线 // 添加标记点点击事件
uiState.value.routePoints?.let { points -> setOnMarkerClickListener { marker ->
mapView.map.addPolyline( marker.showInfoWindow()
PolylineOptions() Handler(Looper.getMainLooper()).postDelayed({
.addAll(points) marker.hideInfoWindow()
.width(15f) }, 800)
.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.icon_road_green_arrow)) true
.zIndex(1f) }
) }
} }
}, update = { // 清除旧标记和路线
mapView.map.clear()
// 再添加标记点,确保标记点在路线上层 // 先绘制路线
// 添加当前位置标记 uiState.value.routePoints?.let { points ->
if (GlobalData.currentLocation != null) { mapView.map.addPolyline(PolylineOptions().addAll(points).width(15f)
mapView.map.addMarker( .setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.icon_road_green_arrow))
MarkerOptions() .zIndex(1f))
.position(LatLng( }
GlobalData.currentLocation?.latitude!!,
GlobalData.currentLocation?.longitude!!
))
.title("当前位置")
.icon(ImageUtil.vectorToBitmap(context,R.drawable.ic_current_location))
.anchor(0.5f, 0.5f)
.visible(true)
)
}
// 添加救援地标记 // 添加标记点,确保标记点在路线上层
uiState.value.orderInfo?.let { order -> // 添加当前位置标记
if (order.lat != null && order.lat != 0.0 && if (GlobalData.currentLocation != null) {
order.lng != null && order.lng != 0.0 mapView.map.addMarker(MarkerOptions().position(LatLng(GlobalData.currentLocation?.latitude !!,
) { GlobalData.currentLocation?.longitude !!)).title("当前位置")
mapView.map.addMarker( .icon(ImageUtil.vectorToBitmap(context, R.drawable.ic_current_location))
MarkerOptions() .anchor(0.5f, 0.5f).visible(true))
.position(LatLng(order.lat!!, order.lng!!)) }
.title("救援地点")
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
.anchor(0.5f, 0.5f)
)
}
// 添加目的地标记 // 添加救援地标记
if (order.distLat != null && order.distLat != 0.0 && uiState.value.orderInfo?.let { order ->
order.distLng != null && order.distLng != 0.0 if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
) { mapView.map.addMarker(MarkerOptions().position(LatLng(order.lat !!,
mapView.map.addMarker( order.lng !!)).title("救援地点")
MarkerOptions() .icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
.position(LatLng(order.distLat!!, order.distLng!!)) .anchor(0.5f, 0.5f))
.title("目的地") }
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map))
.anchor(0.5f, 0.5f)
)
}
}
// 调整地图显示范围 // 添加目的地标记
val bounds = LatLngBounds.Builder().apply { if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
// 添加当前位置 mapView.map.addMarker(MarkerOptions().position(LatLng(order.distLat !!,
GlobalData.currentLocation?.let { order.distLng !!)).title("目的地")
include(LatLng(it.latitude, it.longitude)) .icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map))
} .anchor(0.5f, 0.5f))
}
}
// 添加救援地点和目的地 // 调整地图显示范围
uiState.value.orderInfo?.let { order -> val bounds = LatLngBounds.Builder().apply { // 添加当前位置
if (order.lat != null && order.lat != 0.0 && GlobalData.currentLocation?.let {
order.lng != null && order.lng != 0.0 include(LatLng(it.latitude, it.longitude))
) { }
include(LatLng(order.lat!!, order.lng!!))
}
if (order.distLat != null && order.distLat != 0.0 && // 添加救援地点和目的地
order.distLng != null && order.distLng != 0.0 uiState.value.orderInfo?.let { order ->
) { if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
include(LatLng(order.distLat!!, order.distLng!!)) include(LatLng(order.lat !!, order.lng !!))
} }
}
}.build()
try { if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
mapView.map.animateCamera( include(LatLng(order.distLat !!, order.distLng !!))
CameraUpdateFactory.newLatLngBounds(bounds, 100) }
) }
} catch (e: Exception) { }.build()
// 如果计算边界失败,则使用默认缩放级别
GlobalData.currentLocation?.let { try {
mapView.map.animateCamera( mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100))
CameraUpdateFactory.newLatLngZoom( } catch (e : Exception) { // 如果计算边界失败,则使用默认缩放级别
LatLng(it.latitude, it.longitude), GlobalData.currentLocation?.let {
15f mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(it.latitude,
) it.longitude), 15f))
) }
} }
} })
} }
) }
}
}
} }

View File

@ -34,252 +34,239 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date
import java.util.Locale import java.util.Locale
class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestinationVm.UiState>() { class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestinationVm.UiState>() {
private val _uiState = MutableStateFlow(UiState()) private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState val uiState get() = _uiState
override fun updateState(uiState: UiState) { override fun updateState(uiState : UiState) {
_uiState.value = uiState _uiState.value = uiState
} }
override fun dispatch(action: Action) { override fun dispatch(action : Action) {
when (action) { when (action) {
is Action.Init -> init() is Action.Init -> init()
is Action.UpdateTask -> updateTask() is Action.UpdateTask -> updateTask()
is Action.UpdateState -> updateState(action.uiState) is Action.UpdateState -> updateState(action.uiState)
is Action.UploadOffline -> updateOfflineTask() is Action.UploadOffline -> updateOfflineTask()
is Action.StartTimer -> startTimer() is Action.StartTimer -> startTimer()
} }
} }
private fun updateOfflineTask(taskRequest: UpdateTaskRequest? = null) { private fun updateOfflineTask(taskRequest : UpdateTaskRequest? = null) {
LoadingManager.showLoading() LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = { ZdLocationManager.getSingleLocation(success = {
LoadingManager.hideLoading() LoadingManager.hideLoading()
val temp = taskRequest ?: UpdateTaskRequest( val temp = taskRequest ?: UpdateTaskRequest(type = "ARRIVE_DEST",
type = "ARRIVE_DEST", taskId = GlobalData.currentOrder?.taskId,
taskId = GlobalData.currentOrder?.taskId, userId = GlobalData.driverInfoBean?.userId,
userId = GlobalData.driverInfoBean?.userId, vehicleId = GlobalData.driverInfoBean?.vehicleId,
vehicleId = GlobalData.driverInfoBean?.vehicleId, flowType = GlobalData.currentOrder?.flowType,
flowType = GlobalData.currentOrder?.flowType, currentState = GlobalData.currentOrder?.taskState,
currentState = GlobalData.currentOrder?.taskState, offlineMode = 0,
offlineMode = 0, operateTime = System.currentTimeMillis().toString(),
operateTime = System.currentTimeMillis().toString(), lat = it.latitude,
lat = it.latitude, lng = it.longitude)
lng = it.longitude)
val offlineUpdateTaskBean = OfflineUpdateTaskBean( val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = temp.type,
type = temp.type, taskId = temp.taskId,
taskId = temp.taskId, flowType = temp.flowType,
flowType = temp.flowType, userId = temp.userId,
userId = temp.userId, vehicleId = temp.vehicleId,
vehicleId = temp.vehicleId, currentState = temp.currentState,
currentState = temp.currentState, offlineMode = 1,
offlineMode = 1, operateTime = temp.operateTime,
operateTime = temp.operateTime, updateTaskLat = temp.lat,
updateTaskLat = temp.lat, updateTaskLng = temp.lng,
updateTaskLng = temp.lng, taskCode = uiState.value.orderInfo?.taskCode,
taskCode = uiState.value.orderInfo?.taskCode, userOrderId = uiState.value.orderInfo?.userOrderId,
userOrderId = uiState.value.orderInfo?.userOrderId, offlineTitle = "救援车发车,正在赶往现场",
offlineTitle = "救援车发车,正在赶往现场", offlineType = 1)
offlineType = 1) insertOfflineTask(offlineUpdateTaskBean)
insertOfflineTask(offlineUpdateTaskBean)
updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus())) updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus()))
updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState), orderInfo = getCurrentOrder())) updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState),
}, failed = { orderInfo = getCurrentOrder()))
LoadingManager.hideLoading() }, failed = {
ToastUtils.showShort(it) LoadingManager.hideLoading()
}) ToastUtils.showShort(it)
} })
}
private fun updateTask() { private fun updateTask() {
LoadingManager.showLoading() LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = { ZdLocationManager.getSingleLocation(success = {
LoadingManager.hideLoading() LoadingManager.hideLoading()
val taskRequest = UpdateTaskRequest( val taskRequest = UpdateTaskRequest(type = "ARRIVE_DEST",
type = "ARRIVE_DEST", taskId = GlobalData.currentOrder?.taskId,
taskId = GlobalData.currentOrder?.taskId, userId = GlobalData.driverInfoBean?.userId,
userId = GlobalData.driverInfoBean?.userId, vehicleId = GlobalData.driverInfoBean?.vehicleId,
vehicleId = GlobalData.driverInfoBean?.vehicleId, flowType = GlobalData.currentOrder?.flowType,
flowType = GlobalData.currentOrder?.flowType, currentState = GlobalData.currentOrder?.taskState,
currentState = GlobalData.currentOrder?.taskState, offlineMode = 0,
offlineMode = 0, operateTime = System.currentTimeMillis().toString(),
operateTime = System.currentTimeMillis().toString(), lat = it.latitude,
lat = it.latitude, lng = it.longitude)
lng = it.longitude) doUploadTask(request = taskRequest)
doUploadTask(request = taskRequest) }, failed = {
}, failed = { LoadingManager.hideLoading()
LoadingManager.hideLoading() ToastUtils.showShort(it)
ToastUtils.showShort(it) })
}) }
}
private fun doUploadTask(request: UpdateTaskRequest) { private fun doUploadTask(request : UpdateTaskRequest) {
if (!getCurrentOrderOfflineTask().isNullOrEmpty()) { if (! getCurrentOrderOfflineTask().isNullOrEmpty()) {
updateOfflineTask(taskRequest = request) updateOfflineTask(taskRequest = request)
return return
} }
LoadingManager.showLoading() LoadingManager.showLoading()
CommonMethod.updateTask(request, success = { CommonMethod.updateTask(request, success = {
LoadingManager.hideLoading() LoadingManager.hideLoading()
updateOrder(getCurrentOrder()?.copy(taskState = it?.nextState)) updateOrder(getCurrentOrder()?.copy(taskState = it?.nextState))
updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder())) updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder()))
}, failed = { msg, code -> }, failed = { msg, code ->
LoadingManager.hideLoading() LoadingManager.hideLoading()
ToastUtils.showShort(msg) ToastUtils.showShort(msg)
if (code == Const.NetWorkException) { if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true)) updateState(uiState.value.copy(showOfflineDialog = true))
} }
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg") LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
}) })
} }
private fun init() { private fun init() {
updateState(uiState = uiState.value.copy(orderInfo = getCurrentOrder())) updateState(uiState = uiState.value.copy(orderInfo = getCurrentOrder()))
buildMarkers(getCurrentOrder()) buildMarkers(getCurrentOrder())
searchDrivingRoute(getCurrentOrder()) searchDrivingRoute(getCurrentOrder()) // dispatch(Action.StartTimer)
// dispatch(Action.StartTimer) }
}
private fun searchDrivingRoute(orderInfo: OrderInfo?) { private fun searchDrivingRoute(orderInfo : OrderInfo?) { // 如果没有当前位置,则不进行路径规划
// 如果没有当前位置,则不进行路径规划 if (GlobalData.currentLocation == null) return
if (GlobalData.currentLocation == null) return
val currentPoint = LatLonPoint( val currentPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
GlobalData.currentLocation?.latitude ?: 0.0, GlobalData.currentLocation?.longitude ?: 0.0)
GlobalData.currentLocation?.longitude ?: 0.0
)
// 获取目的地坐标 // 获取目的地坐标
val destPoint = if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && val destPoint =
orderInfo.distLng != null && orderInfo.distLng != 0.0 if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
) { LatLonPoint(orderInfo.distLat !!, orderInfo.distLng !!)
LatLonPoint(orderInfo.distLat!!, orderInfo.distLng!!) } else null
} else null
// 如果没有目的地,则不进行规划 // 如果没有目的地,则不进行规划
if (destPoint == null) return if (destPoint == null) return
// 使用 Application Context 创建路由搜索对象 // 使用 Application Context 创建路由搜索对象
val routeSearch = RouteSearch(GlobalData.application) val routeSearch = RouteSearch(GlobalData.application)
routeSearch.setRouteSearchListener(object : RouteSearch.OnRouteSearchListener { routeSearch.setRouteSearchListener(object : RouteSearch.OnRouteSearchListener {
override fun onDriveRouteSearched(result: DriveRouteResult?, errorCode: Int) { override fun onDriveRouteSearched(result : DriveRouteResult?, errorCode : Int) {
if (errorCode == 1000 && result != null && result.paths.isNotEmpty()) { if (errorCode == 1000 && result != null && result.paths.isNotEmpty()) {
val path = result.paths[0] val path = result.paths[0]
val points = path.steps.flatMap { step -> val points = path.steps.flatMap { step ->
step.polyline.map { LatLng(it.latitude, it.longitude) } step.polyline.map { LatLng(it.latitude, it.longitude) }
} }
val durationInSeconds = path.duration val duration = path.duration
val arrivalTime = SimpleDateFormat("HH:mm:ss", val arrivalTime = System.currentTimeMillis() + duration * 1000
Locale.getDefault()).format(System.currentTimeMillis() + durationInSeconds * 1000) val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val estimatedTime = dateFormat.format(Date(arrivalTime))
updateState(uiState.value.copy(routePoints = points,
estimatedArrivalTime = estimatedTime,
remainingDistance = path.distance))
} else {
LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode")
}
}
updateState(uiState.value.copy(routePoints = points, estimatedArrivalTime =arrivalTime, remainingDistance = path.distance )) override fun onBusRouteSearched(p0 : BusRouteResult?, p1 : Int) {}
} else { override fun onWalkRouteSearched(p0 : WalkRouteResult?, p1 : Int) {}
LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode") override fun onRideRouteSearched(p0 : RideRouteResult?, p1 : Int) {}
} })
}
override fun onBusRouteSearched(p0: BusRouteResult?, p1: Int) {} // 规划当前位置到目的地的路线
override fun onWalkRouteSearched(p0: WalkRouteResult?, p1: Int) {} val query = RouteSearch.FromAndTo(currentPoint, destPoint)
override fun onRideRouteSearched(p0: RideRouteResult?, p1: Int) {} val driveQuery =
}) RouteSearch.DriveRouteQuery(query, RouteSearch.DrivingDefault, null, null, "")
routeSearch.calculateDriveRouteAsyn(driveQuery)
}
// 规划当前位置到目的地的路线 private fun calculateRemainingDistance() : Pair<Float, String> {
val query = RouteSearch.FromAndTo(currentPoint, destPoint) val currentLocation = GlobalData.currentLocation ?: return Pair(0f, "")
val driveQuery = RouteSearch.DriveRouteQuery(query, RouteSearch.DrivingDefault, null, null, "") val orderInfo = _uiState.value.orderInfo ?: return Pair(0f, "")
routeSearch.calculateDriveRouteAsyn(driveQuery)
}
private fun calculateRemainingDistance(): Pair<Float, String> { // 计算到目的地的距离
val currentLocation = GlobalData.currentLocation ?: return Pair(0f, "") val distance = if (orderInfo.distLat != null && orderInfo.distLng != null) {
val orderInfo = _uiState.value.orderInfo ?: return Pair(0f, "") AMapUtils.calculateLineDistance(LatLng(currentLocation.latitude,
currentLocation.longitude), LatLng(orderInfo.distLat !!, orderInfo.distLng !!))
} else 0f
// 计算到目的地的距离 if (distance <= 0f) {
val distance = if (orderInfo.distLat != null && orderInfo.distLng != null) { return Pair(0f, "")
AMapUtils.calculateLineDistance( }
LatLng(currentLocation.latitude, currentLocation.longitude),
LatLng(orderInfo.distLat!!, orderInfo.distLng!!)
)
} else 0f
if (distance <= 0f) { // 计算预计到达时间假设平均速度40km/h
return Pair(0f, "") val timeInSeconds = ((distance / 1000.0 * 60.0 / 40.0) * 60).toInt()
} val calendar = Calendar.getInstance()
calendar.add(Calendar.SECOND, timeInSeconds)
val arrivalTime = SimpleDateFormat("HH:mm", Locale.getDefault()).format(calendar.time)
// 计算预计到达时间假设平均速度40km/h return Pair(distance, arrivalTime)
val timeInSeconds = ((distance / 1000.0 * 60.0 / 40.0) * 60).toInt() }
val calendar = Calendar.getInstance()
calendar.add(Calendar.SECOND, timeInSeconds)
val arrivalTime = SimpleDateFormat("HH:mm", Locale.getDefault()).format(calendar.time)
return Pair(distance, arrivalTime) private var timerJob : Job? = null
}
private var timerJob: Job? = null private fun startTimer() {
timerJob?.cancel()
timerJob = viewModelScope.launch {
while (isActive) {
val (distance, arrivalTime) = calculateRemainingDistance()
_uiState.update {
it.copy(remainingDistance = distance, estimatedArrivalTime = arrivalTime)
}
delay(1000)
}
}
}
private fun startTimer() { override fun onCleared() {
timerJob?.cancel() super.onCleared()
timerJob = viewModelScope.launch { timerJob?.cancel()
while (isActive) { }
val (distance, arrivalTime) = calculateRemainingDistance()
_uiState.update {
it.copy(
remainingDistance = distance,
estimatedArrivalTime = arrivalTime
)
}
delay(1000)
}
}
}
override fun onCleared() { private fun buildMarkers(orderInfo : OrderInfo?) {
super.onCleared() val markers = arrayListOf<MarkerOptions>()
timerJob?.cancel() if (orderInfo?.lat != null && orderInfo.lat != 0.0 && orderInfo.lng != null && orderInfo.lng != 0.0) { // 获取矢量图资源文件
} val startMarkers =
MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
.position(LatLng(orderInfo.lat !!, orderInfo.lng !!)).infoWindowEnable(false)
.visible(true)
markers.add(startMarkers)
}
private fun buildMarkers(orderInfo: OrderInfo?) { if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
val markers = arrayListOf<MarkerOptions>() val startMarkers =
if (orderInfo?.lat != null && orderInfo.lat != 0.0 && orderInfo.lng != null && orderInfo.lng != 0.0) { MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map))
// 获取矢量图资源文件 .position(LatLng(orderInfo.distLat !!, orderInfo.distLng !!)).visible(true)
val startMarkers = MarkerOptions() markers.add(startMarkers)
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map)) }
.position(LatLng(orderInfo.lat!!, orderInfo.lng!!)) updateState(uiState.value.copy(markers = markers))
.infoWindowEnable(false) }
.visible(true)
markers.add(startMarkers)
}
if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) { sealed class Action {
val startMarkers = MarkerOptions() data object Init : Action()
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_dist_map)) data object UpdateTask : Action()
.position(LatLng(orderInfo.distLat!!, orderInfo.distLng!!)) data class UpdateState(val uiState : UiState) : Action()
.visible(true) data object UploadOffline : Action()
markers.add(startMarkers) data object StartTimer : Action()
} }
updateState(uiState.value.copy(markers = markers))
}
sealed class Action { data class UiState(val orderInfo : OrderInfo? = null,
data object Init : Action() val showCallPhoneDialog : Boolean? = false,
data object UpdateTask : Action() val markers : ArrayList<MarkerOptions>? = null,
data class UpdateState(val uiState: UiState) : Action() val goNextPage : UpdateTaskBean? = null,
data object UploadOffline : Action() val isGoNextPageDialog : Boolean? = null,
data object StartTimer : Action() val showOfflineDialog : Boolean? = null,
} val routePoints : List<LatLng>? = null,
val remainingDistance : Float = 0f,
data class UiState( val estimatedArrivalTime : String = "")
val orderInfo: OrderInfo? = null,
val showCallPhoneDialog: Boolean? = false,
val markers: ArrayList<MarkerOptions>? = null,
val goNextPage: UpdateTaskBean? = null,
val isGoNextPageDialog: Boolean? = null,
val showOfflineDialog: Boolean? = null,
val routePoints: List<LatLng>? = null,
val remainingDistance: Float = 0f,
val estimatedArrivalTime: String = ""
)
} }

View File

@ -38,6 +38,7 @@ import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date
import java.util.Locale import java.util.Locale
class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>() { class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>() {
@ -155,7 +156,13 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
val points = path.steps.flatMap { step -> val points = path.steps.flatMap { step ->
step.polyline.map { LatLng(it.latitude, it.longitude) } step.polyline.map { LatLng(it.latitude, it.longitude) }
} }
updateState(uiState.value.copy(routePoints = points)) val duration = path.duration
val arrivalTime = System.currentTimeMillis() + duration * 1000
val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
val estimatedTime = dateFormat.format(Date(arrivalTime))
updateState(uiState.value.copy(routePoints = points,
estimatedArrivalTime = estimatedTime,
remainingDistance = path.distance))
} else { } else {
LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode") LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode")
} }
@ -176,16 +183,16 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
private var timerJob : Job? = null private var timerJob : Job? = null
private fun startTimer() { private fun startTimer() {
timerJob?.cancel() // timerJob?.cancel()
timerJob = viewModelScope.launch { // timerJob = viewModelScope.launch {
while (isActive) { // 计算从当前位置到目标点的距离和到达时间 // while (isActive) { // 计算从当前位置到目标点的距离和到达时间
val (distance, arrivalTime) = calculateRemainingDistance() // val (distance, arrivalTime) = calculateRemainingDistance()
_uiState.update { // _uiState.update {
it.copy(remainingDistance = distance, estimatedArrivalTime = arrivalTime) // it.copy(remainingDistance = distance, estimatedArrivalTime = arrivalTime)
} // }
delay(1000) // 每秒更新一次 // delay(1000) // 每秒更新一次
} // }
} // }
} }
private fun calculateRemainingDistance() : Pair<Float, String> { private fun calculateRemainingDistance() : Pair<Float, String> {

View File

@ -5,7 +5,6 @@ import android.content.Intent
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -51,5 +50,5 @@ fun SignatureView(modifier: Modifier = Modifier, success: (String?) -> Unit, ser
intent.putExtra("lineLength", 10) //每行显示字数(超出屏幕支持横向滚动) intent.putExtra("lineLength", 10) //每行显示字数(超出屏幕支持横向滚动)
signatureLauncher.launch(intent) signatureLauncher.launch(intent)
}, },
contentScale = ContentScale.FillBounds) contentScale = ContentScale.Inside)
} }

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="Theme.Dealer" parent="Theme.AppCompat.Light.NoActionBar" /> <style name="Theme.Zd_sdk_demo" parent="Theme.Dealer" />
<style name="Theme.Zd_sdk_demo" parent="android:Theme.Material.Light.NoActionBar" /> <style name="Theme.Dealer" parent="Theme.AppCompat.Light.NoActionBar" />
</resources> </resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">sino-assist.com</domain>
</domain-config>
</network-security-config>