refactor(servicing): 更新ServicingModule

This commit is contained in:
songzhiling
2025-06-17 11:49:32 +08:00
parent 405f732502
commit ea83fc62a9
75 changed files with 3696 additions and 2558 deletions

View File

@ -4,7 +4,7 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-04-27T03:49:03.966203100Z">
<DropdownSelection timestamp="2025-05-09T04:23:51.991280900Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=4f3d584c" />

View File

@ -80,52 +80,64 @@
<activity
android:name="com.za.base.NetworkRouteSelectionActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.camera.ServicePeopleRealActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.inservice_people_confirm.ServicePeopleConfirmActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.main.ServiceLauncherActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.main.ServicingMainActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.departure_photo.DeparturePhotoActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.order_confirm.input_money.InputMoneyActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.order_confirm.modify_money.ModifyMoneyActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.new_order.NewOrderActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.order_confirm.real_order_confirm.RealOrderConfirmActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.order_confirm.receive_money.ReceiveMoneyActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.map_search.MapSearchActivity"
android:exported="false" />
android:exported="false"
android:screenOrientation="portrait" />
<service
android:name="com.za.ui.order_report.ReportFloatingManager"
@ -147,26 +159,32 @@
android:name="com.za.ui.h5.CommonH5Activity"
android:exported="false"
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.order_give_up.OrderGiveUpActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.in_servicing_setting.OrderRequirementsActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.order_confirm.OrderConfirmActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.destination_photo.DestinationPhotoActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.go_to_destination.GoToDestinationActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.signature.GridPaintActivity"
@ -176,6 +194,7 @@
android:name="com.za.ui.servicing.operation.InOperationActivity"
android:exported="false"
android:label="@string/title_activity_in_operation"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.camera.ZdCameraXActivity"
@ -189,21 +208,24 @@
<activity
android:name="com.za.ui.servicing.check_vehicle.CheckVehicleActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.verify.VerifyOrderActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.go_accident.GoAccidentSiteActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<activity
android:name="com.za.ui.servicing.wait_to_start.WaitToStartActivity"
android:exported="false"
android:screenOrientation="portrait"
android:theme="@style/Theme.Dealer" />
<receiver
android:name="com.za.service.ZdPushServiceReceive"
android:exported="false">

View File

@ -24,12 +24,14 @@ object AppConfig {
when (envType) {
Const.NetEnv.Main -> release()
Const.NetEnv.Review -> review()
else -> release()
}
} else {
when (envType) {
Const.NetEnv.CRM1 -> crm1()
Const.NetEnv.CRM2 -> crm2()
Const.NetEnv.UAT -> uat()
else -> crm1()
}
}
}

View File

@ -5,9 +5,10 @@ import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.core.view.WindowCompat
import com.tencent.smtt.sdk.QbSdk
import com.za.base.BaseVm.Companion.showTipDialog
import com.za.base.theme.DealerTheme
import com.za.base.view.CommonDialog
import com.za.base.view.LoadingManager
@ -21,20 +22,22 @@ abstract class BaseActivity : PushMessageActivity() {
enableEdgeToEdge() // 可选:设置导航栏图标颜色(深色/浅色)
setContent {
DealerTheme {
val tipDialog by remember { showTipDialog }
val showLoading by remember { LoadingManager.showLoading }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val windowInsetsController =
WindowCompat.getInsetsController(window, this.window.decorView)
windowInsetsController.isAppearanceLightStatusBars = false
}
ContentView()
if (LoadingManager.showLoading.value) {
if (showLoading) {
LoadingManager.LoadingView()
}
if (showTipDialog.value != null) {
CommonDialog(message = showTipDialog.value ?: "",
if (tipDialog != null) {
CommonDialog(message = tipDialog ?: "",
title = "提示",
confirmText = "我已了解",
cancelText = "",
confirm = { BaseVm.hideTipDialog() },
cancel = { BaseVm.hideTipDialog() },
dismiss = { BaseVm.hideTipDialog() },

View File

@ -3,14 +3,15 @@ package com.za.base
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
val showTipDialog = mutableStateOf<String?>(null) //提示框
abstract class BaseVm<T, U> : ViewModel() {
val tag: String = javaClass.simpleName
abstract fun updateState(uiState: U)
abstract fun dispatch(action: T)
val tag : String = javaClass.simpleName
abstract fun updateState(uiState : U)
abstract fun dispatch(action : T)
companion object {
val showTipDialog = mutableStateOf<String?>(null)//提示框
fun showTipDialog(msg: String) {
fun showTipDialog(msg : String) {
showTipDialog.value = msg
}

View File

@ -50,4 +50,17 @@ object Const {
const val CRM2 = 3 //测试环境
const val UAT = 4 //测试环境
}
object PushMessageType {
const val ACTION_SDK = "com.zd.servicing.PUSH_MESSAGE"
const val ACTION_MAIN = "com.za.rescue.dealer.PUSH_MESSAGE"
const val BROADCAST = "broadcast"
const val GIVE_UP = "giveUp"
const val IMPORTANT_TIP = "importantTip"
const val NEW_ORDER = "newOrder"
const val RE_DISPATCH = "reDispatch"
const val MODIFY = "modify"
const val REVOKE = "revoke"
const val GO_MAIN_PAGE = "goMainPage"
}
}

View File

@ -1,59 +1,64 @@
package com.za.base
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.gson.Gson
import com.za.bean.JpushBean
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.service.PushListener
import com.za.service.ServiceManager
import com.za.service.ZdPushServiceReceive
open class PushMessageActivity : AppCompatActivity() {
private var currentDialog : AlertDialog? = null
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
// setupPushMessageReceiver()
super.onCreate(savedInstanceState) // setupPushMessageReceiver()
}
private fun setupPushMessageReceiver() { // 注册推送消息接收器
ServiceManager.registerPushListener(object : PushListener {
override fun broadcast(msg : String) {
sendMessageToMainProcess("broadcast", msg)
sendMessageToMainProcess(type = Const.PushMessageType.BROADCAST,
message = msg,
context = this@PushMessageActivity)
}
override fun giveUpOrder(jpushBean : JpushBean) {
sendMessageToMainProcess("giveUp", Gson().toJson(jpushBean))
sendMessageToMainProcess(type = Const.PushMessageType.GIVE_UP,
message = Gson().toJson(jpushBean),
context = this@PushMessageActivity)
}
override fun importantTip(jpushBean : JpushBean) {
sendMessageToMainProcess("importantTip", Gson().toJson(jpushBean))
sendMessageToMainProcess(type = Const.PushMessageType.IMPORTANT_TIP,
message = Gson().toJson(jpushBean),
context = this@PushMessageActivity)
}
override fun newOrderMsg(jpushBean : JpushBean) {
sendMessageToMainProcess("newOrder", Gson().toJson(jpushBean))
sendMessageToMainProcess(type = Const.PushMessageType.NEW_ORDER,
message = Gson().toJson(jpushBean),
context = this@PushMessageActivity)
}
override fun reDispatchOrder(jpushBean : JpushBean) {
sendMessageToMainProcess("reDispatch", Gson().toJson(jpushBean))
sendMessageToMainProcess(type = Const.PushMessageType.RE_DISPATCH,
message = Gson().toJson(jpushBean),
context = this@PushMessageActivity)
}
override fun revokeOrder(jpushBean : JpushBean) {
sendMessageToMainProcess("revoke", Gson().toJson(jpushBean))
sendMessageToMainProcess(type = Const.PushMessageType.REVOKE,
message = Gson().toJson(jpushBean),
context = this@PushMessageActivity)
}
})
}
private fun sendMessageToMainProcess(type : String, message : String) { // 使用广播将消息发送到主进程
val intent = Intent(ZdPushServiceReceive.RECEIVE_ACTION).setPackage(packageName)
intent.putExtra("type", type)
intent.putExtra("message", message)
sendBroadcast(intent)
LogUtil.print("KeepAliveService", "发送消息到主进程: $type")
}
override fun onPause() {
super.onPause()
@ -72,5 +77,17 @@ open class PushMessageActivity : AppCompatActivity() {
companion object {
internal const val GIVE_UP_TYPE_NORMAL = 1
internal const val DIALOG_TAG_GIVE_UP = "giveUp"
private fun sendMessageToMainProcess(context : Context, type : String, message : String) {
// 使用广播将消息发送到主进程
val intent = Intent(Const.PushMessageType.ACTION_MAIN.takeIf { GlobalData.isMaster }
?: Const.PushMessageType.ACTION_SDK)
intent.setPackage(context.packageName)
intent.putExtra("type", type)
intent.putExtra("message", message)
context.sendBroadcast(intent)
LogUtil.print("KeepAliveService", "发送消息到主进程: $type")
}
}
}

View File

@ -1,7 +1,6 @@
package com.za.base.view
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@ -11,23 +10,32 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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
import com.za.base.theme.buttonBgColor
import com.za.base.theme.headBgColor
import com.za.ext.noDoubleClick
@Composable
fun CommonButton(text: String, onClick: () -> Unit) {
fun CommonButton(modifier : Modifier = Modifier, text : String, onClick : () -> Unit) {
Box(modifier = modifier.noDoubleClick { onClick() }, contentAlignment = Alignment.Center) {
Text(text = text,
color = Color.White,
fontSize = 15.sp,
fontWeight = FontWeight.Medium,
style = TextStyle.Default.copy(fontSize = 15.sp, fontWeight = FontWeight.Medium))
}
}
@Composable
fun CommonButton(text : String, onClick : () -> Unit) {
Box(modifier = Modifier
.fillMaxWidth()
.noDoubleClick { onClick() }
.padding(horizontal = 60.dp, vertical = 10.dp)
.background(color = buttonBgColor, shape = RoundedCornerShape(4.dp))
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
Text(text = text, color = Color.White,
fontSize = 15.sp,
fontWeight = FontWeight.Medium)
Text(text = text, color = Color.White, fontSize = 15.sp, fontWeight = FontWeight.Medium, style = TextStyle.Default.copy())
}
}

View File

@ -30,6 +30,7 @@ import androidx.compose.ui.window.DialogProperties
import coil.compose.AsyncImage
import com.za.base.theme.black90
import com.za.common.util.MapUtil
import com.za.ext.noDoubleClick
import com.za.servicing.R
@Composable
@ -146,7 +147,7 @@ fun ReTakePhotoDialog(title : String? = null,
Box(modifier = Modifier
.width(202.dp)
.clickable { confirm() }
.noDoubleClick { confirm() }
.background(color = Color(0xFF3A58B1), shape = RoundedCornerShape(23.dp))
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
Text(text = "重拍",

View File

@ -1,23 +1,27 @@
package com.za.base.view
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
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.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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
import coil.compose.AsyncImage
import com.za.base.theme.headBgColor
import com.za.servicing.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -26,21 +30,34 @@ fun HeadView(title : String,
isCanBack : Boolean = true,
action : @Composable () -> Unit = {}) {
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 = {
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)
}
action()
}
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())
}
}
},
actions = { action() })
AppTipsView()
}
@ -50,11 +67,18 @@ fun HeadView(title : String,
@Composable
fun HeadViewNotBack(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 = {})
Box(modifier = Modifier
.fillMaxWidth()
.background(color = headBgColor)
.padding(horizontal = 10.dp, vertical = 5.dp), contentAlignment = Alignment.Center) {
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()
}

View File

@ -7,120 +7,124 @@ import java.io.Serializable
import java.nio.charset.StandardCharsets
data class JpushBean(
val pushType: Int? = null, //0 新任务 1 任务取消 2 任务变更
val taskId: Int? = null,//订单号 "taskId":5313005
val taskCode: String? = null, //订单编码 "taskCode":"ZD20190308009965"
val customerName: String? = null, //客户姓名 "customerName":"越继安"
val customerPhone: String? = null, //客户电话 "customerPhone":"18078815268"
val carBrand: String? = null, //车辆品牌 "carBrand":""
val carModel: String? = null,//车辆型号 "carModel":"秦"
val contract: String? = null, //车辆型号 "carModel":"秦"
val typeDesc: String? = null, //推送的附加消息 revoke 撤回 giveUp放弃 reDispatch改派
val userOrderId: Int? = null,
val carNo: String? = null, //客户车车牌号 "carNo":"粤AF53918"
val taskState: String? = null, //订单状态 "taskState":"GOTO"
val address: String? = null, //任务地址 "address":"广东省广州市白云区107国道石井凰岗路342号(白云黄石、同德围地区近庆丰兴隆公园)美景大酒店"
val addressProperty: String? = null,//任务地址类型 "addressProperty":"地面"
val hotline: String? = null, //任务地址类型 "addressProperty":"地面"
val schedulingFinalRule: Int? = null, //案件类型 0 传统案件 1 聚合派工
val addressRemark: String? = null,
val distAddress: String? = null, //目的地地址 "distAddress":"广东省广州市白云区雅岗南大道"
val distAddressRemark: String? = null,
val expectArriveTime: String? = null, //预计到达时间 "expectArriveTime":"2019-03-08 05:11:07"
val serviceTypeName: String? = null,//服务类型 "serviceTypeName":"故障--平板拖车"
val dispatchTime: String? = null, //派单时间 "dispatchTime":"2019-03-08 04:26:07"
val lat: Double? = null,
val lng: Double? = null,
val distLat: Double? = null,
val distLng: Double? = null,
val importantTip: String? = null,
val tipContent: String? = null,
val settleType: Int?=null,//结算类型 1 月结 2 现金
var orderSource: String? = null, // "orderSource":"中道救援-比亚迪道路救援项目"
val hasReplaceBatteryCapable: Int? = null ,//是否有更换电瓶的能力 1 搭电可以更换电瓶 2搭电不可以更换电瓶 其他的不展示
var voiceType : Int?=null //语音提示类型 1小修单 2拖车单 3困境单
val pushType : Int? = null, //0 新任务 1 任务取消 2 任务变更
val taskId : Int? = null, //订单号 "taskId":5313005
val taskCode : String? = null, //订单编码 "taskCode":"ZD20190308009965"
val customerName : String? = null, //客户姓名 "customerName":"越继安"
val customerPhone : String? = null, //客户电话 "customerPhone":"18078815268"
val carBrand : String? = null, //车辆品牌 "carBrand":""
val carModel : String? = null, //车辆型号 "carModel":"秦"
val contract : String? = null, //车辆型号 "carModel":"秦"
val typeDesc : String? = null, //推送的附加消息 revoke 撤回 giveUp放弃 reDispatch改派
val userOrderId : Int? = null,
val carNo : String? = null, //客户车车牌号 "carNo":"粤AF53918"
val taskState : String? = null, //订单状态 "taskState":"GOTO"
val address : String? = null, //任务地址 "address":"广东省广州市白云区107国道石井凰岗路342号(白云黄石、同德围地区近庆丰兴隆公园)美景大酒店"
val addressProperty : String? = null, //任务地址类型 "addressProperty":"地面"
val hotline : String? = null, //任务地址类型 "addressProperty":"地面"
val schedulingFinalRule : Int? = null, //案件类型 0 传统案件 1 聚合派工
val addressRemark : String? = null,
val distAddress : String? = null, //目的地地址 "distAddress":"广东省广州市白云区雅岗南大道"
val distAddressRemark : String? = null,
val expectArriveTime : String? = null, //预计到达时间 "expectArriveTime":"2019-03-08 05:11:07"
val serviceTypeName : String? = null, //服务类型 "serviceTypeName":"故障--平板拖车"
val dispatchTime : String? = null, //派单时间 "dispatchTime":"2019-03-08 04:26:07"
val lat : Double? = null,
val lng : Double? = null,
val distLat : Double? = null,
val distLng : Double? = null,
val importantTip : String? = null,
val tipContent : String? = null,
val isAppoint : Int? = null, //是否是预约单 1 预约单
val appointTime : String? = null, //预约时间
val settleType : Int? = null, //结算类型 1 月结 2 现金
var orderSource : String? = null, // "orderSource":"中道救援-比亚迪道路救援项目"
val hasReplaceBatteryCapable : Int? = null, //是否有更换电瓶的能力 1 搭电可以更换电瓶 2搭电不可以更换电瓶 其他的不展示
var voiceType : Int? = null, //语音提示类型 1小修单 2拖车单 3困境单)
) : Serializable {
fun isNeedCallCustomPhone(): Boolean {
fun isNeedCallCustomPhone() : Boolean {
return "210" != customerPhone && "230" != customerPhone
}
}
data class NewOrderRequestBean(val vehicleId: Int? = null)
data class NewOrderRequestBean(val vehicleId : Int? = null)
//历史订单状态
data class HistoryTaskBean(
val taskId: Int? = null, //订单号
val taskCode: String? = null, //订单编码
val userOrderId: Int? = null,
val userOrderCode: String? = null, //只有电子工单历史补传才需要传
val supplierAudit: Int? = null, //审核状态 0待补充 1 待审核 2审核不通过 3 审核通过
val supplierAuditStr: String? = null, //审核状态描述
val missingContent: String? = null, //缺失内容
val auditFailReason: String? = null, //审核失败原因
val customerName: String? = null, //客户姓名
val customerPhone: String? = null, //客户电话
val carBrand: String? = null, //车辆品牌
val carModel: String? = null, //车辆型号
val carNo: String? = null, //客户车车牌号 "
val carVin: String? = null, //客户车Vin码
val taskState: String? = null, //订单状态
val address: String? = null, //任务地址
val addressRemark: String? = null, //事发地地址补充
val addressProperty: String? = null, //任务地址类型
val lat: Double? = null,
val lng: Double? = null,
val distAddress: String? = null, //目的地地址
val distAddressRemark: String? = null, //目的地地址补充
val distLat: Double? = null,
val distLng: Double? = null,
val expectArriveTime: String? = null, //预计到达时间
val serviceTypeName: String? = null, //服务类型
val orderSource: String? = null, //
val flowType: Int? = null, //流程类型 "flowType":2
val settleType: Int? = null, //结算类型 1 月结 2 现金
val supplierId: Int? = null,
val successTime: String? = null, //完成时间 "dispatchTime":"2019-03-08 04:26:07"
val verifyType: Int? = null, //验证类型 "verifyType":1
val verifyValue: String? = null, //验证内容
val holdon: Boolean? = null, //是否被挂起 "holdon":false
val externalCode: String? = null, //流水号
val vehicleName: String? = null,
val traceIdAB: Int? = null,
val mileageAB: Int? = null,
val traceABUrl: String? = null,
val traceIdBC: Int? = null,
val mileageBC: Int? = null,
val mileageCA: Int? = null,
val traceBCUrl: String? = null,
val createTime: String? = null,
val acceptTime: String? = null,
val arriveTime: String? = null,
val arriveDestTime: String? = null,
val giveupTime: String? = null,
val giveupAddress: String? = null,
val giveupLat: Double? = null,
val giveupLng: Double? = null,
val needWaterMarker: Boolean? = null,
val needShowPhoneBrand: Boolean? = null,
val policyNo: String? = null, // 平安拖车责任险 保单号
val taskId : Int? = null, //订单号
val taskCode : String? = null, //订单编码
val userOrderId : Int? = null,
val userOrderCode : String? = null, //只有电子工单历史补传才需要传
val supplierAudit : Int? = null, //审核状态 0待补充 1 待审核 2审核不通过 3 审核通过
val supplierAuditStr : String? = null, //审核状态描述
val missingContent : String? = null, //缺失内容
val auditFailReason : String? = null, //审核失败原因
val customerName : String? = null, //客户姓名
val customerPhone : String? = null, //客户电话
val carBrand : String? = null, //车辆品牌
val carModel : String? = null, //车辆型号
val carNo : String? = null, //客户车车牌号 "
val carVin : String? = null, //客户车Vin码
val taskState : String? = null, //订单状态
val address : String? = null, //任务地址
val addressRemark : String? = null, //事发地地址补充
val addressProperty : String? = null, //任务地址类型
val lat : Double? = null,
val lng : Double? = null,
val distAddress : String? = null, //目的地地址
val distAddressRemark : String? = null, //目的地地址补充
val distLat : Double? = null,
val distLng : Double? = null,
val expectArriveTime : String? = null, //预计到达时间
val serviceTypeName : String? = null, //服务类型
val orderSource : String? = null, //
val flowType : Int? = null, //流程类型 "flowType":2
val settleType : Int? = null, //结算类型 1 月结 2 现金
val supplierId : Int? = null,
val successTime : String? = null, //完成时间 "dispatchTime":"2019-03-08 04:26:07"
val verifyType : Int? = null, //验证类型 "verifyType":1
val verifyValue : String? = null, //验证内容
val holdon : Boolean? = null, //是否被挂起 "holdon":false
val externalCode : String? = null, //流水号
val vehicleName : String? = null,
val traceIdAB : Int? = null,
val mileageAB : Int? = null,
val traceABUrl : String? = null,
val traceIdBC : Int? = null,
val mileageBC : Int? = null,
val mileageCA : Int? = null,
val traceBCUrl : String? = null,
val createTime : String? = null,
val acceptTime : String? = null,
val arriveTime : String? = null,
val arriveDestTime : String? = null,
val giveupTime : String? = null,
val giveupAddress : String? = null,
val giveupLat : Double? = null,
val giveupLng : Double? = null,
val needWaterMarker : Boolean? = null,
val needShowPhoneBrand : Boolean? = null,
val policyNo : String? = null, // 平安拖车责任险 保单号
val electronOrderState: String? = null, //电子工单状态
val electronOrderState : String? = null, //电子工单状态
val hasReplaceBatteryCapable: Int? = null, //是否具有更换电瓶的能力
val hasReplaceBatteryCapable : Int? = null, //是否具有更换电瓶的能力
val hasReplaceBattery: Int = 0 //1已更换过 2有更换能力但没更换过 0无
val hasReplaceBattery : Int = 0, //1已更换过 2有更换能力但没更换过 0无)
) : Serializable {
fun getEleOrderH5Url(): String? {
fun getEleOrderH5Url() : String? {
if (electronOrderState == null || electronOrderState != "3") {
return null
}
val paramQuery = (("userOrderId=$userOrderId").toString() + "&userOrderCode=" + taskCode) + "&supplierId=" + userOrderId
return AppConfig.Resource_URL + "/electronicWorkOrder/index.html?" + EncodeUtils.base64Encode2String(paramQuery.toByteArray(StandardCharsets.UTF_8))
val paramQuery =
(("userOrderId=$userOrderId").toString() + "&userOrderCode=" + taskCode) + "&supplierId=" + userOrderId
return AppConfig.Resource_URL + "/electronicWorkOrder/index.html?" + EncodeUtils.base64Encode2String(
paramQuery.toByteArray(StandardCharsets.UTF_8))
}
fun getSettleTypeStr(): String {
fun getSettleTypeStr() : String {
return when (settleType) {
1 -> {
"月结"
@ -142,33 +146,35 @@ data class HistoryPhotoTemplates(
/**
* 任务节点
*/
val taskStatus: Int? = null,
val taskStatus : Int? = null,
/**
* 图片节点名称
*/
val taskStatusString: String? = null,
val taskStatusString : String? = null,
/**
* 该节点下的所有历史照片信息
*/
val photoList: List<HistoryPhotoTemplateItem>? = null
)
val photoList : List<HistoryPhotoTemplateItem>? = null)
data class HistoryPhotoTemplateItem(
val photoUrl: String? = null,
val tag: String? = null,
val imageTitle: String? = null,
val lon: String? = null,
val lat: String? = null,
val templatePhotoType: Int = 0, //1 照片 2 工单照片
val takePhotoTime: String? = null,
val takeAddress: String? = null,
val uploadStatus: String? = null,
val uploadState: Int? = 0, //0 上传中 1 上传成功 2 上传失败
val photoUrl : String? = null,
val tag : String? = null,
val imageTitle : String? = null,
val lon : String? = null,
val lat : String? = null,
val sort : Int? = null,
val examplePhotoUrl : String? = null, //示例照片地址
val selectFailReasonList : List<PhotoCheckFailedBean>? = null,
val templatePhotoType : Int = 0, //1 照片 2 工单照片
val takePhotoTime : String? = null,
val takeAddress : String? = null,
val uploadStatus : String? = null,
val uploadState : Int? = 0, //0 上传中 1 上传成功 2 上传失败
) {
//获取拍照时间
fun getPhotoTakeTime(taskState: String, historyTaskBean: HistoryTaskBean?): String? {
if (!takePhotoTime.isNullOrBlank()) {
fun getPhotoTakeTime(taskState : String, historyTaskBean : HistoryTaskBean?) : String? {
if (! takePhotoTime.isNullOrBlank()) {
return takePhotoTime
}
return when (taskState) {
@ -190,8 +196,8 @@ data class HistoryPhotoTemplateItem(
}
}
fun getPhotoLat(taskState: String, historyTaskBean: HistoryTaskBean?): Double? {
if (!lat.isNullOrBlank()) {
fun getPhotoLat(taskState : String, historyTaskBean : HistoryTaskBean?) : Double? {
if (! lat.isNullOrBlank()) {
return lat.toDouble()
}
return when (taskState) {
@ -209,8 +215,8 @@ data class HistoryPhotoTemplateItem(
}
}
fun getPhotoLng(taskState: String, historyTaskBean: HistoryTaskBean?): Double? {
if (!lon.isNullOrBlank()) {
fun getPhotoLng(taskState : String, historyTaskBean : HistoryTaskBean?) : Double? {
if (! lon.isNullOrBlank()) {
return lon.toDouble()
}
return when (taskState) {
@ -228,8 +234,8 @@ data class HistoryPhotoTemplateItem(
}
}
fun getPhotoAddress(taskState: String, historyTaskBean: HistoryTaskBean?): String? {
if (!takeAddress?.replace("[", "")?.replace("]", "").isNullOrBlank()) {
fun getPhotoAddress(taskState : String, historyTaskBean : HistoryTaskBean?) : String? {
if (! takeAddress?.replace("[", "")?.replace("]", "").isNullOrBlank()) {
return takeAddress
}
return when (taskState) {
@ -250,39 +256,42 @@ data class HistoryPhotoTemplateItem(
}
data class TaskSettlementAndTraceBean(
val settleMap: SettleMapBean? = null,
val traceIdAB: Int? = null,
val mileageAB: Int? = null,
val traceABUrl: String? = null,
val traceIdBC: Int? = null,
val mileageBC: Int? = null,
val mileageCA: Int? = null,
val traceBCUrl: String? = null
data class PhotoCheckFailedBean(
val abbr : String? = null, //失败原因简称
val failReason : String? = null, //失败原因详情
)
data class TaskSettlementAndTraceBean(val settleMap : SettleMapBean? = null,
val traceIdAB : Int? = null,
val mileageAB : Int? = null,
val traceABUrl : String? = null,
val traceIdBC : Int? = null,
val mileageBC : Int? = null,
val mileageCA : Int? = null,
val traceBCUrl : String? = null)
data class SettleMapBean(
/*————————————子公司——————————*/
val startPrice: Int? = null, //起步价
val unitPrice: Double? = null, //每公里单价
val mileage: Int? = null, //公里数
val basePrice: Double? = null,//基本费用
val roadFee: Int? = null,//路桥费
val assistFee: Int? = null, //辅助总费用
val startPrice : Int? = null, //起步价
val unitPrice : Double? = null, //每公里单价
val mileage : Int? = null, //公里数
val basePrice : Double? = null, //基本费用
val roadFee : Int? = null, //路桥费
val assistFee : Int? = null, //辅助总费用
/*———————————————供应商———————————————*/ // public Integer startMileage;//出发段公里数
// public Integer carryMileage;//背车段公里数
// public Integer backMileage;//回程段公里数
val startRoadFee: Int? = null, //出发段过境费
val carryRoadFee: Int? = null, //背车段过境费
val backRoadFee: Int? = null, //回程段过境费
val waitFee: Int? = null,//等候费
val wheelFee: Int? = null,//辅助轮费
val wheelNum: Int? = null, //辅助轮个数
val wheelPrice: Int? = null, //辅助轮单价
val dilemmaFee: Int? = null,//困境费
val basementFee: Int? = null, //其他费用
val totalFee: Double? = null,//费用总计
val startRoadFee : Int? = null, //出发段过境费
val carryRoadFee : Int? = null, //背车段过境费
val backRoadFee : Int? = null, //回程段过境费
val waitFee : Int? = null, //等候费
val wheelFee : Int? = null, //辅助轮费
val wheelNum : Int? = null, //辅助轮个数
val wheelPrice : Int? = null, //辅助轮单价
val dilemmaFee : Int? = null, //困境费
val basementFee : Int? = null, //其他费用
val totalFee : Double? = null, //费用总计
)
@ -290,42 +299,40 @@ data class SettleMapBean(
* Created by zhangj on 2019/12/4.
*/
class SettleInfoRequest(
val orderId: Int? = null,
val supplierType: Int? = null,
val startMileage: Int? = null,
val carryMileage: Int? = null,
val backMileage: Int? = null,
val startRoadFee: Int? = null,
val carryRoadFee: Int? = null,
val backRoadFee: Int? = null,
val waitFee: Int? = null,
val settleType: Int? = null,
val wheelFee: Int? = null, //辅助轮费
val wheelNum: Int? = null,
val wheelPrice: Int? = null,
val dilemmaFee: Int? = null, //困境费
val basementFee: Int? = null, //其他费用
val totalFee: Double? = null, //
val startPrice: Int? = null,
val unitPrice: Double? = null,
val mileage: Int? = null,
val basePrice: Double? = null,
val assistFee: Int? = null,
val imgInfo: String? = null,
val imgPath: String? = null,
val orderId : Int? = null,
val supplierType : Int? = null,
val startMileage : Int? = null,
val carryMileage : Int? = null,
val backMileage : Int? = null,
val startRoadFee : Int? = null,
val carryRoadFee : Int? = null,
val backRoadFee : Int? = null,
val waitFee : Int? = null,
val settleType : Int? = null,
val wheelFee : Int? = null, //辅助轮费
val wheelNum : Int? = null,
val wheelPrice : Int? = null,
val dilemmaFee : Int? = null, //困境费
val basementFee : Int? = null, //其他费用
val totalFee : Double? = null, //
val startPrice : Int? = null,
val unitPrice : Double? = null,
val mileage : Int? = null,
val basePrice : Double? = null,
val assistFee : Int? = null,
val imgInfo : String? = null,
val imgPath : String? = null,
)
data class AMapTraceBean(
val counts: Int? = null,
val distance: Double? = null,
val time: Long? = null,
val trid: Int? = null,
val points: List<PointsBean>? = null)
data class AMapTraceBean(val counts : Int? = null,
val distance : Double? = null,
val time : Long? = null,
val trid : Int? = null,
val points : List<PointsBean>? = null)
data class PointsBean(
val accuracy: Double? = null,
val direction: Double? = null,
val height: Double? = null,
val locatetime: Long? = null,
val location: String? = null,
val speed: Double? = null)
data class PointsBean(val accuracy : Double? = null,
val direction : Double? = null,
val height : Double? = null,
val locatetime : Long? = null,
val location : String? = null,
val speed : Double? = null)

View File

@ -75,7 +75,7 @@ data class OrderInfo(
var importantTip : String? = null,
var hasReplaceBatteryCapable : Int? = null, //是否有更换电瓶的能力 1 搭电可以更换电瓶 2搭电不可以更换电瓶 其他的不展示
var taskSuccessStatus : Int? = null, //作业是否完成 0 完成 1未完成 拖车默认完成
var tyreNumber : Int? = null, //辅助费用
var tyreNumber : Int? = null, //小轮个数
) : Parcelable {
constructor(parcel : Parcel) : this(parcel.readValue(Int::class.java.classLoader) as? Int,
parcel.readValue(Int::class.java.classLoader) as? Int,

View File

@ -9,6 +9,7 @@ import com.za.base.Const
import com.za.bean.db.order.OrderInfo
import com.za.room.RoomHelper
import com.za.room.db.user.DriverInfoBean
import com.za.service.location.ZdLocationManager
object GlobalData : GlobalLocalData() {
lateinit var application : Application
@ -94,10 +95,17 @@ object GlobalData : GlobalLocalData() {
var currentLocation : AMapLocation? = null
get() {
return mmkv.decodeParcelable("currentLocation", AMapLocation::class.java)
val location = mmkv.decodeParcelable("currentLocation", AMapLocation::class.java)
if (location != null && (System.currentTimeMillis()
.minus(location.time) < 5 * 60 * 1000)
) {
return location
} else {
ZdLocationManager.init(application)
return null
}
}
set(value) {
value?.time = System.currentTimeMillis()
mmkv.encode("currentLocation", value)
field = value
}

View File

@ -0,0 +1,5 @@
package com.za.common
interface IServiceBridge {
fun giveUpOrder(orderId : String)
}

View File

@ -11,14 +11,13 @@ import com.za.service.location.ZdLocationManager
object ZDManager {
lateinit var application : Application
fun init(application : Application, isRelease : Boolean = false) {
this.application = application
thirdSdkInit(isRelease)
}
private fun thirdSdkInit(isRelease : Boolean = false) {
GlobalData.application = application // 在 Application 中初始化 MMKV所有进程共享同一存储路径
GlobalData.application = application
MMKV.initialize(application)
AppConfig.init(isRelease)
Bugly.init(application, "6972a6b56d", true)

View File

@ -107,6 +107,12 @@ object SpeechManager {
mediaPlayer?.start()
}
// 当前订单被改派
fun playCurrentOrderReDispatch() {
mediaPlayer = MediaPlayer.create(mContext, R.raw.order_redispatch)
mediaPlayer?.start()
}
// 订单被取消
fun playOrderCanceled() {
mediaPlayer = MediaPlayer.create(mContext, R.raw.cancel_order)

View File

@ -485,5 +485,22 @@ object ImageUtil {
vectorDrawable.draw(canvas)
return BitmapDescriptorFactory.fromBitmap(bitmap)
}
fun scaleBitmapWithMatrix(originalBitmap : Bitmap, targetWidth : Int) : Bitmap {
val aspectRatio = originalBitmap.height.toFloat() / originalBitmap.width.toFloat()
val targetHeight = (targetWidth * aspectRatio).toInt()
val matrix = Matrix().apply {
postScale(targetWidth.toFloat() / originalBitmap.width,
targetHeight.toFloat() / originalBitmap.height)
}
return Bitmap.createBitmap(originalBitmap,
0,
0,
originalBitmap.width,
originalBitmap.height,
matrix,
true)
}
}

View File

@ -3,19 +3,28 @@ package com.za.common.util
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.core.net.toUri
import androidx.exifinterface.media.ExifInterface
import com.amap.api.maps.model.LatLng
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.geocoder.GeocodeSearch
import com.amap.api.services.geocoder.RegeocodeQuery
import com.za.common.log.LogUtil
import com.za.ext.toJson
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Locale
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.ln
import kotlin.math.sin
import kotlin.math.sqrt
object MapUtil {
const val PN_GAODE_MAP: String = "com.autonavi.minimap" // 高德地图包名
const val PN_BAIDU_MAP: String = "com.baidu.BaiduMap" // 百度地图包名
const val PN_TENCENT_MAP: String = "com.tencent.map" // 百度地图包名
const val PN_GAODE_MAP : String = "com.autonavi.minimap" // 高德地图包名
const val PN_BAIDU_MAP : String = "com.baidu.BaiduMap" // 百度地图包名
const val PN_TENCENT_MAP : String = "com.tencent.map" // 百度地图包名
/**
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
@ -24,10 +33,13 @@ object MapUtil {
* @param latLng
* @returns
*/
fun gcj02ToBD09(latLng: LatLng): LatLng {
fun gcj02ToBD09(latLng : LatLng) : LatLng {
val xPI = 3.141592653589793 * 3000.0 / 180.0
val z = sqrt(latLng.longitude * latLng.longitude + latLng.latitude * latLng.latitude) + 0.00002 * sin(latLng.latitude * xPI)
val theta = atan2(latLng.latitude, latLng.longitude) + 0.000003 * cos(latLng.longitude * xPI)
val z =
sqrt(latLng.longitude * latLng.longitude + latLng.latitude * latLng.latitude) + 0.00002 * sin(
latLng.latitude * xPI)
val theta =
atan2(latLng.latitude, latLng.longitude) + 0.000003 * cos(latLng.longitude * xPI)
val bdLat = z * sin(theta) + 0.006
val bdLng = z * cos(theta) + 0.0065
return LatLng(bdLat, bdLng)
@ -38,64 +50,137 @@ object MapUtil {
*
* @return
*/
fun isGdMapInstalled(context: Context): Boolean {
fun isGdMapInstalled(context : Context) : Boolean {
return isInstallPackage(context, PN_GAODE_MAP)
}
fun isBaiduMapInstalled(context: Context): Boolean {
fun isBaiduMapInstalled(context : Context) : Boolean {
return isInstallPackage(context, PN_BAIDU_MAP)
}
fun isTencentInstalled(context: Context): Boolean {
fun isTencentInstalled(context : Context) : Boolean {
return isInstallPackage(context, PN_TENCENT_MAP)
}
private fun isInstallPackage(context: Context, packageName: String): Boolean {
private fun isInstallPackage(context : Context, packageName : String) : Boolean {
try {
val info = context.packageManager
.getApplicationInfo(packageName,
val info = context.packageManager.getApplicationInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES)
return true
} catch (e: PackageManager.NameNotFoundException) {
} catch (e : PackageManager.NameNotFoundException) {
return false
}
}
//开启高德导航
fun startNavigationGd(context: Context, lat: Double?, lng: Double?, address: String?) {
val stringBuffer = "androidamap://route?sourceApplication=" + "amap" +
"&dlat=" + lat +
"&dlon=" + lng +
"&dname=" + address +
"&dev=" + 0 +
"&t=" + 0
val intent = Intent("android.intent.action.VIEW", Uri.parse(stringBuffer))
fun startNavigationGd(context : Context, lat : Double?, lng : Double?, address : String?) {
val stringBuffer =
"androidamap://route?sourceApplication=amap&dlat=$lat&dlon=$lng&dname=$address&dev=0&t=0"
val intent = Intent("android.intent.action.VIEW", stringBuffer.toUri())
intent.setPackage("com.autonavi.minimap")
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
//开启高德导航
fun startNavigationBd(context: Context, lat: Double?, lng: Double?, address: String?) {
fun startNavigationBd(context : Context, lat : Double?, lng : Double?, address : String?) {
val i1 = Intent("android.intent.action.VIEW")
i1.setData(Uri.parse("baidumap://map/navi?query=${address}&mode=driving&location=${lat},${lng}&coord_type=gcj02&src=com.za.servicing"))
i1.setData("baidumap://map/navi?query=${address}&mode=driving&location=${lat},${lng}&coord_type=gcj02&src=com.za.servicing".toUri())
context.startActivity(i1)
}
//开启高德导航
fun startNavigationTencent(context: Context, lat: Double?, lng: Double?, address: String?) {
val stringBuffer = "androidamap://route?sourceApplication=" + "amap" +
"&dlat=" + lat +
"&dlon=" + lng +
"&dname=" + address +
"&dev=" + 0 +
"&t=" + 0
val intent = Intent("android.intent.action.VIEW", Uri.parse(stringBuffer))
fun startNavigationTencent(context : Context, lat : Double?, lng : Double?, address : String?) {
val stringBuffer =
"androidamap://route?sourceApplication=amap&dlat=$lat&dlon=$lng&dname=$address&dev=0&t=0"
val intent = Intent("android.intent.action.VIEW", stringBuffer.toUri())
intent.setPackage("com.autonavi.minimap")
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
fun getAddressFromLocation(context : Context, latLng : LatLng?) : String? {
if (latLng == null) {
return null
}
try {
val geocoderSearch = GeocodeSearch(context)
val point = LatLonPoint(latLng.latitude, latLng.longitude)
val query = RegeocodeQuery(point, 200f, GeocodeSearch.AMAP)
return geocoderSearch.getFromLocation(query).formatAddress
} catch (e : Exception) {
LogUtil.print("geoCoderFromPhoto 获取地址异常", e)
return null
}
}
// fun getAddressFromLocation(context : Context, latLng : LatLng?) : String? {
// if (latLng == null) {
// return null
// }
// val geocoder = Geocoder(context, Locale.getDefault())
// try {
// val addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1)
// if (addresses != null && ! addresses.isEmpty()) {
// val address = addresses[0]
// val sb = StringBuilder()
// for (i in 0 .. address.maxAddressLineIndex) {
// sb.append(address.getAddressLine(i))
// if (i < address.maxAddressLineIndex) {
// sb.append(", ")
// }
// }
// val addressStr = sb.toString()
// LogUtil.print("获取照片地址", addressStr)
// return addressStr
// }
// } catch (e : IOException) {
// LogUtil.print("获取照片地址异常", e)
// }
// return null
// }
fun getExifLatLng(localPath : String) : LatLng? {
try {
val exif = ExifInterface(localPath)
val latLong = exif.latLong
if (exif.getLatLong() != null) {
val lat = latLong?.get(0)
val lng = latLong?.get(1)
if (lat == 0.0 || lng == 0.0) {
LogUtil.print("获取照片的经纬度为空", "null1")
return null
}
val latlng = LatLng(lat !!, lng !!)
LogUtil.print("获取照片的经纬度", latlng.toJson().toString())
return latlng
} else {
LogUtil.print("获取照片的经纬度为空", "null2")
}
} catch (e : IOException) {
LogUtil.print("获取照片拍摄时间异常", e)
return null
}
return null
}
fun getPhotoTime(localPath : String) : String? {
try {
val exif = ExifInterface(localPath) // 获取拍摄时间格式通常为YYYY:MM:DD HH:MM:SS
val dateTime = exif.getAttribute(ExifInterface.TAG_DATETIME)
if (dateTime != null) { // 转换时间格式(可选)
val srcFormat = SimpleDateFormat("yyyy:MM:dd HH:mm:ss", Locale.getDefault())
val destFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val date = srcFormat.parse(dateTime)
return destFormat.format(date)
}
} catch (e : IOException) {
LogUtil.print("获取照片拍摄时间异常", e)
}
return null
}
}

View File

@ -25,3 +25,15 @@ fun String?.copy(context : Context) {
clipboardManager.setPrimaryClip(ClipData.newPlainText("", this))
ToastUtils.showLong("复制成功")
}
//截取字符串后六位进行保存
fun String?.getLastSix() : String {
if (this.isNullOrBlank()) {
return ""
}
return if (this.length > 6) {
this.substring(this.length - 6)
} else {
this
}
}

View File

@ -73,12 +73,12 @@ abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
}
is ConnectException -> {
doFailure(Const.NetWorkException, "与服务器断开连接")
doFailure(Const.NetWorkException, "网络异常")
handlerNetError()
}
is UnknownHostException -> {
doFailure(Const.NetWorkException, "与服务器断开连接")
doFailure(Const.NetWorkException, "网络异常")
handlerNetError()
}
@ -89,12 +89,12 @@ abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
}
is TimeoutException -> {
doFailure(Const.NetWorkException, "网络连接超时1")
doFailure(Const.NetWorkException, "网络异常")
LogUtil.print("TimeoutException", e)
}
is SocketTimeoutException -> {
doFailure(Const.NetWorkException, "网络连接超时2")
doFailure(Const.NetWorkException, "网络异常")
LogUtil.print("SocketTimeoutException2", e)
handlerNetError()
}

View File

@ -70,7 +70,7 @@ object CommonMethod {
RetrofitHelper.getDefaultService().uploadImage(body).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer<ImageBean> {
override fun onSubscribe(d : Disposable) {
LogUtil.print("onSubscribe", "onSubscribe")
}
override fun onError(e : Throwable) {
@ -123,6 +123,8 @@ object CommonMethod {
GeneralInfoRequest(vehicleId = vehicleId ?: GlobalData.driverInfoBean?.vehicleId,
driverId = userId ?: GlobalData.driverInfoBean?.userId,
deviceId = DeviceUtil.getAndroidId(ActivityUtils.getTopActivity()))
LogUtil.print("getGenerateInfo", "request=${generalInfoRequest.toJson()}")
RetrofitHelper.getDefaultService().generalInfo(generalInfoRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<DriverInfoBean>() {
@ -173,6 +175,8 @@ object CommonMethod {
carNo = order.carNo,
taskState = order.taskState,
address = order.address,
settleType = order.settleType,
contract = order.contract,
addressProperty = order.addressProperty,
hotline = order.hotline,
expectArriveTime = order.expectArriveTime,
@ -180,6 +184,8 @@ object CommonMethod {
dispatchTime = order.dispatchTime,
lat = order.lat,
lng = order.lng,
isAppoint = order.isAppoint,
appointTime = order.appointTime,
distLat = order.distLat,
distLng = order.distLng,
importantTip = order.importantTip,
@ -213,7 +219,7 @@ object CommonMethod {
return
}
val inServicingOrder = it.find { it.isCurrent == true }
var inServicingOrder = it.find { it.isCurrent == true }
val waitServiceOrders =
it.filter { it.isCurrent == false && it.taskState != "ACCEPT" }
@ -222,6 +228,75 @@ object CommonMethod {
return
}
//如果有离线任务,先走离线任务的逻辑
if (! RoomHelper.db?.offlineTaskDao()
?.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
}
GlobalData.currentOrder = inServicingOrder
it.forEach {
if (RoomHelper.db?.orderDao()
@ -259,6 +334,7 @@ object CommonMethod {
}
fun fetchPhotoTemplate(orderInfo : OrderInfo?,
isNeedUpload : Boolean? = false,
success : () -> Unit = {},
failed : (String?) -> Unit = {}) {
val photoTemplateRequest = PhotoTemplateRequest(orderInfo?.userOrderId)
@ -273,13 +349,16 @@ object CommonMethod {
return
}
if (isNeedUpload == false) {
val listData = RoomHelper.db?.photoTemplateDao()
?.queryCurrentOrderHasTaskNode(orderInfo?.userOrderId ?: 0)
if (! listData.isNullOrEmpty()) {
LogUtil.print("queryPhotoTemplate", "模板已经存在==${listData.toJson()}")
LogUtil.print("queryPhotoTemplate",
"模板已经存在==${listData.toJson()}")
success()
return
}
}
it.forEachIndexed { _, item ->
val photoTemplateInfo = item.copy(userOrderId = orderInfo?.userOrderId,

View File

@ -5,6 +5,7 @@ import android.provider.Settings
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import com.alibaba.fastjson.JSONObject
import com.amap.api.maps.model.LatLng
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.geocoder.GeocodeResult
import com.amap.api.services.geocoder.GeocodeSearch
@ -20,6 +21,7 @@ import com.za.bean.request.UpdateTaskBean
import com.za.bean.request.UpdateTaskRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.util.MapUtil
import com.za.ext.toJson
import com.za.net.BaseObserver
import com.za.net.CommonMethod
@ -32,6 +34,7 @@ import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.File
import java.util.concurrent.TimeUnit
interface IOfflineListener {
fun start()
@ -42,6 +45,7 @@ interface IOfflineListener {
}
object OfflineManager {
private const val TAG = "离线任务"
private var isUploading = false
private var uploadDispose : Disposable? = null
private var offlineListener : IOfflineListener? = null
@ -56,11 +60,14 @@ object OfflineManager {
if (checkOfflineIsComplete(taskId)) {
return
}
if (currentTaskId != null && taskId == currentTaskId && isUploading) {
LogUtil.print(TAG, "当前任务正在上传中")
return
}
if (! Settings.canDrawOverlays(GlobalData.application)) {
LogUtil.print(TAG, "开始失败:悬浮窗权限未开启")
openSystemAlertPermissionDialog()
return
}
@ -68,13 +75,13 @@ object OfflineManager {
stop()
OfflineService.addListener()
offlineListener?.start()
uploadDispose = Observable.interval(0, 5, java.util.concurrent.TimeUnit.SECONDS)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe {
uploadDispose = Observable.interval(0, 5, TimeUnit.SECONDS).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).subscribe {
if (! isUploading) {
val list =
RoomHelper.db?.offlineTaskDao()?.getOfflineTaskFromTaskId(taskId ?: 0)
if (list.isNullOrEmpty()) {
LogUtil.print("离线任务", "离线任务为空!!")
LogUtil.print(TAG, "离线任务为空!!")
stop()
ToastUtils.showLong("离线任务上传完成")
return@subscribe
@ -117,6 +124,7 @@ object OfflineManager {
private fun uploadTask(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
isUploading = true
LogUtil.print(TAG, "开始 uploadTask=${offlineUpdateTaskBean.toJson()}")
val updateTaskRequest = UpdateTaskRequest(type = offlineUpdateTaskBean.type,
taskId = offlineUpdateTaskBean.taskId,
userId = offlineUpdateTaskBean.userId,
@ -139,25 +147,24 @@ object OfflineManager {
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务", "success=$it request=${updateTaskRequest.toJson()}")
LogUtil.print(TAG, "uploadTask 完成")
}
override fun doFailure(code : Int, msg : String?) {
isUploading = false
offlineListener?.uploadFailure(msg)
LogUtil.print("离线任务",
"uploadTask failed==${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadTask 失败 $code $msg")
}
})
}
private fun uploadOrderImage(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
isUploading = true
LogUtil.print(TAG, "开始 uploadOrderImage=${offlineUpdateTaskBean.toJson()}")
var file = File(offlineUpdateTaskBean.photoLocalWaterMarkerPath ?: "")
if (! file.exists()) {
offlineListener?.uploadFailure("图片未找到!")
LogUtil.print("离线任务 uploadOrderImage",
"uploadTask failed==${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadOrderImage 失败,图片未找到")
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
@ -165,31 +172,33 @@ object OfflineManager {
}
if (offlineUpdateTaskBean.imageAddress.isNullOrBlank() && (offlineUpdateTaskBean.imageLat != null && offlineUpdateTaskBean.imageLat != 0f && offlineUpdateTaskBean.imageLng != null && offlineUpdateTaskBean.imageLng != 0f)) {
geoCoder(offlineUpdateTaskBean.imageLat.toDouble(),
offlineUpdateTaskBean.imageLng.toDouble(),
success = { it ->
val address = MapUtil.getAddressFromLocation(context = ActivityUtils.getTopActivity(),
latLng = LatLng(offlineUpdateTaskBean.imageLat.toDouble(),
offlineUpdateTaskBean.imageLng.toDouble()))
val photoMarkerInfo = PhotoMarkerInfo(offlineUpdateTaskBean.needWater,
needShowPhoneBrand = offlineUpdateTaskBean.needPhoneBrand,
path = offlineUpdateTaskBean.photoLocalWaterMarkerPath,
from = "(离线)",
lat = offlineUpdateTaskBean.imageLat.toDouble(),
lng = offlineUpdateTaskBean.imageLng.toDouble(),
address = it,
address = address,
time = offlineUpdateTaskBean.time,
driverName = GlobalData.driverInfoBean?.userName,
taskCode = offlineUpdateTaskBean.taskCode)
val offlineTemp = offlineUpdateTaskBean.copy(imageAddress = it)
val offlineTemp = offlineUpdateTaskBean.copy(imageAddress = address)
file = File(PhotoMarkerManager.addPhotoMarker(ActivityUtils.getTopActivity(),
photoMarkerInfo))
CommonMethod.uploadImage(file = file, success = {
val item = RoomHelper.db?.offlineTaskDao()
?.getRecentOfflineTask(offlineTemp.taskId ?: 0)?.get(0)
val item =
RoomHelper.db?.offlineTaskDao()?.getRecentOfflineTask(offlineTemp.taskId ?: 0)
?.get(0)
if (item == null) {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "离线图片要出插入的节点 未找到")
return@uploadImage
}
LogUtil.print("离线任务 getRecentOfflineTask", "success=${item.toJson()}")
LogUtil.print(TAG, "离线图片要出插入的节点 =${item.toJson()}")
val list = item.templatePhotoInfoList?.toMutableList()
val jsonObject = JSONObject()
jsonObject["realTakePhotoTime"] = offlineTemp.realTakePhotoTime ?: ""
@ -197,26 +206,21 @@ object OfflineManager {
jsonObject["path"] = it
jsonObject["time"] = offlineTemp.time
jsonObject["lat"] = offlineTemp.imageLat
jsonObject["sort"] = offlineTemp.sort
jsonObject["lng"] = offlineTemp.imageLng
jsonObject["address"] = offlineTemp.imageAddress
list?.set(offlineTemp.imageIndex ?: 0, jsonObject.toJSONString())
val temp = item.copy(templatePhotoInfoList = list?.toList())
RoomHelper.db?.offlineTaskDao()?.update(temp)
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineTemp.primaryId ?: 0)
RoomHelper.db?.offlineTaskDao()?.deleteOfflineTaskFromId(offlineTemp.primaryId ?: 0)
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务 逆地理 uploadOrderImage",
"success=$it request=${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "离线 uploadOrderImage 成功")
}, failed = {
RoomHelper.db?.offlineTaskDao()?.update(offlineTemp)
offlineListener?.uploadFailure(it)
isUploading = false
})
},
failed = {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "uploadOrderImage 失败$it")
})
} else {
CommonMethod.uploadImage(file = file, success = {
@ -225,14 +229,16 @@ object OfflineManager {
if (item == null) {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "离线图片要出插入的节点 未找到")
return@uploadImage
}
LogUtil.print("离线任务 getRecentOfflineTask", "success=${item.toJson()}")
LogUtil.print(TAG, "离线图片要出插入的节点 =${item.toJson()}")
val list = item.templatePhotoInfoList?.toMutableList()
val jsonObject = JSONObject()
jsonObject["realTakePhotoTime"] = offlineUpdateTaskBean.realTakePhotoTime ?: ""
jsonObject["photoSource"] = offlineUpdateTaskBean.photoSource
jsonObject["path"] = it
jsonObject["sort"] = offlineUpdateTaskBean.sort
jsonObject["time"] = offlineUpdateTaskBean.time
jsonObject["lat"] = offlineUpdateTaskBean.imageLat
jsonObject["lng"] = offlineUpdateTaskBean.imageLng
@ -245,22 +251,22 @@ object OfflineManager {
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务 uploadOrderImage",
"success=$it request=${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "离线 uploadOrderImage 成功")
}, failed = {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "uploadOrderImage 图片上传失败$it")
})
}
}
private fun uploadEleDamageImage(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
isUploading = true
LogUtil.print(TAG, "开始 uploadEleDamageImage${offlineUpdateTaskBean.toJson()}")
val file = File(offlineUpdateTaskBean.imageLocalPath ?: "")
if (! file.exists()) {
offlineListener?.uploadFailure("图片未找到!")
LogUtil.print("离线任务 uploadEleDamageImage",
"failed==${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadEleDamageImage 图片未找到")
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
@ -274,7 +280,7 @@ object OfflineManager {
isUploading = false
return@uploadImage
}
LogUtil.print("离线任务 getRecentOfflineEle", "success=${item.toJson()}")
LogUtil.print(TAG, "最近的节点${item.toJson()}")
val list = item.damageFileList?.toMutableList()
list?.set(offlineUpdateTaskBean.imageIndex ?: 0, it)
val temp = item.copy(templatePhotoInfoList = list?.toList())
@ -284,15 +290,16 @@ object OfflineManager {
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务 uploadEleDamageImage",
"success=$it request=${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadEleDamageImage 成功")
}, failed = {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "uploadEleDamageImage 失败$it")
})
}
private fun uploadEleWorkOrder(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
LogUtil.print(TAG, "开始 uploadEleWorkOrder ${offlineUpdateTaskBean.toJson()}")
val saveEleOrderRequest = SaveEleOrderRequest(state = offlineUpdateTaskBean.eleState,
userOrderId = offlineUpdateTaskBean.userOrderId,
taskOrderId = offlineUpdateTaskBean.taskId,
@ -308,7 +315,7 @@ object OfflineManager {
lng = offlineUpdateTaskBean.eleLng,
tyreNumber = offlineUpdateTaskBean.tyreNumber,
isFinish = offlineUpdateTaskBean.isFinish)
LogUtil.print("离线数据 eleSign_check request", saveEleOrderRequest.toJson() ?: "")
LogUtil.print(TAG, "uploadEleWorkOrder request=${saveEleOrderRequest.toJson()}")
RetrofitHelper.getDefaultService().saveElectronOrder(saveEleOrderRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<String>() {
@ -317,27 +324,27 @@ object OfflineManager {
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务 uploadEleWorkOrder",
"success=$it request=${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadEleWorkOrder 成功")
}
override fun doFailure(code : Int, msg : String?) {
offlineListener?.uploadFailure(msg)
isUploading = false
LogUtil.print(TAG, "uploadEleWorkOrder 失败$code $msg")
}
})
}
private fun uploadCustomerSignImage(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
isUploading = true
LogUtil.print(TAG, "开始 uploadCustomerSignImage${offlineUpdateTaskBean.toJson()}")
val file = File(offlineUpdateTaskBean.imageLocalPath ?: "")
if (! file.exists()) {
offlineListener?.uploadFailure("图片未找到!")
LogUtil.print("离线任务 uploadCustomerSignImage",
"failed==${offlineUpdateTaskBean.toJson()}")
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
LogUtil.print(TAG, "uploadCustomerSignImage 图片未找到")
return
}
CommonMethod.uploadImage(file = file, success = { it ->
@ -348,8 +355,7 @@ object OfflineManager {
isUploading = false
return@uploadImage
}
LogUtil.print("离线任务 uploadCustomerSignImage getRecentOfflineEle",
"success=${item.toJson()}")
LogUtil.print(TAG, "uploadCustomerSignImage 要插入的接单=${item.toJson()}")
RoomHelper.db?.offlineTaskDao()?.update(item.copy(customerSignPath = it))
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
@ -359,21 +365,21 @@ object OfflineManager {
}
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务 uploadCustomerSignImage",
"success=$it request=${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadCustomerSignImage 成功")
}, failed = {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "uploadCustomerSignImage 失败$it")
})
}
private fun uploadAcceptPeopleSignImage(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
isUploading = true
LogUtil.print(TAG, "开始 uploadAcceptPeopleSignImage ${offlineUpdateTaskBean.toJson()}")
val file = File(offlineUpdateTaskBean.imageLocalPath ?: "")
if (! file.exists()) {
offlineListener?.uploadFailure("图片未找到!")
LogUtil.print("离线任务 uploadCustomerSignImage",
"failed==${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadAcceptPeopleSignImage 图片未找到")
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
@ -387,8 +393,7 @@ object OfflineManager {
isUploading = false
return@uploadImage
}
LogUtil.print("离线任务 uploadAcceptPeopleSignImage getRecentOfflineEle",
"success=${item.toJson()}")
LogUtil.print(TAG, "uploadAcceptPeopleSignImage 要插入的接单=${item.toJson()}")
RoomHelper.db?.offlineTaskDao()?.update(item.copy(recipientSignPath = it))
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
@ -398,24 +403,24 @@ object OfflineManager {
}
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务 uploadAcceptPeopleSignImage",
"success=$it request=${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadAcceptPeopleSignImage 成功")
}, failed = {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "uploadAcceptPeopleSignImage 逆地理失败")
})
}
private fun uploadServicePeopleSignImage(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
isUploading = true
LogUtil.print(TAG, "开始 uploadServicePeopleSignImage${offlineUpdateTaskBean.toJson()}")
val file = File(offlineUpdateTaskBean.imageLocalPath ?: "")
if (! file.exists()) {
offlineListener?.uploadFailure("图片未找到!")
LogUtil.print("离线任务 uploadCustomerSignImage",
"failed==${offlineUpdateTaskBean.toJson()}")
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
LogUtil.print(TAG, "uploadServicePeopleSignImage 图片未找到")
return
}
CommonMethod.uploadImage(file = file, success = { it ->
@ -426,8 +431,7 @@ object OfflineManager {
isUploading = false
return@uploadImage
}
LogUtil.print("离线任务 uploadCustomerSignImage getRecentOfflineEle",
"success=${item.toJson()}")
LogUtil.print(TAG, "uploadServicePeopleSignImage 要插入的接单=${item.toJson()}")
RoomHelper.db?.offlineTaskDao()?.update(item.copy(waitstaffSignPath = it))
RoomHelper.db?.offlineTaskDao()
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
@ -438,22 +442,24 @@ object OfflineManager {
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务 uploadCustomerSignImage",
"success=$it request=${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "uploadServicePeopleSignImage 成功")
}, failed = {
offlineListener?.uploadFailure(it)
isUploading = false
LogUtil.print(TAG, "uploadAcceptPeopleSignImage 失败$it")
})
}
private fun taskFinish(offlineUpdateTaskBean : OfflineUpdateTaskBean) {
isUploading = true
LogUtil.print(TAG, "开始 taskFinish ${offlineUpdateTaskBean.toJson()}")
val taskFinishRequest = TaskFinishRequest(
operateTime = offlineUpdateTaskBean.operateTime?.toLong(),
lat = offlineUpdateTaskBean.updateTaskLat,
userOrderId = offlineUpdateTaskBean.userOrderId,
lng = offlineUpdateTaskBean.updateTaskLng,
)
LogUtil.print(TAG, "taskFinish request ${taskFinishRequest.toJson()}")
RetrofitHelper.getDefaultService().taskFinish(taskFinishRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<TaskFinishResponse>() {
@ -462,14 +468,13 @@ object OfflineManager {
?.deleteOfflineTaskFromId(offlineUpdateTaskBean.primaryId ?: 0)
isUploading = false
offlineListener?.uploadSuccess()
LogUtil.print("离线任务", "success=$it request=${taskFinishRequest.toJson()}")
LogUtil.print(TAG, "taskFinish 成功")
}
override fun doFailure(code : Int, msg : String?) {
isUploading = false
offlineListener?.uploadFailure(msg)
LogUtil.print("离线任务",
"uploadTask failed==${offlineUpdateTaskBean.toJson()}")
LogUtil.print(TAG, "taskFinish 失败 $code $msg")
}
})
}
@ -505,7 +510,7 @@ private fun geoCoder(lat : Double,
regeocodeResult.regeocodeAddress.formatAddress)
} else {
failed("地址获取失败")
LogUtil.print("singleLocation 逆地理失败 ", regeocodeResult.toString())
LogUtil.print("离线任务 逆地理失败 ", regeocodeResult.toString())
}
}

View File

@ -12,12 +12,13 @@ import android.os.Looper
import androidx.core.app.NotificationCompat
import cn.jiguang.api.utils.JCollectionAuth
import cn.jpush.android.api.JPushInterface
import com.blankj.utilcode.util.ProcessUtils
import com.google.gson.Gson
import com.za.base.Const
import com.za.bean.JpushBean
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.util.DeviceUtil
import com.za.ext.toJson
import com.za.service.mqtt.MyMqttClient
import com.za.servicing.R
@ -25,6 +26,7 @@ interface PushListener {
fun newOrderMsg(jpushBean : JpushBean)
fun giveUpOrder(jpushBean : JpushBean)
fun revokeOrder(jpushBean : JpushBean)
fun modifyOrder(jpushBean : JpushBean)
fun reDispatchOrder(jpushBean : JpushBean)
fun broadcast(string : String)
fun importantTip(jpushBean : JpushBean)
@ -38,15 +40,30 @@ object ServiceManager {
private var lastJPushBean : LastJPushBean? = null
private const val DUPLICATE_MSG_THRESHOLD = 3000L // 3秒
private const val TAG = "ServiceManager"
// Initialize SharedPreferences
fun initialize(context : Context) {
LogUtil.print("ServiceManager", "Initializing ServiceManager")
LogUtil.print(TAG, "Initializing ServiceManager")
jpushRegister(context)
MyMqttClient.initialize(deviceId = DeviceUtil.getAndroidId(context))
setupPushMessageReceiver(context)
}
fun sendMessageToMainProcess(context : Context,
type : String,
message : String) { // 使用广播将消息发送到主进程
val intent = Intent(Const.PushMessageType.ACTION_MAIN.takeIf { GlobalData.isMaster }
?: Const.PushMessageType.ACTION_SDK)
intent.setPackage(context.packageName)
intent.putExtra("type", type)
intent.putExtra("message", message)
context.sendBroadcast(intent)
LogUtil.print(TAG, "发送消息到主进程: $type")
}
private fun setupPushMessageReceiver(context : Context) { // 注册推送消息接收器
registerPushListener(object : PushListener {
override fun broadcast(msg : String) {
@ -74,30 +91,25 @@ object ServiceManager {
override fun revokeOrder(jpushBean : JpushBean) {
sendMessageToMainProcess(context = context, "revoke", Gson().toJson(jpushBean))
}
override fun modifyOrder(jpushBean : JpushBean) {
sendMessageToMainProcess(context = context, "modify", Gson().toJson(jpushBean))
}
})
}
private fun sendMessageToMainProcess(context : Context,
type : String,
message : String) { // 使用广播将消息发送到主进程
val intent = Intent("com.za.rescue.dealer.PUSH_MESSAGE".takeIf { GlobalData.isMaster }
?: ZdPushServiceReceive.RECEIVE_ACTION)
intent.setPackage(context.packageName)
intent.putExtra("type", type)
intent.putExtra("message", message)
context.sendBroadcast(intent)
LogUtil.print("KeepAliveService", "发送消息到主进程: $type")
}
// Register JPush
private fun jpushRegister(context : Context) {
try {
JCollectionAuth.setAuth(context, true)
JPushInterface.setDebugMode(false)
JCollectionAuth.setAuth(context, true)
JPushInterface.init(context)
LogUtil.print("ServiceManager", "JPush initialized successfully")
JCollectionAuth.setAuth(context, true)
JCollectionAuth.enableAutoWakeup(context, true)
LogUtil.print(TAG, "JPush initialized successfully")
} catch (e : Exception) {
LogUtil.print("ServiceManager", "JPush initialization failed: ${e.message}")
LogUtil.print(TAG, "JPush initialization failed: ${e.message}")
}
}
@ -105,18 +117,16 @@ object ServiceManager {
fun registerPushListener(listener : PushListener) {
Handler(Looper.getMainLooper()).post {
this.pushListener = listener
LogUtil.print("ServiceManager", "Registered push listener: ${this.pushListener}")
LogUtil.print(TAG, "registerPushListener")
}
}
// Handle incoming push messages
fun handlerPushMsg(msg : String) {
LogUtil.print("handlerPushMsg", "Received push message: $msg")
// 优化后的重复消息判断
LogUtil.print(TAG, "handlerPushMsg Received push message: $msg") // 优化后的重复消息判断
lastJPushBean?.let {
if (System.currentTimeMillis() - it.time < DUPLICATE_MSG_THRESHOLD && it.msg == msg) {
LogUtil.print("MessageHandler", "Duplicate message detected (hash: ${msg})")
LogUtil.print(TAG, "handlerPushMsg Duplicate message detected (hash: ${msg})")
return
}
}
@ -133,6 +143,7 @@ object ServiceManager {
when (jpushOrderInfoBean.pushType) {
0 -> newOrderMsg(jpushOrderInfoBean)
1 -> handleTypeOneMessage(jpushOrderInfoBean)
2 -> handlerModifyOrderMessage(jpushOrderInfoBean)
3 -> importantTip(jpushOrderInfoBean)
else -> LogUtil.print("JpushMessage",
"Unknown push type: ${jpushOrderInfoBean.pushType}")
@ -141,7 +152,7 @@ object ServiceManager {
if (msg.startsWith("broadcast:")) {
handleBroadcast(msg)
}
LogUtil.print("JpushMessage", "Error handling message: ${e.message}")
LogUtil.print(TAG, "handlerPushMsg Error handling message: ${e.message}")
}
}
@ -151,9 +162,9 @@ object ServiceManager {
val content = msg.substring(10)
pushListener?.broadcast(content)
sendNotification(GlobalData.application, content)
LogUtil.print("JpushMessage", "Broadcast content: $content")
LogUtil.print(TAG, "handleBroadcast Broadcast content: $content")
} catch (e : Exception) {
LogUtil.print("JpushMessage", "Broadcast failed: ${e.message}")
LogUtil.print(TAG, "handleBroadcast Broadcast failed: ${e.message}")
}
}
@ -167,15 +178,23 @@ object ServiceManager {
}
}
private fun handlerModifyOrderMessage(jpushOrderBean : JpushBean) {
try {
LogUtil.print(TAG, "handlerModifyOrderMessage ${jpushOrderBean.toJson()}")
this.pushListener?.modifyOrder(jpushOrderBean)
} catch (e : Exception) {
LogUtil.print(TAG,
"handlerModifyOrderMessage Failed to handle new order message: ${e.message}")
}
}
// Handle new order messages
private fun newOrderMsg(jpushOrderBean : JpushBean) {
try {
LogUtil.print("JpushMessage",
"Handling new order message: ${this.pushListener} ${this.pushListener?.javaClass?.simpleName}")
LogUtil.print("isManThread", " ${ProcessUtils.getCurrentProcessName()}")
LogUtil.print(TAG, "newOrderMsg ${jpushOrderBean.toJson()}")
this.pushListener?.newOrderMsg(jpushOrderBean)
} catch (e : Exception) {
LogUtil.print("JpushMessage", "Failed to handle new order message: ${e.message}")
LogUtil.print(TAG, "newOrderMsg Failed to handle new order message: ${e.message}")
}
}
@ -205,9 +224,9 @@ object ServiceManager {
try {
JPushInterface.stopPush(context) // Stop JPush
MyMqttClient.disconnect() // Disconnect MQTT
LogUtil.print("ServiceManager", "Disconnected from JPush and MQTT successfully")
LogUtil.print(TAG, "disconnect")
} catch (e : Exception) {
LogUtil.print("ServiceManager", "Error during disconnection: ${e.message}")
LogUtil.print(TAG, "disconnect Failed ${e.message}")
}
}
}

View File

@ -17,6 +17,7 @@ import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.AppUtils
import com.google.gson.Gson
import com.za.base.BaseActivityLifecycleCallbacks
import com.za.base.Const
import com.za.bean.JpushBean
import com.za.common.GlobalData
import com.za.common.log.LogUtil
@ -27,7 +28,6 @@ import com.za.ui.view.CommonDialogFragment
class ZdPushServiceReceive : BroadcastReceiver() {
companion object {
const val RECEIVE_ACTION = "com.zd.servicing.PUSH_MESSAGE"
private const val GIVE_UP_TYPE_NORMAL = 1
private const val DIALOG_TAG_GIVE_UP = "giveUp"
}
@ -35,7 +35,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
private fun handlerMessage(context : Context?, intent : Intent?) {
val activity = context ?: ActivityUtils.getTopActivity()
activity as? AppCompatActivity
if (intent?.action == RECEIVE_ACTION) {
if (intent?.action == Const.PushMessageType.ACTION_SDK) {
val type = intent.getStringExtra("type") ?: return
val message = intent.getStringExtra("message") ?: return
if (ActivityUtils.getTopActivity() == null) {
@ -43,9 +43,9 @@ class ZdPushServiceReceive : BroadcastReceiver() {
}
LogUtil.print("PushActivityLifecycleCallbacks", "收到来自远程进程的消息: $type")
when (type) {
"broadcast" -> handleBroadcast("broadcast:$message")
Const.PushMessageType.BROADCAST -> handleBroadcast("broadcast:$message")
"giveUp" -> {
Const.PushMessageType.GIVE_UP -> {
try {
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
@ -57,8 +57,9 @@ class ZdPushServiceReceive : BroadcastReceiver() {
LogUtil.print("PushActivityLifecycleCallbacks",
"处理订单放弃消息失败: ${e.message}")
}
} // 处理其他类型的消息...
"importantTip" -> {
}
Const.PushMessageType.IMPORTANT_TIP -> {
try {
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
@ -72,7 +73,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
}
}
"reDispatch" -> {
Const.PushMessageType.RE_DISPATCH -> {
try {
val jpushBean = Gson().fromJson(message, JpushBean::class.java)
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
@ -86,7 +87,20 @@ class ZdPushServiceReceive : BroadcastReceiver() {
}
}
"revoke" -> {
Const.PushMessageType.MODIFY -> {
try {
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
?: ActivityUtils.getTopActivity()
if (activity is AppCompatActivity) {
handlerModifyOrder()
}
} catch (e : Exception) {
LogUtil.print("PushActivityLifecycleCallbacks",
"处理重要提示消息失败: ${e.message}")
}
}
Const.PushMessageType.REVOKE -> {
try {
val activity = BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()
?: ActivityUtils.getTopActivity()
@ -134,7 +148,7 @@ class ZdPushServiceReceive : BroadcastReceiver() {
private fun handleReDispatchOrder(activity : Activity, jpushBean : JpushBean) {
playNotificationSound(activity)
BaseActivityLifecycleCallbacks.Companion.getCurrentActivity()?.let { currentActivity ->
BaseActivityLifecycleCallbacks.getCurrentActivity()?.let { currentActivity ->
if (currentActivity is AppCompatActivity) {
AlertDialog.Builder(currentActivity).setTitle("订单重新派发")
.setMessage(buildReDispatchMessage(jpushBean)).setCancelable(false)
@ -154,6 +168,21 @@ class ZdPushServiceReceive : BroadcastReceiver() {
.show()
}
private fun handlerModifyOrder() {
SpeechManager.speech("订单信息被修改")
BaseActivityLifecycleCallbacks.getCurrentActivity()?.let { currentActivity ->
if (currentActivity is AppCompatActivity) {
AlertDialog.Builder(currentActivity).setTitle("订单重新派发")
.setMessage("订单信息被修改,请返回首页更新订单信息!")
.setPositiveButton("确定") { dialog, _ ->
dialog.dismiss()
currentActivity.finish()
}.show()
}
}
}
// Handle broadcast messages
private fun handleBroadcast(msg : String) {
try {

View File

@ -25,11 +25,6 @@ import com.za.common.log.LogUtil
import com.za.ext.toJson
import com.za.net.CommonMethod
import com.za.service.mqtt.MyMqttClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.Locale
import kotlin.math.abs
import kotlin.math.cos
@ -44,42 +39,11 @@ object ZdLocationManager : AMapLocationListener {
private var option : AMapLocationClientOption? = null
private const val NORMA_INTERVAL_TIME = 20000L // GPS上传时间间隔
private const val LOCATION_GET_DURATION = 5 * 1000L
private const val LOCATION_CACHE_DURATION = 60 * 1000L // 1分钟的缓存时间
private const val LOCATION_GET_DURATION = 10 * 1000L
private const val LOCATION_SEARCH_RADIUS = 200f
private const val DEFAULT_TIMEOUT = 30000L
private var globalLocation : AMapLocation? = null
private var lastSingleLocationTime = 0L
private var locationUploadJob : Job? = null
private fun startUploadLocationJob() {
stopUploadLocationJob()
locationUploadJob = CoroutineScope(Dispatchers.IO).launch {
while (true) {
delay(NORMA_INTERVAL_TIME)
if (GlobalData.currentLocation == null) {
LogUtil.print(TAG, "定位上传失败: location is null")
continue
}
if (System.currentTimeMillis() - (GlobalData.currentLocation?.time
?: System.currentTimeMillis()) > 1000 * 60 * 2
) {
LogUtil.print(TAG, "定位上传失败: location is old")
continue
}
uploadGpsRequest(GlobalData.currentLocation !!)
}
}
}
private fun stopUploadLocationJob() {
locationUploadJob?.cancel()
locationUploadJob = null
}
var lastSingleLocationTime = System.currentTimeMillis()
fun init(context : Context) {
this.context = context.applicationContext
@ -103,16 +67,17 @@ object ZdLocationManager : AMapLocationListener {
}
private fun createLocationOption(isOnceLocation : Boolean = false,
isGpsFirst : Boolean = false,
isNeedAddress : Boolean = false) : AMapLocationClientOption =
isGpsFirst : Boolean = false) : AMapLocationClientOption =
AMapLocationClientOption().apply {
locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
interval = LOCATION_GET_DURATION
isWifiScan = true
isLocationCacheEnable = false
httpTimeOut = DEFAULT_TIMEOUT
isMockEnable = false
this.isNeedAddress = isNeedAddress
this.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
this.interval = NORMA_INTERVAL_TIME
this.isWifiScan = true
this.httpTimeOut = DEFAULT_TIMEOUT
this.isLocationCacheEnable = false
this.httpTimeOut = 6000
this.gpsFirstTimeout = 6000
this.isMockEnable = false
this.isNeedAddress = false
this.isOnceLocation = isOnceLocation
this.isGpsFirst = isGpsFirst
}
@ -124,7 +89,6 @@ object ZdLocationManager : AMapLocationListener {
}
try {
aMapLocationClient?.startLocation()
startUploadLocationJob()
LogUtil.print(TAG, "持续定位开启成功")
} catch (e : Exception) {
LogUtil.print(TAG, "持续定位开启失败: ${e.message}")
@ -137,7 +101,6 @@ object ZdLocationManager : AMapLocationListener {
aMapLocationClient?.onDestroy()
aMapLocationClient?.unRegisterLocationListener(this)
aMapLocationClient = null
stopUploadLocationJob()
LogUtil.print(TAG, "关闭持续定位成功")
} catch (e : Exception) {
LogUtil.print(TAG, "关闭持续定位失败: ${e.message}")
@ -149,13 +112,13 @@ object ZdLocationManager : AMapLocationListener {
LogUtil.print(TAG, "定位获取失败: location is null")
return
}
if (location.errorCode != 0) {
LogUtil.print(TAG, "定位获取失败: ${location.errorInfo}")
return
}
GlobalData.currentLocation = location
lastSingleLocationTime = System.currentTimeMillis()
uploadGpsRequest(location)
LogUtil.print(TAG,
"定位获取成功: lat=${location.latitude} lng=${location.longitude} time=${location.time} speed=${location.speed} ") // uploadGpsRequest(location)
}
@ -181,132 +144,151 @@ object ZdLocationManager : AMapLocationListener {
}
CommonMethod.uploadGps(uploadGpsRequest, success = {
LogUtil.print(TAG, "定位上传成功: ${uploadGpsRequest.toJson()}")
MyMqttClient.publishMessage() // if (ActivityUtils.getTopActivity()==null) {
// AppUtils.launchApp(AppUtils.getAppPackageName())
// }
MyMqttClient.publishMessage()
}, failed = { error ->
LogUtil.print(TAG, "定位上传失败: $error $uploadGpsRequest")
MyMqttClient.publishMessage()
})
}
fun getSingleLocation(success : (AMapLocation) -> Unit,
failed : (String) -> Unit,
isNeedAddress : Boolean = false) {
globalLocation?.let { location ->
if (System.currentTimeMillis() - lastSingleLocationTime < LOCATION_CACHE_DURATION && (! isNeedAddress || ! location.address.isNullOrBlank())) {
LogUtil.print(TAG, "返回缓存位置")
success(location)
GlobalData.currentLocation = location
isNeedAddress : Boolean? = false) {
NetworkUtils.isAvailableByDnsAsync {
LogUtil.print(TAG, "getSingleLocation isAvailableByDnsAsync=$it")
if (it) {
LogUtil.print(TAG, "is NeedAddress=$isNeedAddress")
doGetSingleLocation(isNeedAddress = isNeedAddress, success = {
success(it)
}, failed = { failed(it) })
return@isAvailableByDnsAsync
}
doGetSingleLocationGps(success = {
success(it)
}, failed = { failed(it) }, isNeedAddress = isNeedAddress)
}
}
fun doGetSingleLocation(success : (AMapLocation) -> Unit,
failed : (String) -> Unit,
isNeedAddress : Boolean? = false) {
LogUtil.print(TAG, "doGetSingleLocation")
if (GlobalData.currentLocation != null && (System.currentTimeMillis()
.minus(GlobalData.currentLocation?.time ?: 0) < 60 * 1000)
) {
if (isNeedAddress == false) {
success(GlobalData.currentLocation !!)
return
}
}
NetworkUtils.isAvailableAsync { isNetworkAvailable ->
LogUtil.print(TAG, "网络状态: $isNetworkAvailable")
if (isNetworkAvailable) {
doGetSingleLocationOnline(isNeedAddress = isNeedAddress,
success = success,
failed = failed)
val option = if (isNeedAddress == true) {
AMapLocationClientOption().apply {
this.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
this.isNeedAddress = true
this.isWifiScan = true
this.isLocationCacheEnable = true
this.httpTimeOut = 5000
this.isMockEnable = false
this.isOnceLocation = true
}
} else {
doGetSingleLocationGpsFromOriginal(success,
failed) // doGetSingleLocationGps(success, failed)
}
AMapLocationClientOption().apply {
this.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
this.isNeedAddress = false
this.isWifiScan = true
this.isLocationCacheEnable = true
this.httpTimeOut = 5000
this.isMockEnable = false
this.isOnceLocation = true
}
}
private fun createSingleLocationClient(isNeedAddress : Boolean,
isGpsFirst : Boolean,
locationCallback : (AMapLocation?) -> Unit) : AMapLocationClient? {
return context?.let { ctx ->
try {
AMapLocationClient(ctx).apply {
setLocationOption(createLocationOption(isOnceLocation = true,
isGpsFirst = isGpsFirst,
isNeedAddress = isNeedAddress))
setLocationListener { location ->
locationCallback(location)
stopLocation()
onDestroy()
}
}
} catch (e : Exception) {
LogUtil.print(TAG, "创建单次定位客户端失败: ${e.message}")
null
}
}
}
AMapLocationClient.updatePrivacyShow(context, true, true)
AMapLocationClient.updatePrivacyAgree(context, true)
val aMapLocationClient = AMapLocationClient(context)
aMapLocationClient.setLocationOption(option)
aMapLocationClient.setLocationListener {
if (it != null && it.errorCode == 0) {
LogUtil.print("单次定位结果", "$it")
private fun handleLocationResult(location : AMapLocation?,
isNeedAddress : Boolean,
success : (AMapLocation) -> Unit,
failed : (String) -> Unit) {
if (location == null) {
failed("Location is null")
LogUtil.print(TAG, "单次定位失败: location is null")
return
}
if (location.errorCode != 0) {
failed("Error code: ${location.errorCode}, ${location.errorInfo}")
LogUtil.print(TAG,
"单次定位失败: errorCode=${location.errorCode}, errorInfo=${location.locationDetail}")
return
}
if (isNeedAddress && location.address.isNullOrBlank()) {
nativeGeoCoder(location = location, success = { success(it) }, failed = { error ->
LogUtil.print(TAG, "逆地理编码失败: $error")
failed("位置获取失败")
})
if (it.address.isNullOrBlank() && isNeedAddress == true) {
geoCoder(it, { aMapLocation ->
it.time = System.currentTimeMillis()
GlobalData.currentLocation = it
success(aMapLocation)
}, { error -> failed(error) })
} else {
updateGlobalLocation(location)
success(location)
GlobalData.currentLocation = it
success(it)
}
} else {
failed(it.errorInfo)
LogUtil.print("单次定位失败",
"errorCode====${it.errorCode} errorInfo==${it.locationDetail}")
}
aMapLocationClient.stopLocation()
aMapLocationClient.onDestroy()
}
aMapLocationClient.startLocation()
}
private fun updateGlobalLocation(location : AMapLocation) {
globalLocation = location
lastSingleLocationTime = System.currentTimeMillis()
GlobalData.currentLocation = location
LogUtil.print(TAG, "单次定位结果: $location")
}
private fun doGetSingleLocationOnline(isNeedAddress : Boolean,
success : (AMapLocation) -> Unit,
failed : (String) -> Unit) {
val locationClient = createSingleLocationClient(isNeedAddress = isNeedAddress,
isGpsFirst = false) { location ->
handleLocationResult(location, isNeedAddress, success, failed)
} ?: run {
failed("Failed to create location client")
return
}
try {
locationClient.startLocation()
} catch (e : Exception) {
LogUtil.print(TAG, "启动单次定位失败: ${e.message}")
failed("Failed to start location: ${e.message}")
}
}
private fun doGetSingleLocationGps(success : (AMapLocation) -> Unit,
failed : (String) -> Unit) {
val locationClient =
createSingleLocationClient(isNeedAddress = false, isGpsFirst = true) { location ->
handleLocationResult(location, false, success, failed)
} ?: run {
failed("Failed to create location client")
failed : (String) -> Unit,
isNeedAddress : Boolean? = false) {
LogUtil.print(TAG, "doGetSingleLocationGps")
if (GlobalData.currentLocation != null && (System.currentTimeMillis()
.minus(GlobalData.currentLocation?.time ?: 0) < 60 * 1000)
) {
if (isNeedAddress == false) {
success(GlobalData.currentLocation !!)
return
}
try {
locationClient.startLocation()
} catch (e : Exception) {
LogUtil.print(TAG, "启动GPS定位失败: ${e.message}")
failed("Failed to start GPS location: ${e.message}")
}
val option = AMapLocationClientOption().apply {
this.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
this.isWifiScan = true
this.isGpsFirst = true
this.isLocationCacheEnable = true
this.httpTimeOut = 5000
this.gpsFirstTimeout = 5000
this.isMockEnable = false
this.isOnceLocation = true
}
AMapLocationClient.updatePrivacyShow(context, true, true)
AMapLocationClient.updatePrivacyAgree(context, true)
val aMapLocationClient = AMapLocationClient(context)
aMapLocationClient.setLocationOption(option)
aMapLocationClient.setLocationListener {
if (it != null && it.errorCode == 0) {
LogUtil.print("单次定位结果", "$it")
if (it.address.isNullOrBlank() && isNeedAddress == true) {
geoCoder(it, { aMapLocation ->
it.time = System.currentTimeMillis()
GlobalData.currentLocation = it
success(aMapLocation)
}, { error -> failed(error) })
} else {
GlobalData.currentLocation = it
success(it)
}
} else {
failed(it.errorInfo)
LogUtil.print("单次定位失败",
"errorCode====${it.errorCode} errorInfo==${it.locationDetail}")
}
aMapLocationClient.stopLocation()
aMapLocationClient.onDestroy()
}
aMapLocationClient.startLocation()
}
@SuppressLint("MissingPermission")
@ -320,10 +302,12 @@ object ZdLocationManager : AMapLocationListener {
locationManager)
) {
failed("Location service is disabled")
LogUtil.print(TAG, "原生定位 Location service is disabled")
return@let
}
val lastKnownLocation =
locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
LogUtil.print(TAG, "lastKnownLocation== ${lastKnownLocation?.toJson() ?: "null"}")
if (lastKnownLocation != null) {
val gcj02Location =
wgs84ToGcj02(lastKnownLocation.latitude, lastKnownLocation.longitude)
@ -352,8 +336,10 @@ object ZdLocationManager : AMapLocationListener {
private fun requestSingleGpsUpdate(locationManager : LocationManager,
success : (AMapLocation) -> Unit,
failed : (String) -> Unit) {
LogUtil.print(TAG, "requestSingleGpsUpdate")
val locationListener = object : android.location.LocationListener {
override fun onLocationChanged(location : Location) {
LogUtil.print(TAG, "requestSingleGpsUpdate onLocationChanged==${location.toJson()}")
locationManager.removeUpdates(this)
val gcj02 = wgs84ToGcj02(location.latitude, location.longitude)
val aMapLocation = AMapLocation("").apply {
@ -402,6 +388,7 @@ object ZdLocationManager : AMapLocationListener {
geocoderSearch.setOnGeocodeSearchListener(object : OnGeocodeSearchListener {
override fun onRegeocodeSearched(result : RegeocodeResult?, rCode : Int) {
if (result == null || rCode != 1000) {
LogUtil.print(TAG, "Geocoding failed: $rCode")
failed("Geocode search failed: $rCode")
return
}
@ -409,6 +396,7 @@ object ZdLocationManager : AMapLocationListener {
val address = result.regeocodeAddress?.formatAddress
if (! address.isNullOrBlank()) {
aMapLocation.address = address
LogUtil.print(TAG, "Geocoding success: $address")
success(aMapLocation)
} else {
failed("Empty address returned")

View File

@ -2,11 +2,13 @@ package com.za.signature;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@ -16,6 +18,8 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.activity.compose.ManagedActivityResultLauncher;
import androidx.activity.result.ActivityResult;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -178,7 +182,9 @@ public class GridPaintActivity extends BaseActivity implements View.OnClickListe
mEditView.setMaxWidth(maxWidth * 2 / 3);
}
mEditView.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
mEditView.setLineHeight(DisplayUtil.dip2px(this, fontSize));
}
mEditView.setHorizontallyScrolling(false);
mEditView.requestFocus();
if (bgColor != Color.TRANSPARENT) {
@ -303,7 +309,7 @@ public class GridPaintActivity extends BaseActivity implements View.OnClickListe
mHandler.obtainMessage(MSG_SAVE_FAILED).sendToTarget();
}
bm.recycle();
bm=null;
bm = null;
}).start();
}
@ -439,4 +445,14 @@ public class GridPaintActivity extends BaseActivity implements View.OnClickListe
}
public static void goGridPaintActivity(ManagedActivityResultLauncher<Intent, ActivityResult> launcher, Context context) {
Intent intent = new Intent(context, GridPaintActivity.class);
intent.putExtra("background", Color.WHITE);
intent.putExtra("crop", false);
intent.putExtra("fontSize", 60); //手写字体大小
intent.putExtra("format", PenConfig.FORMAT_PNG);
intent.putExtra("lineLength", 10); //每行显示字数(超出屏幕支持横向滚动)
launcher.launch(intent);
}
}

View File

@ -101,7 +101,7 @@ public class HandWriteEditView extends AppCompatEditText {
return null;
}
SpannableString mSpan = new SpannableString("1");
mSpan.setSpan(new ImageSpan(getContext(), srcBitmap, ImageSpan.ALIGN_BASELINE), mSpan.length() - 1, mSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mSpan.setSpan(new ImageSpan(getContext(), srcBitmap, ImageSpan.ALIGN_BOTTOM), mSpan.length() - 1, mSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Editable editable = getText();
//获取光标所在位置

View File

@ -38,6 +38,7 @@ import com.za.bean.request.DriverFaceCompareRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.speech.SpeechManager
import com.za.common.util.ImageUtil
import com.za.net.BaseObserver
import com.za.net.CommonMethod
import com.za.net.RetrofitHelper
@ -57,7 +58,7 @@ class ServicePeopleRealActivity : AppCompatActivity() {
private var isActivityActive = true
private var currentStep = 0
private val steps = listOf( "请向左转头", "请向右转头", "请保持面部居中")
private val steps = listOf("请向左转头", "请向右转头", "请保持面部居中")
private var isStepCompleted = false
private lateinit var viewFinder : PreviewView
@ -110,10 +111,10 @@ class ServicePeopleRealActivity : AppCompatActivity() {
retryButton = findViewById(R.id.retryButton)
confirmButton = findViewById(R.id.confirmButton)
// lowLightWarning = findViewById(R.id.lowLightWarning) // 保存原始亮度
// originalBrightness = window.attributes.screenBrightness.let {
// if (it != - 1f) it else 0.5f
// }.toInt()
// lowLightWarning = findViewById(R.id.lowLightWarning) // 保存原始亮度
// originalBrightness = window.attributes.screenBrightness.let {
// if (it != - 1f) it else 0.5f
// }.toInt()
}
private fun setupClickListeners() {
@ -242,8 +243,7 @@ class ServicePeopleRealActivity : AppCompatActivity() {
lifecycleCameraController.setImageAnalysisAnalyzer(ContextCompat.getMainExecutor(this@ServicePeopleRealActivity),
FaceAnalyzer(faceListener = {
handleFaceDetection(it)
}, lightListener = {
// handleLowLightCallback(it)
}, lightListener = { // handleLowLightCallback(it)
}))
}
@ -343,7 +343,8 @@ class ServicePeopleRealActivity : AppCompatActivity() {
private fun returnPhotoResult() {
avatarBitmap?.let { bitmap -> // 保存图片到临时文件
val file = ImageUtils.save2Album(bitmap, CompressFormat.JPEG, 100)
val comprossBitmap = ImageUtil.scaleBitmapWithMatrix(bitmap, 1280)
val file = ImageUtils.save2Album(comprossBitmap, CompressFormat.JPEG, 100)
if (file?.exists() == true) { // 创建返回结果
val resultIntent = Intent()
resultIntent.putExtra("path", file.absolutePath)

View File

@ -291,21 +291,7 @@ class ZdCameraXActivity : AppCompatActivity() {
if (imageCapture == null) {
ToastUtils.showShort("相机打开失败")
finish()
} // val filename = TimeUtils.date2String(Date(), "yyyyMMddHHmmss")
// val contentValues = ContentValues()
// contentValues.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, filename)
// contentValues.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/jpeg")
// contentValues.put(MediaStore.Images.ImageColumns.DATE_TAKEN, System.currentTimeMillis())
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// contentValues.put(MediaStore.Images.ImageColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
// } else {
// ImageUtils.save2Album()
// contentValues.put(MediaStore.Images.ImageColumns.DATA, getTakePictureParentPath() + File.separator + filename + ".jpg")
// }
//
// val outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver,
// MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues).build()
}
// Create time stamped name and MediaStore entry.
val filename = SimpleDateFormat("yyyyMMddHHmmss",
@ -325,7 +311,6 @@ class ZdCameraXActivity : AppCompatActivity() {
takePhoto?.startAnimation()
imageCapture?.takePicture(outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
@ -347,6 +332,7 @@ class ZdCameraXActivity : AppCompatActivity() {
exifInterface.saveAttributes()
takePhoto?.cancelAnimation()
groupPreview?.visibility = View.VISIBLE
if (! this@ZdCameraXActivity.isFinishing) {
Glide.with(this@ZdCameraXActivity).load(outputFileResults.savedUri)
.into(ivPreview)
@ -372,6 +358,7 @@ class ZdCameraXActivity : AppCompatActivity() {
imageCapture =
ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
.build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
try {

View File

@ -157,6 +157,7 @@ private fun CommonH5Screen(url : String,
var progress by remember { mutableFloatStateOf(0f) }
var isError by remember { mutableStateOf(false) }
var webView by remember { mutableStateOf<WebView?>(null) }
var title by remember { mutableStateOf(title) }
BackHandler(enabled = isCanBack || webView?.canGoBack() == true) {
handleBackPress(context, webView)
@ -178,6 +179,9 @@ private fun CommonH5Screen(url : String,
onError = { _, desc ->
isError = true
ToastUtils.showLong("加载失败:$desc")
},
onReceiveTitle = {
title = it ?: ""
})
webView = this
onWebViewCreated(this)
@ -197,11 +201,17 @@ private fun CommonH5Screen(url : String,
private fun setupWebViewClients(webView : WebView,
onProgressChanged : (Int) -> Unit,
onReceiveTitle : (String?) -> Unit,
onError : (Int, String?) -> Unit) {
webView.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view : WebView?, newProgress : Int) {
onProgressChanged(newProgress)
}
override fun onReceivedTitle(view : WebView?, title : String?) {
onReceiveTitle(title)
LogUtil.print("H5Activity title", "$title")
}
}
webView.webViewClient = object : WebViewClient() {

View File

@ -48,6 +48,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.blankj.utilcode.util.ActivityUtils
import com.google.gson.Gson
import com.za.base.BaseActivity
import com.za.base.Const
import com.za.base.theme.bgColor
import com.za.base.view.CommonButton
import com.za.base.view.EmptyView
@ -64,7 +65,7 @@ import com.za.ext.finish
import com.za.ext.goStatusPage
import com.za.service.PushListener
import com.za.service.ServiceManager
import com.za.service.ZdPushServiceReceive
import com.za.service.ServiceManager.registerPushListener
import com.za.service.location.ZdLocationManager
import com.za.servicing.R
import kotlinx.coroutines.launch
@ -84,43 +85,49 @@ class ServicingMainActivity : BaseActivity() {
override fun onResume() {
super.onResume()
setupPushMessageReceiver()
setupPushMessageReceiver(this)
}
private fun setupPushMessageReceiver() { // 注册推送消息接收器
ServiceManager.registerPushListener(object : PushListener {
private fun setupPushMessageReceiver(context : Context) { // 注册推送消息接收器
registerPushListener(object : PushListener {
override fun broadcast(msg : String) {
sendMessageToMainProcess("broadcast", msg)
sendMessageToMainProcess(context = context, "broadcast", msg)
}
override fun giveUpOrder(jpushBean : JpushBean) {
sendMessageToMainProcess("giveUp", Gson().toJson(jpushBean))
sendMessageToMainProcess(context = context, "giveUp", Gson().toJson(jpushBean))
}
override fun importantTip(jpushBean : JpushBean) {
sendMessageToMainProcess("importantTip", Gson().toJson(jpushBean))
sendMessageToMainProcess(context = context,
"importantTip",
Gson().toJson(jpushBean))
}
override fun newOrderMsg(jpushBean : JpushBean) {
sendMessageToMainProcess("newOrder", Gson().toJson(jpushBean))
sendMessageToMainProcess(context = context, "newOrder", Gson().toJson(jpushBean))
}
override fun reDispatchOrder(jpushBean : JpushBean) {
sendMessageToMainProcess("reDispatch", Gson().toJson(jpushBean))
sendMessageToMainProcess(context = context, "reDispatch", Gson().toJson(jpushBean))
}
override fun revokeOrder(jpushBean : JpushBean) {
sendMessageToMainProcess("revoke", Gson().toJson(jpushBean))
sendMessageToMainProcess(context = context, "revoke", Gson().toJson(jpushBean))
}
})
}
private fun sendMessageToMainProcess(type : String, message : String) { // 使用广播将消息发送到主进程
val intent = Intent(ZdPushServiceReceive.RECEIVE_ACTION).setPackage(packageName)
fun sendMessageToMainProcess(context : Context,
type : String,
message : String) { // 使用广播将消息发送到主进程
val intent = Intent(Const.PushMessageType.ACTION_MAIN.takeIf { GlobalData.isMaster }
?: Const.PushMessageType.ACTION_SDK)
intent.setPackage(context.packageName)
intent.putExtra("type", type)
intent.putExtra("message", message)
sendBroadcast(intent)
LogUtil.print(TAG, "发送消息到主进程: $type")
context.sendBroadcast(intent)
LogUtil.print("KeepAliveService", "发送消息到主进程: $type")
}
companion object {

View File

@ -18,6 +18,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.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
@ -36,7 +37,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@ -55,6 +58,7 @@ import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.LatLngBounds
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.PolylineOptions
import com.blankj.utilcode.util.ConvertUtils
import com.za.base.BaseActivity
import com.za.base.view.CommonDialog
import com.za.base.view.HeadViewNotBack
@ -104,11 +108,6 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
val uiState = vm.uiState.collectAsStateWithLifecycle()
val mapView = remember { MapView(context) }
// 将状态提升到 Composable 层级
val lastRoutePoints = remember { mutableStateOf<List<LatLng>?>(null) }
val lastMarkers = remember { mutableStateOf<ArrayList<MarkerOptions>?>(null) }
val lastCurrentLocation = remember { mutableStateOf<LatLng?>(null) }
val bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.Expanded)
val scaffoldState = rememberBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
@ -126,7 +125,6 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
Lifecycle.Event.ON_PAUSE -> mapView.onPause()
Lifecycle.Event.ON_DESTROY -> {
mapView.onDestroy()
vm.dispatch(NewOrderVm.Action.UpdateState(uiState.value.copy(remainingTime = 0)))
}
else -> {}
@ -140,7 +138,6 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
onDispose {
try {
lifecycleOwner.lifecycle.removeObserver(observer)
vm.dispatch(NewOrderVm.Action.UpdateState(uiState.value.copy(remainingTime = 0)))
} catch (e : Exception) {
LogUtil.print("DisposableEffect", "清理资源异常: ${e.message}")
}
@ -171,31 +168,30 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
}
if (uiState.value.refuseSuccess == true) {
vm.updateState(uiState.value.copy(refuseSuccess = false))
context.finish()
}
// 添加超时对话框
if (uiState.value.showTimeoutDialog) {
CommonDialog(cancelText = "关闭",
confirmText = "确定",
title = "订单已超时",
message = "当前订单已超时,请等待新的订单",
cancelEnable = false,
dismiss = {
vm.dispatch(NewOrderVm.Action.UpdateState(uiState.value.copy(showTimeoutDialog = false)))
context.finish()
},
if (uiState.value.refuelOrderDialog == true) {
CommonDialog(title = "请确认是否拒绝该任务!",
confirmText = "确认拒绝",
cancelText = "再想想",
cancelEnable = true,
confirm = {
vm.dispatch(NewOrderVm.Action.UpdateState(uiState.value.copy(showTimeoutDialog = false)))
context.finish()
})
vm.updateState(uiState.value.copy(refuelOrderDialog = false))
vm.dispatch(NewOrderVm.Action.RefuseOrder)
},
cancel = {
vm.updateState(uiState.value.copy(refuelOrderDialog = false))
},
dismiss = { vm.updateState(uiState.value.copy(refuelOrderDialog = false)) })
}
if (uiState.value.acceptOrderDialog == true) {
CommonDialog(title = "请确认是否接受该任务!",
confirmText = "确认接单",
cancelText = "再想想",
cancelEnable = false,
cancelEnable = true,
confirm = {
vm.updateState(uiState.value.copy(acceptOrderDialog = false))
vm.dispatch(NewOrderVm.Action.ShowTaskNotes)
@ -206,13 +202,20 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
if (uiState.value.showTaskNotesDialog == true) {
OrderTaskNotesDialog(uiState.value.taskNotesBean,
uiState.value.jpushBean?.contract,
uiState.value.jpushBean?.hasReplaceBatteryCapable == 2,
dismiss = {},
dismiss = {
vm.updateState(uiState.value.copy(showTaskNotesDialog = false))
},
confirm = {
vm.updateState(uiState.value.copy(showTaskNotesDialog = false))
vm.dispatch(NewOrderVm.Action.AcceptOrder)
})
}
var sheetExpandHeight = remember { mutableStateOf(0.dp) }
val localDensity = LocalDensity.current
BottomSheetScaffold(scaffoldState = scaffoldState,
topBar = { HeadViewNotBack(title = "新订单") },
sheetContent = {
@ -221,13 +224,24 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
address = uiState.value.jpushBean?.address,
distAddress = uiState.value.jpushBean?.distAddress,
serviceTypeName = uiState.value.jpushBean?.serviceTypeName,
orderSource = uiState.value.jpushBean?.orderSource,
orderSource = uiState.value.jpushBean?.contract,
settleType = uiState.value.jpushBean?.settleType,
bottomTextString = "接单",
reserveTime = (uiState.value.jpushBean?.appointTime
?: "").takeIf { uiState.value.jpushBean?.isAppoint == 1 } ?: "",
uiType = NewOrderUiType.ACCEPT)
Box(modifier = Modifier
.fillMaxWidth()
.onSizeChanged { coordinates ->
sheetExpandHeight.value = with(localDensity) { coordinates.height.toDp() }
}) {
NewOrderItem(uiBean, goAccept = {
vm.dispatch(NewOrderVm.Action.ShowTaskNotes)
}, refuelOrder = {
vm.updateState(uiState.value.copy(refuelOrderDialog = true))
})
}
},
sheetPeekHeight = 180.dp,
sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
@ -236,8 +250,13 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
sheetDragHandle = null,
sheetSwipeEnabled = true) { paddingValues ->
Box(modifier = Modifier
.fillMaxSize()
.padding(paddingValues)) {
.wrapContentSize()
.padding(top = paddingValues.calculateTopPadding(),
bottom = if (bottomSheetState.currentValue == SheetValue.PartiallyExpanded) {
0.dp
} else {
sheetExpandHeight.value
})) {
AndroidView(modifier = Modifier.fillMaxSize(), factory = {
AMapLocationClient.updatePrivacyShow(context, true, true)
AMapLocationClient.updatePrivacyAgree(context, true)
@ -259,15 +278,6 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
}
}
}, update = { mapView ->
val currentLocation = if (GlobalData.currentLocation != null) {
LatLng(GlobalData.currentLocation?.latitude !!,
GlobalData.currentLocation?.longitude !!)
} else null
val needUpdate =
lastRoutePoints.value != uiState.value.routePoints || lastMarkers.value != uiState.value.markers || lastCurrentLocation.value != currentLocation
if (needUpdate) {
mapView.map.clear()
// 绘制路线
@ -277,57 +287,34 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
.zIndex(1f))
}
// 添加标记点
val allPoints = mutableListOf<LatLng>()
mapView.map.addMarkers(uiState.value.markers, false)
// 添加当前位置标记
currentLocation?.let {
mapView.map.addMarker(MarkerOptions().position(it).title("当前位置")
if (GlobalData.currentLocation != null) {
mapView.map.addMarker(MarkerOptions().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))
allPoints.add(it)
}
// 添加其他标记点
uiState.value.markers?.let { markers ->
mapView.map.addMarkers(markers, true)
markers.forEach { marker ->
allPoints.add(marker.position)
}
// 计算地图显示范围
val bounds = LatLngBounds.Builder().apply {
uiState.value.routePoints?.forEach {
include(LatLng(it.latitude, it.longitude))
}
}.build()
// 添加路线点
uiState.value.routePoints?.let { points ->
allPoints.addAll(points)
}
// 计算边界
if (allPoints.isNotEmpty()) {
// 调整地图显示范围,确保所有点都可见
try {
val boundsBuilder = LatLngBounds.builder()
allPoints.forEach { point ->
boundsBuilder.include(point)
}
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(
boundsBuilder.build(),
100))
} catch (e : Exception) { // 如果边界计算失败,使用救援点作为中心
jpushBean?.let { bean ->
if (bean.lat != null && bean.lat != 0.0 && bean.lng != null && bean.lng != 0.0) {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(
LatLng(bean.lat, bean.lng),
15f))
}
}
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,
ConvertUtils.dp2px(50f)))
} catch (e : Exception) { // 如果计算边界失败,则使用默认缩放级别
GlobalData.currentLocation?.let {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(it.latitude,
it.longitude), 15f))
}
}
// 更新状态
lastRoutePoints.value = uiState.value.routePoints
lastMarkers.value = uiState.value.markers
lastCurrentLocation.value = currentLocation
}
})
}
}

View File

@ -26,6 +26,12 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
@ -43,17 +49,24 @@ import coil.compose.AsyncImage
import com.za.base.theme.bgColor
import com.za.base.theme.black50
import com.za.base.theme.black90
import com.za.base.theme.buttonBgColor
import com.za.base.view.CommonButton
import com.za.base.view.CommonDialog
import com.za.common.log.LogUtil
import com.za.ext.copy
import com.za.ext.finish
import com.za.servicing.R
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
object NewOrderUiType {
const val SERVICING = 1
const val HISTORY = 2
const val ACCEPT = 3
const val PENDING = 4
const val IN_SERVICING_HOME = 5
const val SERVICING = 1 //服务中界面
const val HISTORY = 2 //历史界面
const val ACCEPT = 3 //接单页
const val PENDING = 4 //待服务
const val IN_SERVICING_HOME = 5 //首页服务中
}
data class NewOrderItemUIBean(
@ -82,6 +95,7 @@ fun NewOrderItem(uiBean : NewOrderItemUIBean?,
goDetail : () -> Unit = {},
goNextPage : () -> Unit = {},
goAccept : () -> Unit = {},
refuelOrder : () -> Unit = {},
goOrderPhoto : () -> Unit = {},
goEle : () -> Unit = {},
goChange : () -> Unit = {}) {
@ -157,14 +171,19 @@ fun NewOrderItem(uiBean : NewOrderItemUIBean?,
Spacer(modifier = Modifier.width(10.dp))
Text(uiBean?.orderSource ?: "",
color = Color.Black,
modifier = Modifier.width(140.dp),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Medium,
fontSize = 12.sp)
Spacer(Modifier.weight(1f))
Text(uiBean?.addressProperty ?: "",
color = Color.Black,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.width(100.dp),
fontWeight = FontWeight.SemiBold,
fontSize = 14.sp,
modifier = Modifier.wrapContentSize(align = Alignment.Center))
fontSize = 14.sp)
}
if (! uiBean?.reserveTime.isNullOrBlank()) {
@ -225,7 +244,8 @@ fun NewOrderItem(uiBean : NewOrderItemUIBean?,
modifier = Modifier.size(16.dp))
if (! uiBean?.distAddress.isNullOrBlank()) {
VerticalDivider(modifier = Modifier.weight(1f), color = Color(0xFFC1C1C1))
VerticalDivider(modifier = Modifier.weight(1f),
color = Color(0xFFC1C1C1).copy(0.5f))
AsyncImage(model = R.drawable.sv_dist,
contentDescription = null,
@ -315,14 +335,36 @@ fun NewOrderItem(uiBean : NewOrderItemUIBean?,
if (uiBean?.uiType == NewOrderUiType.SERVICING || uiBean?.uiType == NewOrderUiType.ACCEPT) {
Spacer(modifier = Modifier.height(10.dp))
CommonButton(text = uiBean?.bottomTextString ?: "") {
if (uiBean?.uiType == NewOrderUiType.ACCEPT) {
goAccept()
return@CommonButton
Row(modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 5.dp)) {
CommonButton(text = "拒绝",
modifier = Modifier
.weight(1f)
.padding(vertical = 10.dp, horizontal = 5.dp)
.background(color = buttonBgColor.copy(alpha = 0.5f),
shape = RoundedCornerShape(4.dp))
.padding(vertical = 15.dp)) {
refuelOrder()
}
CommonButton(text = uiBean?.bottomTextString ?: "",
modifier = Modifier
.weight(2f)
.padding(vertical = 10.dp, horizontal = 5.dp)
.background(color = buttonBgColor, shape = RoundedCornerShape(4.dp))
.padding(vertical = 15.dp)) {
goAccept()
}
}
} else {
CommonButton(text = uiBean?.bottomTextString ?: "") {
goNextPage()
}
}
}
Spacer(modifier = Modifier.height(20.dp))
}
@ -332,8 +374,14 @@ fun NewOrderItem(uiBean : NewOrderItemUIBean?,
fun NewOrderItemHead(uiBean : NewOrderItemUIBean?,
goInServicing : () -> Unit = {},
goChange : () -> Unit = {}) {
var timeOut by remember { mutableStateOf<String?>(null) }
if (uiBean?.uiType == NewOrderUiType.ACCEPT) {
NewOrderTimeOut(countValue = { timeOut = it })
}
when (uiBean?.uiType) {
NewOrderUiType.IN_SERVICING_HOME, NewOrderUiType.PENDING, NewOrderUiType.SERVICING -> {
NewOrderUiType.IN_SERVICING_HOME, NewOrderUiType.PENDING, NewOrderUiType.SERVICING, NewOrderUiType.ACCEPT -> {
Row(modifier = Modifier
.fillMaxWidth()
.clickable {
@ -356,11 +404,13 @@ fun NewOrderItemHead(uiBean : NewOrderItemUIBean?,
verticalAlignment = Alignment.CenterVertically) {
Text(uiBean.serviceTypeName ?: "",
color = black90,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Medium,
modifier = Modifier.fillMaxWidth(0.5f),
fontSize = 17.sp)
Spacer(Modifier.weight(1f))
if (uiBean?.uiType == NewOrderUiType.SERVICING) {
Text("预计到达:",
color = Color(0xFFF19028),
@ -370,9 +420,22 @@ fun NewOrderItemHead(uiBean : NewOrderItemUIBean?,
Text("${
uiBean.expectArriveTime?.split(" ")?.get(1)
}", color = Color(0xFFF19028), fontWeight = FontWeight.Medium, fontSize = 13.sp)
} else if (uiBean?.uiType == NewOrderUiType.ACCEPT) {
Text("超时剩余:",
color = Color.Red,
fontWeight = FontWeight.Medium,
fontSize = 13.sp)
Spacer(modifier = Modifier.width(8.dp))
Text(timeOut ?: "",
color = Color.Red,
fontWeight = FontWeight.Medium,
fontSize = 13.sp)
} else {
Text(uiBean?.currentOrderState ?: "",
color = Color(0xFFF19028),
modifier = Modifier.fillMaxWidth(0.4f),
overflow = TextOverflow.Ellipsis,
maxLines = 1,
fontWeight = FontWeight.Medium,
fontSize = 13.sp)
Spacer(modifier = Modifier.width(8.dp))
@ -428,3 +491,50 @@ fun NewOrderItemHead(uiBean : NewOrderItemUIBean?,
HorizontalDivider(modifier = Modifier.alpha(0.1f))
}
@Composable
private fun NewOrderTimeOut(countValue : (String) -> Unit) {
val context = LocalContext.current
var timerJob : Job? = null
val scope = rememberCoroutineScope()
var timeCount by remember { mutableStateOf<String?>(null) }
var showTimeOutDialog by remember { mutableStateOf(false) }
DisposableEffect(timerJob) {
timerJob = scope.launch {
try {
var timeLeft = 120
while (timeLeft > 0) {
delay(1000)
timeLeft --
timeCount = "$timeLeft"
countValue(timeCount ?: "")
}
if (timeLeft == 0) {
showTimeOutDialog = true
}
} catch (e : Exception) {
LogUtil.print("startTimer", "倒计时异常: ${e.message}")
}
}
onDispose {
timerJob?.cancel()
timerJob = null
}
}
if (showTimeOutDialog) {
CommonDialog(cancelText = "关闭",
confirmText = "确定",
title = "订单已超时",
message = "当前订单已超时,请等待新的订单",
cancelEnable = false,
dismiss = {
showTimeOutDialog = false
context.finish()
},
confirm = {
showTimeOutDialog = false
context.finish()
})
}
}

View File

@ -1,6 +1,5 @@
package com.za.ui.new_order
import androidx.lifecycle.viewModelScope
import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.MarkerOptions
@ -30,10 +29,7 @@ import com.za.servicing.R
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@ -49,9 +45,7 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
is Action.Init -> init(action.jpushBean)
is Action.AcceptOrder -> acceptOrder()
is Action.RefuseOrder -> refuseOrder()
is Action.StartTimer -> startTimer()
is Action.ShowTaskNotes -> showTaskNotes()
is Action.UpdateTimer -> updateTimer(action.remainingTime)
else -> {}
}
}
@ -64,7 +58,6 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
updateState(uiState.value.copy(jpushBean = jpushBean))
buildMarkers(jpushBean)
searchDrivingRoute(jpushBean)
startTimer()
getTaskNote()
}
@ -85,20 +78,20 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
private fun buildMarkers(jpushBean : JpushBean?) {
val markers = arrayListOf<MarkerOptions>()
if (jpushBean?.lat != null && jpushBean.lat != 0.0 && jpushBean.lng != null && jpushBean.lng != 0.0) {
if (jpushBean?.lat != null && jpushBean.lat != 0.0 && jpushBean.lng != null && jpushBean.lng != 0.0) { // 获取矢量图资源文件
val startMarkers =
MarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.mipmap.sv_rescuing_map))
.position(LatLng(jpushBean.lat, jpushBean.lng)).title(jpushBean.address)
.snippet("救援地点").visible(true)
.position(LatLng(jpushBean.lat !!, jpushBean.lng !!)).infoWindowEnable(false)
.visible(true)
markers.add(startMarkers)
}
if (jpushBean?.distLat != null && jpushBean.distLat != 0.0 && jpushBean.distLng != null && jpushBean.distLng != 0.0) {
val startMarkers =
val destMarker =
MarkerOptions().icon(ImageUtil.vectorToBitmap(ActivityUtils.getTopActivity(),
R.drawable.sv_map_dist)).position(LatLng(jpushBean.distLat, jpushBean.distLng))
.title(jpushBean.distAddress).snippet("目的地").visible(true)
markers.add(startMarkers)
R.drawable.sv_map_dist))
.position(LatLng(jpushBean.distLat !!, jpushBean.distLng !!)).visible(true)
markers.add(destMarker)
}
updateState(uiState.value.copy(markers = markers))
}
@ -135,13 +128,43 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
override fun doFailure(code : Int, msg : String?) {
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
showTipDialog(msg ?: "接单失败")
LogUtil.print("接单失败", "request=$acceptOrderRequest msg=$msg")
}
})
}, failed = {
LoadingManager.hideLoading()
LogUtil.print("接单时获取定位失败", it)
if (GlobalData.currentLocation == null) {
LogUtil.print("接单失败", "定位获取失败$it")
showTipDialog(it)
} else {
val orderInfo = uiState.value.jpushBean
val acceptOrderRequest = AcceptOrderRequest()
acceptOrderRequest.taskId = orderInfo?.taskId
acceptOrderRequest.vehicleId = GlobalData.driverInfoBean?.vehicleId
acceptOrderRequest.userId = GlobalData.driverInfoBean?.userId
acceptOrderRequest.taskCode = orderInfo?.taskCode
acceptOrderRequest.deviceId =
DeviceUtil.getAndroidId(ActivityUtils.getTopActivity())
acceptOrderRequest.lat = GlobalData.currentLocation?.latitude
acceptOrderRequest.lng = GlobalData.currentLocation?.longitude
RetrofitHelper.getDefaultService().acceptOrder(acceptOrderRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<String>() {
override fun doSuccess(it : String?) {
LoadingManager.hideLoading()
LogUtil.print("接单成功,单次订单获取失败",
"request=$acceptOrderRequest")
updateState(uiState.value.copy(showCallPhoneDialog = orderInfo?.isNeedCallCustomPhone()))
}
override fun doFailure(code : Int, msg : String?) {
LoadingManager.hideLoading()
showTipDialog(msg ?: "接单失败")
LogUtil.print("接单失败", "request=$acceptOrderRequest msg=$msg")
}
})
}
})
}
@ -167,25 +190,6 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
})
}
private fun startTimer() {
timerJob?.cancel()
timerJob = viewModelScope.launch {
try {
var timeLeft = 120
while (timeLeft > 0 && isActive) {
delay(1000)
timeLeft --
updateState(uiState.value.copy(remainingTime = timeLeft))
}
if (timeLeft == 0 && isActive) { // 倒计时结束,显示订单超时
updateState(uiState.value.copy(isTimeout = true, showTimeoutDialog = true))
}
} catch (e : Exception) {
LogUtil.print("startTimer", "倒计时异常: ${e.message}")
}
}
}
private fun isNeedShowNotes() : Boolean {
if (! uiState.value.taskNotesBean?.taskNotes.isNullOrBlank()) {
return true
@ -206,38 +210,23 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
return false
}
private fun updateTimer(remainingTime : Int) {
updateState(uiState.value.copy(remainingTime = remainingTime))
}
private fun searchDrivingRoute(jpushBean : JpushBean?) {
if (GlobalData.currentLocation == null) {
ToastUtils.showShort("获取当前位置失败")
return
}
updateState(uiState.value.copy(isLoading = true))
if (GlobalData.currentLocation == null) return
val startPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
GlobalData.currentLocation?.longitude ?: 0.0)
GlobalData.currentLocation?.longitude ?: 0.0) // 获取救援地点坐标
val rescuePoint =
if (jpushBean?.lat != null && jpushBean.lat != 0.0 && jpushBean.lng != null && jpushBean.lng != 0.0) {
LatLonPoint(jpushBean.lat !!, jpushBean.lng !!)
} else null
val endPoint = when {
jpushBean?.distLat != null && jpushBean.distLat != 0.0 && jpushBean.distLng != null && jpushBean.distLng != 0.0 -> {
LatLonPoint(jpushBean.distLat, jpushBean.distLng)
}
// 获取救援地点坐标
val disPoint =
if (jpushBean?.distLat != null && jpushBean.distLat != 0.0 && jpushBean.distLng != null && jpushBean.distLng != 0.0) {
LatLonPoint(jpushBean.distLat !!, jpushBean.distLng !!)
} else null
jpushBean?.lat != null && jpushBean.lat != 0.0 && jpushBean.lng != null && jpushBean.lng != 0.0 -> {
LatLonPoint(jpushBean.lat, jpushBean.lng)
}
else -> null
}
if (endPoint == null) return
val fromAndTo = RouteSearch.FromAndTo(startPoint, endPoint)
val query =
RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DrivingDefault, null, null, "")
// 如果没有救援地点,则不进行规划
if (rescuePoint == null) return
RouteSearch(GlobalData.application).apply {
setRouteSearchListener(object : RouteSearch.OnRouteSearchListener {
@ -268,7 +257,25 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
override fun onWalkRouteSearched(p0 : WalkRouteResult?, p1 : Int) {}
override fun onRideRouteSearched(p0 : RideRouteResult?, p1 : Int) {}
})
if (disPoint != null) {
val fromAndTo = RouteSearch.FromAndTo(startPoint, disPoint)
val wayPoints = listOf(rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
wayPoints,
null,
"")
calculateDriveRouteAsyn(query)
} else {
val fromAndTo = RouteSearch.FromAndTo(startPoint, rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
null,
null,
"")
calculateDriveRouteAsyn(query)
}
}
}
@ -288,8 +295,6 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
data class UpdateState(val uiState : UiState) : Action()
data object RefuseOrder : Action()
data object ShowTaskNotes : Action()
data object StartTimer : Action()
data class UpdateTimer(val remainingTime : Int) : Action()
}
data class UiState(val jpushBean : JpushBean? = null,
@ -298,14 +303,12 @@ class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
val refuseSuccess : Boolean? = false,
val taskNotesBean : TaskNotesBean? = null,
val showTaskNotesDialog : Boolean? = false,
val refuelOrderDialog : Boolean? = false,
val acceptOrderDialog : Boolean? = null,
val remainingTime : Int = 50,
val routePoints : List<LatLng>? = null,
val remainingDistance : Double = 0.0,
val estimatedArrivalTime : String = "",
val isLoading : Boolean = false,
val isTimeout : Boolean = false,
val showTimeoutDialog : Boolean = false)
}

View File

@ -26,6 +26,7 @@ import android.widget.ImageView
import androidx.core.app.NotificationCompat
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.ServiceUtils
import com.za.common.log.LogUtil
import com.za.servicing.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -65,10 +66,14 @@ class ReportFloatingManager : Service() {
}
}
override fun onBind(intent : Intent?) : IBinder? = null
override fun onBind(intent : Intent?) : IBinder?{
LogUtil.print("ReportFloatingManager service", "onBind")
return null
}
override fun onCreate() {
super.onCreate()
LogUtil.print("ReportFloatingManager service", "onCreate")
lastUpdateTime = System.currentTimeMillis()
prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
initializeFloatingWindow()

View File

@ -5,7 +5,6 @@ import android.content.Context
import android.content.Intent
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
@ -39,6 +38,7 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import coil.compose.AsyncImage
import com.amap.api.location.AMapLocation
import com.amap.api.maps.model.LatLng
import com.blankj.utilcode.util.TimeUtils
import com.blankj.utilcode.util.ToastUtils
import com.permissionx.guolindev.PermissionX
@ -54,6 +54,7 @@ import com.za.bean.db.order.PhotoTemplateInfo
import com.za.bean.request.OrderPhotoOcrRecognizeRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.util.MapUtil
import com.za.ext.getEleOrderH5Url
import com.za.ext.noDoubleClick
import com.za.ext.toJson
@ -72,6 +73,21 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.File
import java.util.concurrent.Executors
private fun formatLocationAddress(aMapLocation : AMapLocation?, context : Context) : String {
return if (aMapLocation?.address.isNullOrBlank()) {
if (aMapLocation?.latitude != 0.0 && aMapLocation?.longitude != 0.0) {
MapUtil.getAddressFromLocation(context = context,
latLng = LatLng(aMapLocation?.latitude ?: 0.0, aMapLocation?.longitude ?: 0.0))
?: ""
} else {
""
}
} else {
aMapLocation?.address ?: ""
}
}
@Synchronized
private fun handlerInServicingPhoto(
context : Context,
@ -82,6 +98,7 @@ private fun handlerInServicingPhoto(
) {
LogUtil.print("handlerPhoto", "photoTemplateInfo==${photoTemplateInfo.toJson()}")
val time = System.currentTimeMillis().minus(photoTemplateInfo.advanceTime ?: 0L)
val address = formatLocationAddress(aMapLocation = aMapLocation, context = context)
val photoTemplateInfoTemp = photoTemplateInfo.copy(photoLocalPath = path,
photoUploadPath = null,
realTakePhotoTime = TimeUtils.getNowString(),
@ -89,7 +106,7 @@ private fun handlerInServicingPhoto(
time = TimeUtils.millis2String(time),
lat = aMapLocation?.latitude?.toFloat(),
lng = aMapLocation?.longitude?.toFloat(),
address = aMapLocation?.address)
address = address)
LogUtil.print("本地照片拍好返回结果",
photoTemplateInfoTemp.toJson() ?: photoTemplateInfoTemp.toString())
RoomHelper.db?.photoTemplateDao()?.update(photoTemplateInfo = photoTemplateInfoTemp)
@ -98,15 +115,14 @@ private fun handlerInServicingPhoto(
var localPhotoTemplateInfo = photoTemplateInfoTemp
//当需要添加水印并且地址不为空的情况下,才添加水印
val file =
if (localPhotoTemplateInfo.needWaterMarker == true && ! aMapLocation?.address.isNullOrBlank()) {
val photoMarkerInfo = PhotoMarkerInfo(localPhotoTemplateInfo.needWaterMarker,
val file = if (localPhotoTemplateInfo.needWaterMarker == true) {
val photoMarkerInfo = PhotoMarkerInfo(needMark = true,
needShowPhoneBrand = localPhotoTemplateInfo.needShowPhoneBrand,
path = localPhotoTemplateInfo.photoLocalPath,
from = "(相机)",
lat = localPhotoTemplateInfo.lat?.toDouble(),
lng = localPhotoTemplateInfo.lng?.toDouble(),
address = localPhotoTemplateInfo.address,
address = localPhotoTemplateInfo.address ?: "",
time = localPhotoTemplateInfo.time,
driverName = GlobalData.driverInfoBean?.userName,
taskCode = localPhotoTemplateInfo.taskCode)
@ -164,6 +180,7 @@ private fun handlerChangeBatteryPhoto(context : Context,
success : (PhotoTemplateInfo) -> Unit) {
LogUtil.print("handlerPhoto", "photoTemplateInfo==${photoTemplateInfo.toJson()}")
val time = System.currentTimeMillis().minus(photoTemplateInfo.advanceTime ?: 0L)
val address = formatLocationAddress(aMapLocation = aMapLocation, context = context)
val photoTemplateInfoTemp = photoTemplateInfo.copy(photoLocalPath = path,
photoUploadPath = null,
realTakePhotoTime = TimeUtils.getNowString(),
@ -171,16 +188,15 @@ private fun handlerChangeBatteryPhoto(context : Context,
time = TimeUtils.millis2String(time),
lat = aMapLocation?.latitude?.toFloat(),
lng = aMapLocation?.longitude?.toFloat(),
address = aMapLocation?.address)
address = address)
LogUtil.print("本地照片拍好返回结果",
photoTemplateInfoTemp.toJson() ?: photoTemplateInfoTemp.toString())
RoomHelper.db?.changeBatteryDao()?.update(photoTemplateInfo = photoTemplateInfoTemp)
success(photoTemplateInfoTemp)
var localPhotoTemplateInfo = photoTemplateInfoTemp
val file =
if (localPhotoTemplateInfo.needWaterMarker == true && ! aMapLocation?.address.isNullOrBlank()) {
val photoMarkerInfo = PhotoMarkerInfo(localPhotoTemplateInfo.needWaterMarker,
val file = if (localPhotoTemplateInfo.needWaterMarker == true) {
val photoMarkerInfo = PhotoMarkerInfo(needMark = true,
needShowPhoneBrand = localPhotoTemplateInfo.needShowPhoneBrand,
path = localPhotoTemplateInfo.photoLocalPath,
from = "(相机)",
@ -246,6 +262,7 @@ private fun handlerNormalPhoto(context : Context,
success : (PhotoTemplateInfo) -> Unit) {
LogUtil.print("handlerNormalPhoto", "photoTemplateInfo==${photoTemplateInfo.toJson()}")
val time = System.currentTimeMillis().minus(photoTemplateInfo.advanceTime ?: 0L)
val address = formatLocationAddress(aMapLocation = aMapLocation, context = context)
val photoTemplateInfoTemp = photoTemplateInfo.copy(photoLocalPath = path,
photoUploadPath = null,
realTakePhotoTime = TimeUtils.getNowString(),
@ -254,7 +271,7 @@ private fun handlerNormalPhoto(context : Context,
time = TimeUtils.millis2String(time),
lat = aMapLocation?.latitude?.toFloat(),
lng = aMapLocation?.longitude?.toFloat(),
address = aMapLocation?.address)
address = address)
LogUtil.print("本地照片拍好返回结果",
photoTemplateInfoTemp.toJson() ?: photoTemplateInfoTemp.toString())
success(photoTemplateInfoTemp)
@ -389,6 +406,8 @@ fun InServicingPhotoView(modifier : Modifier = Modifier,
?: 0),
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = photoTemplateInfo.getPhotoStatusColor())
Spacer(modifier = Modifier.width(10.dp))
@ -472,6 +491,8 @@ fun InServicingPhotoViewIsCanClick(modifier : Modifier = Modifier,
?: 0),
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = photoTemplateInfo.getPhotoStatusColor())
Spacer(modifier = Modifier.width(10.dp))
@ -548,6 +569,8 @@ fun InServicingPhotoWithoutTitleView(modifier : Modifier = Modifier,
?: 0),
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = photoTemplateInfo.getPhotoStatusColor())
Spacer(modifier = Modifier.width(10.dp))
@ -647,7 +670,6 @@ fun InServicingPhotoItemView(modifier : Modifier = Modifier,
aMapLocation.value = GlobalData.currentLocation
val intent = Intent(context, ZdCameraXActivity::class.java)
getResult.launch(intent)
ToastUtils.showShort(it)
LogUtil.print("上传图片定位获取失败",
"使用全局定位location==${GlobalData.currentLocation.toJson()}")
})
@ -676,7 +698,6 @@ fun InServicingPhotoItemView(modifier : Modifier = Modifier,
aMapLocation.value = GlobalData.currentLocation
val intent = Intent(context, ZdCameraXActivity::class.java)
getResult.launch(intent)
ToastUtils.showShort(it)
LogUtil.print("上传图片定位获取失败",
"使用全局定位location==${GlobalData.currentLocation.toJson()}")
})
@ -747,7 +768,6 @@ fun InServicingPhotoItemView(modifier : Modifier = Modifier,
aMapLocation.value = GlobalData.currentLocation
val intent = Intent(context, ZdCameraXActivity::class.java)
getResult.launch(intent)
ToastUtils.showShort(it)
LogUtil.print("上传图片定位获取失败",
"使用全局定位location==${GlobalData.currentLocation.toJson()}")
})

View File

@ -88,11 +88,16 @@ class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiStat
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(isNeedAddress = true, success = {
LoadingManager.hideLoading()
doUploadOfflineTask(it, tempPhotoList = tempPhotoList)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doUploadOfflineTask(GlobalData.currentLocation, tempPhotoList = tempPhotoList)
} else {
LogUtil.print("$tag updateOffline", "定位获取失败$it")
showTipDialog(it)
}
})
}
@ -141,7 +146,7 @@ class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiStat
private fun updateTask() {
if (uiState.value.photoTemplateList.isNullOrEmpty()) {
ToastUtils.showShort("现场照片不能为空")
showTipDialog("现场照片不能为空")
return
}
@ -151,7 +156,7 @@ class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiStat
return@forEach
}
if (it.doHaveFilm == 1 && it.photoLocalWaterMarkerPath.isNullOrBlank()) {
ToastUtils.showLong("请上传 ${it.imageTitle}")
showTipDialog("请上传 ${it.imageTitle}")
return
}
}
@ -168,7 +173,7 @@ class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiStat
return@forEach
}
if (it.photoUploadStatus == 4) {
ToastUtils.showLong("${it.photoName}正在上传,请等待照片上传完成!")
showTipDialog("${it.photoName}正在上传,请等待照片上传完成!")
return
}
if (! it.photoLocalWaterMarkerPath.isNullOrBlank() && it.photoUploadPath.isNullOrBlank()) {
@ -212,8 +217,25 @@ class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiStat
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
LogUtil.print("$tag updateTask", "定位获取失败==$it")
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateTask",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "CHECK_VEHICLE",
taskId = getCurrentOrder()?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = "EXAMINE",
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude,
address = GlobalData.currentLocation?.address,
templatePhotoInfoList = tempPhotoList.toList())
doUploadTask(request = taskRequest)
} else {
LogUtil.print("$tag updateTask", "全局定位获取失败==")
showTipDialog(it)
}
})
}
@ -226,9 +248,10 @@ class CheckVehicleVm : IServicingVm<CheckVehicleVm.Action, CheckVehicleVm.UiStat
LogUtil.print("$tag doUploadTask", "状态更新成功==$request")
}, failed = { msg, code ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true))
} else {
showTipDialog(msg ?: "状态更新失败")
}
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
})

View File

@ -40,7 +40,7 @@ class DeparturePhotoVm : IServicingVm<DeparturePhotoVm.Action, DeparturePhotoVm.
private fun updateTask() {
if (uiState.value.photoTemplateList.isNullOrEmpty()) {
ToastUtils.showShort("现场照片不能为空")
showTipDialog("现场照片不能为空!")
return
}
@ -50,7 +50,7 @@ class DeparturePhotoVm : IServicingVm<DeparturePhotoVm.Action, DeparturePhotoVm.
return@forEach
}
if (it.doHaveFilm == 1 && it.photoLocalWaterMarkerPath.isNullOrBlank()) {
ToastUtils.showLong("请上传 ${it.imageTitle}")
showTipDialog("请上传 ${it.imageTitle}")
return
}
}
@ -60,11 +60,11 @@ class DeparturePhotoVm : IServicingVm<DeparturePhotoVm.Action, DeparturePhotoVm.
return@forEach
}
if (it.photoUploadStatus == 4) {
ToastUtils.showLong("${it.photoName}正在上传,请等待照片上传完成!")
showTipDialog("${it.photoName}正在上传,请等待照片上传完成!")
return
}
if (! it.photoLocalWaterMarkerPath.isNullOrBlank() && it.photoUploadPath.isNullOrBlank()) {
ToastUtils.showLong("请上传 ${it.imageTitle}")
showTipDialog("请上传 ${it.imageTitle}")
return
}
}
@ -104,8 +104,25 @@ class DeparturePhotoVm : IServicingVm<DeparturePhotoVm.Action, DeparturePhotoVm.
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
LogUtil.print("$tag updateTask", "定位获取失败==$it")
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateTask",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "START",
taskId = getCurrentOrder()?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = GlobalData.currentOrder?.taskState,
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude,
address = GlobalData.currentLocation?.address,
templatePhotoInfoList = tempPhotoList.toList())
doUploadTask(request = taskRequest)
} else {
LogUtil.print("$tag updateTask", "全局定位获取失败==$it")
showTipDialog(it)
}
})
}
@ -118,7 +135,7 @@ class DeparturePhotoVm : IServicingVm<DeparturePhotoVm.Action, DeparturePhotoVm.
LogUtil.print("$tag doUploadTask", "状态更新成功==$request")
}, failed = { msg, code ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
showTipDialog(msg ?: "提交失败")
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
})
}

View File

@ -22,11 +22,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPhotoVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState: UiState) {
override fun updateState(uiState : UiState) {
_uiState.value = uiState
}
override fun dispatch(action: Action) {
override fun dispatch(action : Action) {
when (action) {
is Action.Init -> init()
is Action.UpdateTask -> updateTask()
@ -47,9 +47,9 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
return@forEachIndexed
}
if (!photoTemplateInfo.photoLocalWaterMarkerPath.isNullOrBlank() && photoTemplateInfo.photoUploadPath.isNullOrBlank()) {
val offlineUpdateTaskBean = OfflineUpdateTaskBean(
realTakePhotoTime = photoTemplateInfo.realTakePhotoTime,
if (! photoTemplateInfo.photoLocalWaterMarkerPath.isNullOrBlank() && photoTemplateInfo.photoUploadPath.isNullOrBlank()) {
val offlineUpdateTaskBean =
OfflineUpdateTaskBean(realTakePhotoTime = photoTemplateInfo.realTakePhotoTime,
photoSource = photoTemplateInfo.photoSource,
time = photoTemplateInfo.time,
imageLat = photoTemplateInfo.lat,
@ -89,18 +89,22 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
}
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(isNeedAddress = true,
success = {
ZdLocationManager.getSingleLocation(isNeedAddress = true, success = {
LoadingManager.hideLoading()
doUploadOfflineTask(it, tempPhotoList = tempPhotoList)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
LogUtil.print("$tag updateOffline", "定位获取失败$it")
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doUploadOfflineTask(GlobalData.currentLocation, tempPhotoList = tempPhotoList)
} else {
showTipDialog(it)
}
})
}
private fun doUploadOfflineTask(it: AMapLocation?, tempPhotoList: ArrayList<String?>) {
private fun doUploadOfflineTask(it : AMapLocation?, tempPhotoList : ArrayList<String?>) {
val taskRequest = UpdateTaskRequest(type = "DEST_PHOTO",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
@ -114,8 +118,7 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
address = it?.address,
templatePhotoInfoList = tempPhotoList.toList())
val offlineUpdateTaskBean = OfflineUpdateTaskBean(
type = taskRequest.type,
val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = taskRequest.type,
taskId = taskRequest.taskId,
userId = taskRequest.userId,
vehicleId = taskRequest.vehicleId,
@ -134,7 +137,8 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
offlineType = 1)
insertOfflineTask(offlineUpdateTaskBean)
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),
orderInfo = getCurrentOrder()))
}
private fun updateTask() {
@ -155,7 +159,7 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
}
//先判断是否有离线任务
if (!getCurrentOrderOfflineTask().isNullOrEmpty()) {
if (! getCurrentOrderOfflineTask().isNullOrEmpty()) {
updateOffline()
return
}
@ -170,7 +174,7 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
return
}
if (!it.photoLocalWaterMarkerPath.isNullOrBlank() && it.photoUploadPath.isNullOrBlank()) {
if (! it.photoLocalWaterMarkerPath.isNullOrBlank() && it.photoUploadPath.isNullOrBlank()) {
updateState(uiState.value.copy(showOfflineDialog = true))
return
}
@ -212,11 +216,29 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateTask",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "DEST_PHOTO",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
flowType = GlobalData.currentOrder?.flowType,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = "DESTPHOTO",
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude,
address = GlobalData.currentLocation?.address,
templatePhotoInfoList = tempPhotoList.toList())
doUploadTask(request = taskRequest)
} else {
showTipDialog(it)
}
})
}
private fun doUploadTask(request: UpdateTaskRequest) {
private fun doUploadTask(request : UpdateTaskRequest) {
LoadingManager.showLoading()
CommonMethod.updateTask(request, success = {
LoadingManager.hideLoading()
@ -243,16 +265,16 @@ class DestinationPhotoVm : IServicingVm<DestinationPhotoVm.Action, DestinationPh
sealed class Action {
data object Init : Action()
data object UpdateTask : Action()
data class UpdatePhotoTemplate(val photoTemplateInfo: PhotoTemplateInfo) : Action()
data class UpdateState(val uiState: UiState) : Action()
data class UpdatePhotoTemplate(val photoTemplateInfo : PhotoTemplateInfo) : Action()
data class UpdateState(val uiState : UiState) : Action()
data object UpdateOffline : Action()
}
data class UiState(val orderInfo: OrderInfo? = null,
val verifyValue: String? = null,
val goNextPage: UpdateTaskBean? = null,
val isGoNextPageDialog: Boolean? = null,
val showCallPhoneDialog: Boolean? = null,
val showOfflineDialog: Boolean? = null,
val photoTemplateList: List<PhotoTemplateInfo>? = null)
data class UiState(val orderInfo : OrderInfo? = null,
val verifyValue : String? = null,
val goNextPage : UpdateTaskBean? = null,
val isGoNextPageDialog : Boolean? = null,
val showCallPhoneDialog : Boolean? = null,
val showOfflineDialog : Boolean? = null,
val photoTemplateList : List<PhotoTemplateInfo>? = null)
}

View File

@ -41,6 +41,7 @@ import com.za.base.view.CommonDialog
import com.za.common.GlobalData
import com.za.common.util.ServicingSpeechManager
import com.za.ext.finish
import com.za.ext.getLastSix
import com.za.ext.goStatusPage
import com.za.servicing.R
import com.za.ui.servicing.view.InServicingHeadView
@ -73,6 +74,23 @@ fun EleSignScreen(vm : EleSignVm = viewModel()) {
})
}
if (uiState.value.signUploadFailedDialog == true) {
CommonDialog(cancelText = "取消",
confirmText = "离线上传",
title = "签名上传失败,是否进行离线上传?",
cancelEnable = true,
cancel = {
vm.dispatch(EleSignVm.Action.UpdateState(uiState.value.copy(signUploadFailedDialog = false)))
},
dismiss = {
vm.dispatch(EleSignVm.Action.UpdateState(uiState.value.copy(signUploadFailedDialog = false)))
},
confirm = {
vm.dispatch(EleSignVm.Action.UpdateState(uiState.value.copy(signUploadFailedDialog = false)))
vm.dispatch(EleSignVm.Action.SignUploadFailed)
})
}
if (uiState.value.goNextPage != null) {
uiState.value.orderInfo?.goStatusPage(context)
context.finish()
@ -152,7 +170,8 @@ fun EleSignScreen(vm : EleSignVm = viewModel()) {
Text(text = "车架号后6位", fontSize = 12.sp, color = black65)
Spacer(modifier = Modifier.width(5.dp))
Text(text = uiState.value.eleWorkOrderBean?.carVin ?: "",
Text(text = uiState.value.eleWorkOrderBean?.carVin?.getLastSix()
?: GlobalData.currentOrder?.carVin?.getLastSix() ?: "",
textDecoration = TextDecoration.Underline,
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
@ -214,10 +233,6 @@ fun EleSignScreen(vm : EleSignVm = viewModel()) {
Spacer(modifier = Modifier.height(10.dp))
}
item {
}
item {
Column(modifier = Modifier
.fillMaxWidth()

View File

@ -1,5 +1,7 @@
package com.za.ui.servicing.ele_sign
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.ToastUtils
import com.za.base.Const
import com.za.base.IServicingVm
@ -18,7 +20,10 @@ import com.za.offline.OfflineUpdateTaskBean
import com.za.room.RoomHelper
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
@ -35,10 +40,21 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
is Action.Upload -> upload()
is Action.UploadSignature -> uploadSignature(action.path)
is Action.UploadOffline -> uploadOffline()
is Action.SignUploadFailed -> uploadOfflineSignPhoto()
}
}
private fun uploadOfflineSignPhoto() {
val signOfflineUpdateTaskBean =
OfflineUpdateTaskBean(imageLocalPath = uiState.value.eleWorkOrderBean?.localCustomSignPath,
taskId = getCurrentOrder()?.taskId,
taskCode = getCurrentOrder()?.taskCode,
offlineTitle = "电子工单-客户签名照片",
offlineType = 5)
insertOfflineTask(signOfflineUpdateTaskBean)
}
private fun uploadOffline() {
val eleWorkOrderBean =
RoomHelper.db?.eleWorkOrderDao()?.getEleWorkOrder(getCurrentOrder()?.taskId ?: 0)
@ -57,7 +73,6 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
insertOfflineTask(signOfflineUpdateTaskBean)
}
val offlineUpdateTaskBean = OfflineUpdateTaskBean(taskId = getCurrentOrder()?.taskId,
taskCode = getCurrentOrder()?.taskCode,
customerSignPath = uiState.value.eleWorkOrderBean?.serverCustomSignPath,
@ -89,6 +104,17 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
}
}, failed = {
LoadingManager.hideLoading()
viewModelScope.launch(Dispatchers.IO) {
if (! NetworkUtils.isAvailable()) {
withContext(Dispatchers.Main) {
updateState(uiState.value.copy(signUploadFailedDialog = true))
}
} else {
withContext(Dispatchers.Main) {
showTipDialog(msg = "签名上传失败,请重新签名上传!")
}
}
}
LogUtil.print("uploadSignature", "failed==$it")
})
}
@ -134,9 +160,10 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
override fun doFailure(code : Int, msg : String?) {
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true))
} else {
showTipDialog(msg ?: "数据提交异常")
}
LogUtil.print("eleSign upload failed", msg ?: "")
}
@ -155,7 +182,7 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
LogUtil.print("电子表单更新车辆损伤照片", "eleWorkOrderBean==${it.toJson()}")
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort("数据加载异常,请返回重试!")
showTipDialog(msg = "数据加载异常,请返回重试!")
})
}
@ -164,6 +191,7 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
data class UpdateState(val uiState : UiState) : Action()
data object Upload : Action()
data object UploadOffline : Action()
data object SignUploadFailed : Action()
data class UploadSignature(val path : String) : Action()
}
@ -174,6 +202,7 @@ class EleSignVm : IServicingVm<EleSignVm.Action, EleSignVm.UiState>() {
val isGoNextPageDialog : Boolean? = null,
val showCallPhoneDialog : Boolean? = null,
val showOfflineDialog : Boolean? = null,
val signUploadFailedDialog : Boolean? = null,
val damagePhoto : List<EleCarDamagePhotoBean>? = null,
)
}

View File

@ -5,7 +5,9 @@ import android.os.Handler
import android.os.Looper
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api
@ -14,10 +16,13 @@ import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.material3.rememberStandardBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle
@ -33,11 +38,11 @@ import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.LatLngBounds
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.PolylineOptions
import com.blankj.utilcode.util.ConvertUtils
import com.za.base.BaseActivity
import com.za.base.view.CommonDialog
import com.za.common.GlobalData
import com.za.common.util.ImageUtil
import com.za.ext.convertToFlowName
import com.za.ext.finish
import com.za.ext.goNextPage
import com.za.servicing.R
@ -110,6 +115,30 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
})
}
if (uiState.value.showOfflineDialog == true) {
CommonDialog(cancelText = "取消",
confirmText = "离线上传",
title = "任务提交失败,是否离线提交?",
cancelEnable = true,
cancel = {
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(
showOfflineDialog = false)))
},
dismiss = {
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(
showOfflineDialog = false)))
},
confirm = {
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(
showOfflineDialog = false)))
vm.dispatch(GoAccidentSiteVm.Action.UpdateOffline)
})
}
var sheetExpandHeight = remember { mutableStateOf(0.dp) }
val localDensity = LocalDensity.current
BottomSheetScaffold(scaffoldState = scaffoldState,
topBar = {
InServicingHeadView(title = "救援车发车,正在赶往现场",
@ -127,10 +156,17 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
bottomTextString = "到达事发地",
expectArriveTime = uiState.value.orderInfo?.expectArriveTime,
uiType = NewOrderUiType.SERVICING)
Box(modifier = Modifier
.fillMaxWidth()
.onSizeChanged { coordinates ->
sheetExpandHeight.value = with(localDensity) { coordinates.height.toDp() }
}) {
NewOrderItem(uiBean, goNextPage = {
vm.dispatch(GoAccidentSiteVm.Action.UpdateState(uiState.value.copy(
isGoNextPageDialog = true)))
})
}
},
sheetPeekHeight = 180.dp,
sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
@ -138,8 +174,13 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
sheetDragHandle = null,
sheetSwipeEnabled = true) { paddingValues ->
Box(modifier = Modifier
.fillMaxSize()
.padding(paddingValues)) {
.wrapContentSize()
.padding(top = paddingValues.calculateTopPadding(),
bottom = if (bottomSheetState.currentValue == SheetValue.PartiallyExpanded) {
0.dp
} else {
sheetExpandHeight.value
})) {
AndroidView(modifier = Modifier.fillMaxSize(), factory = {
AMapLocationClient.updatePrivacyShow(context, true, true)
AMapLocationClient.updatePrivacyAgree(context, true)
@ -171,6 +212,8 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
.zIndex(1f))
}
mapView.map.addMarkers(uiState.value.markers, false)
// 添加当前位置标记
if (GlobalData.currentLocation != null) {
mapView.map.addMarker(MarkerOptions().position(LatLng(GlobalData.currentLocation?.latitude !!,
@ -179,43 +222,16 @@ fun GoAccidentSiteScreen(vm : GoAccidentSiteVm = viewModel()) {
.anchor(0.5f, 0.5f).visible(true))
}
// 添加救援地标记
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
mapView.map.addMarker(MarkerOptions().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 && order.distLng != null && order.distLng != 0.0) {
mapView.map.addMarker(MarkerOptions().position(LatLng(order.distLat !!,
order.distLng !!)).title("目的地")
.icon(ImageUtil.vectorToBitmap(context, R.drawable.sv_map_dist))
.anchor(0.5f, 0.5f))
}
}
// 调整地图显示范围
// 计算地图显示范围
val bounds = LatLngBounds.Builder().apply {
GlobalData.currentLocation?.let {
uiState.value.routePoints?.forEach {
include(LatLng(it.latitude, it.longitude))
}
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
include(LatLng(order.lat !!, order.lng !!))
}
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
include(LatLng(order.distLat !!, order.distLng !!))
}
}
}.build()
try {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100))
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,
ConvertUtils.dp2px(100f)))
} catch (e : Exception) {
GlobalData.currentLocation?.let {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(it.latitude,

View File

@ -1,5 +1,6 @@
package com.za.ui.servicing.go_accident
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMapUtils
import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.LatLng
@ -11,7 +12,6 @@ import com.amap.api.services.route.RideRouteResult
import com.amap.api.services.route.RouteSearch
import com.amap.api.services.route.WalkRouteResult
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.ToastUtils
import com.za.base.Const
import com.za.base.IServicingVm
import com.za.base.view.LoadingManager
@ -55,6 +55,21 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = {
LoadingManager.hideLoading()
doUploadOfflineTask(taskRequest, it)
}, failed = {
LoadingManager.hideLoading()
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doUploadOfflineTask(taskRequest, GlobalData.currentLocation)
} else {
showTipDialog(it)
}
})
}
private fun doUploadOfflineTask(taskRequest : UpdateTaskRequest? = null,
location : AMapLocation? = null) {
val temp = taskRequest ?: UpdateTaskRequest(type = "VERIFY",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
@ -62,8 +77,8 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
currentState = GlobalData.currentOrder?.taskState,
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = it.latitude,
lng = it.longitude)
lat = location?.latitude,
lng = location?.longitude)
val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = temp.type,
taskId = temp.taskId,
@ -83,10 +98,6 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus()))
updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState),
orderInfo = getCurrentOrder()))
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
})
}
private fun updateTask() {
@ -105,7 +116,23 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "VERIFY",
taskId = getCurrentOrder()?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = getCurrentOrder()?.taskState,
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude)
doUploadTask(request = taskRequest)
} else {
LogUtil.print("$tag updateTask", "全局定位获取失败$it")
showTipDialog(it)
}
})
}
@ -122,11 +149,13 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder()))
}, failed = { msg, code ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true))
} else {
showTipDialog(msg ?: "提交失败")
}
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
LogUtil.print("$tag doUploadTask",
"状态更新失败==${request.toJson()} msg==$msg code==$code")
})
}
@ -148,10 +177,11 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
}
if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
val startMarkers =
MarkerOptions().icon(ImageUtil.vectorToBitmap(ActivityUtils.getTopActivity(), R.drawable.sv_map_dist))
val destMarker =
MarkerOptions().icon(ImageUtil.vectorToBitmap(ActivityUtils.getTopActivity(),
R.drawable.sv_map_dist))
.position(LatLng(orderInfo.distLat !!, orderInfo.distLng !!)).visible(true)
markers.add(startMarkers)
markers.add(destMarker)
}
updateState(uiState.value.copy(markers = markers))
}
@ -159,7 +189,7 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
private fun searchDrivingRoute(orderInfo : OrderInfo?) { // 如果没有当前位置,则不进行路径规划
if (GlobalData.currentLocation == null) return
val currentPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
val startPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
GlobalData.currentLocation?.longitude ?: 0.0)
// 获取救援地点坐标
@ -168,6 +198,12 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
LatLonPoint(orderInfo.lat !!, orderInfo.lng !!)
} else null
// 获取救援地点坐标
val disPoint =
if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
LatLonPoint(orderInfo.distLat !!, orderInfo.distLng !!)
} else null
// 如果没有救援地点,则不进行规划
if (rescuePoint == null) return
@ -197,11 +233,24 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
override fun onRideRouteSearched(p0 : RideRouteResult?, p1 : Int) {}
})
// 规划当前位置到救援地的路线
val query = RouteSearch.FromAndTo(currentPoint, rescuePoint)
val driveQuery =
RouteSearch.DriveRouteQuery(query, RouteSearch.DrivingDefault, null, null, "")
routeSearch.calculateDriveRouteAsyn(driveQuery)
if (disPoint != null) {
val fromAndTo = RouteSearch.FromAndTo(startPoint, disPoint)
val wayPoints = listOf(rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
wayPoints,
null,
"")
routeSearch.calculateDriveRouteAsyn(query)
} else {
val fromAndTo = RouteSearch.FromAndTo(startPoint, rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
null,
null,
"")
routeSearch.calculateDriveRouteAsyn(query)
}
}
private fun calculateRemainingDistance() : Pair<Float, String> {
@ -229,17 +278,16 @@ class GoAccidentSiteVm : IServicingVm<GoAccidentSiteVm.Action, GoAccidentSiteVm.
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() { // timerJob?.cancel()
// timerJob = viewModelScope.launch {
// while (isActive) {
// val (distance, arrivalTime) = calculateRemainingDistance()
// _uiState.update {
// it.copy(remainingDistance = distance, estimatedArrivalTime = arrivalTime)
// }
// delay(1000)
// }
// }
}
override fun onCleared() {

View File

@ -3,53 +3,33 @@ package com.za.ui.servicing.go_to_destination
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
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.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.SheetValue
import androidx.compose.material3.Text
import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.material3.rememberStandardBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import com.amap.api.location.AMapLocationClient
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.MapView
@ -58,19 +38,17 @@ import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.LatLngBounds
import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.PolylineOptions
import com.blankj.utilcode.util.ConvertUtils
import com.za.base.BaseActivity
import com.za.base.theme.headBgColor
import com.za.base.view.CommonDialog
import com.za.common.GlobalData
import com.za.common.util.ImageUtil
import com.za.ext.copy
import com.za.ext.finish
import com.za.ext.goNextPage
import com.za.servicing.R
import com.za.ui.new_order.NewOrderItem
import com.za.ui.new_order.NewOrderItemUIBean
import com.za.ui.new_order.NewOrderUiType
import com.za.ui.new_order.NewOrderVm
import com.za.ui.servicing.view.InServicingHeadView
import com.za.ui.servicing.view.ServiceOperation
@ -89,26 +67,11 @@ fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
val lifecycleOwner = LocalLifecycleOwner.current
val mapView = remember { MapView(context) }
// 添加协程作用域
val scope = rememberCoroutineScope()
// 修改 BottomSheet 状态
val bottomSheetState =
rememberStandardBottomSheetState(initialValue = SheetValue.PartiallyExpanded,
confirmValueChange = { true })
val bottomSheetState = rememberStandardBottomSheetState(initialValue = SheetValue.Expanded)
val scaffoldState = rememberBottomSheetScaffoldState(bottomSheetState = bottomSheetState)
// 优化状态管理
val isExpanded by remember {
derivedStateOf { bottomSheetState.currentValue == SheetValue.Expanded }
}
// 记忆化常用值,减少重组
val orderInfo = remember(uiState.value.orderInfo) { uiState.value.orderInfo }
val estimatedTime =
remember(uiState.value.estimatedArrivalTime) { uiState.value.estimatedArrivalTime }
val remainingDistance =
remember(uiState.value.remainingDistance) { uiState.value.remainingDistance }
DisposableEffect(key1 = lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
@ -176,6 +139,9 @@ fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
})
}
var sheetExpandHeight = remember { mutableStateOf(0.dp) }
val localDensity = LocalDensity.current
BottomSheetScaffold(scaffoldState = scaffoldState,
topBar = {
InServicingHeadView(title = "作业完成,正在拖往目的地",
@ -193,11 +159,16 @@ fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
expectArriveTime = uiState.value.orderInfo?.expectArriveTime,
bottomTextString = "到达目的地",
uiType = NewOrderUiType.SERVICING)
Box(modifier = Modifier
.fillMaxWidth()
.onSizeChanged { coordinates ->
sheetExpandHeight.value = with(localDensity) { coordinates.height.toDp() }
}) {
NewOrderItem(uiBean, goNextPage = {
vm.dispatch(GoToDestinationVm.Action.UpdateState(uiState.value.copy(
isGoNextPageDialog = true)))
})
}
},
sheetPeekHeight = 180.dp,
sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
@ -205,8 +176,13 @@ fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
sheetDragHandle = null,
sheetSwipeEnabled = true) { paddingValues ->
Box(modifier = Modifier
.fillMaxSize()
.padding(paddingValues)) {
.wrapContentSize()
.padding(top = paddingValues.calculateTopPadding(),
bottom = if (bottomSheetState.currentValue == SheetValue.PartiallyExpanded) {
0.dp
} else {
sheetExpandHeight.value
})) {
AndroidView(modifier = Modifier.fillMaxSize(), factory = {
AMapLocationClient.updatePrivacyShow(context, true, true)
AMapLocationClient.updatePrivacyAgree(context, true)
@ -231,14 +207,15 @@ fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
}, update = { // 清除旧标记和路线
mapView.map.clear()
// 绘制路线
// 绘制路线
uiState.value.routePoints?.let { points ->
mapView.map.addPolyline(PolylineOptions().addAll(points).width(15f)
.setCustomTexture(BitmapDescriptorFactory.fromResource(R.drawable.icon_road_green_arrow))
.zIndex(1f))
}
// 再添加标记点,确保标记点在路线上层
mapView.map.addMarkers(uiState.value.markers, false)
// 添加当前位置标记
if (GlobalData.currentLocation != null) {
mapView.map.addMarker(MarkerOptions().position(LatLng(GlobalData.currentLocation?.latitude !!,
@ -247,44 +224,16 @@ fun GoToDestinationScreen(vm : GoToDestinationVm = viewModel()) {
.anchor(0.5f, 0.5f).visible(true))
}
// 添加救援地标记
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
mapView.map.addMarker(MarkerOptions().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 && order.distLng != null && order.distLng != 0.0) {
mapView.map.addMarker(MarkerOptions().position(LatLng(order.distLat !!,
order.distLng !!)).title("目的地")
.icon(ImageUtil.vectorToBitmap(context, R.drawable.sv_map_dist))
.anchor(0.5f, 0.5f))
}
}
// 调整地图显示范围
val bounds = LatLngBounds.Builder().apply { // 添加当前位置
GlobalData.currentLocation?.let {
// 计算地图显示范围
val bounds = LatLngBounds.Builder().apply {
uiState.value.routePoints?.forEach {
include(LatLng(it.latitude, it.longitude))
}
// 添加救援地点和目的地
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
include(LatLng(order.lat !!, order.lng !!))
}
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
include(LatLng(order.distLat !!, order.distLng !!))
}
}
}.build()
try {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 100))
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,
ConvertUtils.dp2px(100f)))
} catch (e : Exception) { // 如果计算边界失败,则使用默认缩放级别
GlobalData.currentLocation?.let {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(it.latitude,

View File

@ -1,9 +1,18 @@
package com.za.ui.servicing.go_to_destination
import androidx.lifecycle.viewModelScope
import com.amap.api.location.AMapLocation
import com.amap.api.maps.AMapUtils
import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.LatLng
import com.amap.api.maps.model.MarkerOptions
import com.blankj.utilcode.util.ToastUtils
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.route.BusRouteResult
import com.amap.api.services.route.DriveRouteResult
import com.amap.api.services.route.RideRouteResult
import com.amap.api.services.route.RouteSearch
import com.amap.api.services.route.WalkRouteResult
import com.blankj.utilcode.util.ActivityUtils
import com.za.base.Const
import com.za.base.IServicingVm
import com.za.base.view.LoadingManager
@ -12,25 +21,16 @@ import com.za.bean.request.UpdateTaskBean
import com.za.bean.request.UpdateTaskRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.common.util.ImageUtil
import com.za.ext.getNextStatus
import com.za.ext.toJson
import com.za.net.CommonMethod
import com.za.offline.OfflineUpdateTaskBean
import com.za.service.location.ZdLocationManager
import com.za.servicing.R
import kotlinx.coroutines.flow.MutableStateFlow
import androidx.lifecycle.viewModelScope
import com.amap.api.maps.AMapUtils
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.route.BusRouteResult
import com.amap.api.services.route.DriveRouteResult
import com.amap.api.services.route.RideRouteResult
import com.amap.api.services.route.RouteSearch
import com.amap.api.services.route.WalkRouteResult
import com.blankj.utilcode.util.ActivityUtils
import com.za.common.util.ImageUtil
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
@ -60,6 +60,22 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = {
LoadingManager.hideLoading()
doUploadOffline(taskRequest, it)
}, failed = {
LoadingManager.hideLoading()
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doUploadOffline(taskRequest, GlobalData.currentLocation)
} else {
LogUtil.print("$tag updateOfflineTask", "全局定位获取失败$it")
showTipDialog(it)
}
})
}
private fun doUploadOffline(taskRequest : UpdateTaskRequest? = null,
location : AMapLocation? = null) {
val temp = taskRequest ?: UpdateTaskRequest(type = "ARRIVE_DEST",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
@ -68,8 +84,8 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
currentState = GlobalData.currentOrder?.taskState,
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = it.latitude,
lng = it.longitude)
lat = location?.latitude,
lng = location?.longitude)
val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = temp.type,
taskId = temp.taskId,
@ -90,13 +106,8 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus()))
updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState),
orderInfo = getCurrentOrder()))
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
})
}
private fun updateTask() {
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = {
@ -114,7 +125,24 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "ARRIVE_DEST",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
flowType = GlobalData.currentOrder?.flowType,
currentState = GlobalData.currentOrder?.taskState,
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude)
doUploadTask(request = taskRequest)
} else {
LogUtil.print("$tag updateTask", "全局定位获取失败$it")
showTipDialog(it)
}
})
}
@ -130,9 +158,10 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder()))
}, failed = { msg, code ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true))
} else {
showTipDialog(msg ?: "提交失败")
}
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
})
@ -141,23 +170,29 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
private fun init() {
updateState(uiState = uiState.value.copy(orderInfo = getCurrentOrder()))
buildMarkers(getCurrentOrder())
searchDrivingRoute(getCurrentOrder()) // dispatch(Action.StartTimer)
searchDrivingRoute(getCurrentOrder())
}
private fun searchDrivingRoute(orderInfo : OrderInfo?) { // 如果没有当前位置,则不进行路径规划
if (GlobalData.currentLocation == null) return
val currentPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
val startPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
GlobalData.currentLocation?.longitude ?: 0.0)
// 获取目的地坐标
val destPoint =
// 获取救援地点坐标
val rescuePoint =
if (orderInfo?.lat != null && orderInfo.lat != 0.0 && orderInfo.lng != null && orderInfo.lng != 0.0) {
LatLonPoint(orderInfo.lat !!, orderInfo.lng !!)
} else null
// 获取救援地点坐标
val disPoint =
if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
LatLonPoint(orderInfo.distLat !!, orderInfo.distLng !!)
} else null
// 如果没有目的地,则不进行规划
if (destPoint == null) return
// 如果没有救援地点,则不进行规划
if (rescuePoint == null) return
// 使用 Application Context 创建路由搜索对象
val routeSearch = RouteSearch(GlobalData.application)
@ -185,11 +220,24 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
override fun onRideRouteSearched(p0 : RideRouteResult?, p1 : Int) {}
})
// 规划当前位置到目的地的路线
val query = RouteSearch.FromAndTo(currentPoint, destPoint)
val driveQuery =
RouteSearch.DriveRouteQuery(query, RouteSearch.DrivingDefault, null, null, "")
routeSearch.calculateDriveRouteAsyn(driveQuery)
if (disPoint != null) {
val fromAndTo = RouteSearch.FromAndTo(startPoint, disPoint)
val wayPoints = listOf(rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
wayPoints,
null,
"")
routeSearch.calculateDriveRouteAsyn(query)
} else {
val fromAndTo = RouteSearch.FromAndTo(startPoint, rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
null,
null,
"")
routeSearch.calculateDriveRouteAsyn(query)
}
}
private fun calculateRemainingDistance() : Pair<Float, String> {
@ -246,10 +294,11 @@ class GoToDestinationVm : IServicingVm<GoToDestinationVm.Action, GoToDestination
}
if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
val startMarkers =
MarkerOptions().icon(ImageUtil.vectorToBitmap(ActivityUtils.getTopActivity(), R.drawable.sv_map_dist))
val destMarker =
MarkerOptions().icon(ImageUtil.vectorToBitmap(ActivityUtils.getTopActivity(),
R.drawable.sv_map_dist))
.position(LatLng(orderInfo.distLat !!, orderInfo.distLng !!)).visible(true)
markers.add(startMarkers)
markers.add(destMarker)
}
updateState(uiState.value.copy(markers = markers))
}

View File

@ -146,6 +146,24 @@ private fun OrderDetailBaseInformationView(orderInfo : OrderInfo?) {
})
}
//拖车责任险
if (! orderInfo?.externalCode.isNullOrBlank()) {
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically) {
Text(text = "流水号",
color = titleColor,
fontSize = titleSize,
fontWeight = FontWeight.Medium,
modifier = Modifier.width(75.dp))
Spacer(modifier = Modifier.width(5.dp))
Text(text = "${orderInfo?.externalCode}",
color = contentColor,
fontSize = titleSize,
fontWeight = FontWeight.Medium)
}
}
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "客户姓名",
@ -168,6 +186,25 @@ private fun OrderDetailBaseInformationView(orderInfo : OrderInfo?) {
modifier = Modifier.size(10.dp))
}
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "是否新车",
color = titleColor,
fontSize = titleSize,
fontWeight = FontWeight.Medium,
modifier = Modifier.width(75.dp))
Spacer(modifier = Modifier.width(5.dp))
Text(text = "".takeIf { orderInfo?.isNewCar == true } ?: "",
color = contentColor,
fontSize = titleSize,
fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.width(5.dp))
AsyncImage(model = R.drawable.sv_copy,
contentDescription = "",
modifier = Modifier.size(15.dp))
}
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "客户车牌号",
@ -186,6 +223,24 @@ private fun OrderDetailBaseInformationView(orderInfo : OrderInfo?) {
modifier = Modifier.size(15.dp))
}
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "客户车架号",
color = titleColor,
fontSize = titleSize,
fontWeight = FontWeight.Medium,
modifier = Modifier.width(75.dp))
Spacer(modifier = Modifier.width(5.dp))
Text(text = "${orderInfo?.carVin}",
color = contentColor,
fontSize = titleSize,
fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.width(5.dp))
AsyncImage(model = R.drawable.sv_copy,
contentDescription = "",
modifier = Modifier.size(15.dp))
}
if (! orderInfo?.carModel.isNullOrBlank()) {
Spacer(modifier = Modifier.height(10.dp))

View File

@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -25,13 +26,19 @@ 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
import com.za.base.theme.buttonBgColor
import com.za.base.theme.headBgColor
import com.za.base.theme.white80
import com.za.base.view.CommonButton
import com.za.base.view.HeadView
import com.za.bean.db.order.OrderInfo
import com.za.ext.finish
import com.za.ext.navigationActivity
import com.za.ext.noDoubleClick
import com.za.ui.order_report.OrderReportActivity
import com.za.ui.servicing.order_give_up.OrderGiveUpActivity
import kotlinx.coroutines.launch
@ -44,12 +51,49 @@ fun OrderDetailScreen(orderInfo : OrderInfo?) {
Scaffold(topBar = {
HeadView(title = "订单信息", onBack = { context.finish() })
}, bottomBar = {
CommonButton(text = "客户放弃") {
Row(modifier = Modifier
.fillMaxWidth()
.height(60.dp)
.padding(vertical = 5.dp, horizontal = 12.dp)) {
Box(modifier = Modifier
.weight(1f)
.height(60.dp)
.noDoubleClick { // val url =
// "${AppConfig.BASE_URL}/h5/supplier/dispatch/reportIndex?userOrderId=${GlobalData.currentOrder?.userOrderId}&type=2&userOrderCode=${GlobalData.currentOrder?.taskCode}&driverId=${GlobalData.driverInfoBean?.userId}"
//
// CommonH5Activity.goH5Activity(context, url, "")
context.navigationActivity(OrderReportActivity::class.java)
}
.background(color = Color.Red.copy(alpha = 0.7f), shape = RoundedCornerShape(4.dp))
.padding(vertical = 8.dp), contentAlignment = Alignment.Center) {
Text(text = "报备",
color = Color.White,
fontSize = 15.sp,
fontWeight = FontWeight.Medium,
style = TextStyle.Default.copy())
}
Spacer(modifier = Modifier.width(10.dp))
Box(modifier = Modifier
.weight(2f)
.height(60.dp)
.noDoubleClick {
OrderGiveUpActivity.goOrderGiveUpActivity(context,
orderInfo = orderInfo,
userOrderId = orderInfo?.userOrderId,
giveUpType = 0)
}
.background(color = buttonBgColor, shape = RoundedCornerShape(4.dp))
.padding(vertical = 8.dp), contentAlignment = Alignment.Center) {
Text(text = "客户放弃",
color = Color.White,
fontSize = 15.sp,
fontWeight = FontWeight.Medium,
style = TextStyle.Default.copy())
}
}
}) {
Column(modifier = Modifier
.fillMaxSize()

View File

@ -124,6 +124,7 @@ fun CarModeView(orderInfo : OrderInfo?) {
@Composable
fun OrderTaskNotesDialog(taskNotesBean : TaskNotesBean?,
orderSource : String? = null,
isShowChangeBattery : Boolean? = false,
dismiss : () -> Unit,
confirm : () -> Unit) {
@ -137,7 +138,7 @@ fun OrderTaskNotesDialog(taskNotesBean : TaskNotesBean?,
.fillMaxWidth()
.wrapContentHeight()
.verticalScroll(state = rememberScrollState())
.padding(horizontal = 10.dp),
.padding(horizontal = 5.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top) {
Spacer(modifier = Modifier.height(20.dp))
@ -152,7 +153,7 @@ fun OrderTaskNotesDialog(taskNotesBean : TaskNotesBean?,
Spacer(Modifier.weight(1f))
Text("平安保险",
Text(orderSource ?: "",
color = Color.Black,
fontSize = 15.sp,
fontWeight = FontWeight.Bold)
@ -162,26 +163,27 @@ fun OrderTaskNotesDialog(taskNotesBean : TaskNotesBean?,
if (! taskNotesBean?.otherNotes.isNullOrBlank()) {
OrderRequirementsItemView(title = "特殊提醒",
content = taskNotesBean?.otherNotes)
content = taskNotesBean?.otherNotes ?: "")
}
if (! taskNotesBean?.feeStandard.isNullOrBlank()) {
OrderRequirementsItemView(title = "收费标准",
content = taskNotesBean?.feeStandard)
content = taskNotesBean?.feeStandard ?: "")
}
if (! taskNotesBean?.modelVinNo.isNullOrBlank()) {
OrderRequirementsItemView(title = "车型", content = taskNotesBean?.modelVinNo)
OrderRequirementsItemView(title = "车型",
content = taskNotesBean?.modelVinNo ?: "")
}
if (! taskNotesBean?.taskNotes.isNullOrBlank()) {
OrderRequirementsItemView(title = "救援要求",
content = taskNotesBean?.taskNotes)
content = taskNotesBean?.taskNotes ?: "")
}
if (! taskNotesBean?.customerNotes.isNullOrBlank()) {
OrderRequirementsItemView(title = "客户要求",
content = taskNotesBean?.customerNotes)
content = taskNotesBean?.customerNotes ?: "")
}
if (isShowChangeBattery == true) {

View File

@ -1,6 +1,5 @@
package com.za.ui.servicing.inservice_people_confirm
import com.blankj.utilcode.util.ToastUtils
import com.za.base.IServicingVm
import com.za.base.view.LoadingManager
import com.za.bean.db.order.OrderInfo
@ -40,7 +39,6 @@ class InServicePeopleConfirmVm : IServicingVm<Action, UiState>() {
}
}
private fun updateTask() {
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = {
@ -57,7 +55,23 @@ class InServicePeopleConfirmVm : IServicingVm<Action, UiState>() {
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "START",
taskId = getCurrentOrder()?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = getCurrentOrder()?.taskState,
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude)
doUploadTask(request = taskRequest)
} else {
LogUtil.print("$tag updateTask", "使用全局定位失败$it")
showTipDialog(it)
}
})
}
@ -69,7 +83,7 @@ class InServicePeopleConfirmVm : IServicingVm<Action, UiState>() {
updateState(uiState.value.copy(goNextPage = data, orderInfo = getCurrentOrder()))
}, failed = { msg, _ ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
showTipDialog(msg ?: "提交失败")
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
})
}
@ -77,7 +91,7 @@ class InServicePeopleConfirmVm : IServicingVm<Action, UiState>() {
private fun comparePeople(url : String?) {
if (url.isNullOrBlank()) {
ToastUtils.showLong("图片路径为空!")
showTipDialog("图片路径为空!")
return
}
LoadingManager.showLoading()

View File

@ -22,11 +22,11 @@ import kotlinx.coroutines.flow.MutableStateFlow
class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState: UiState) {
override fun updateState(uiState : UiState) {
_uiState.value = uiState
}
override fun dispatch(action: Action) {
override fun dispatch(action : Action) {
when (action) {
is Action.Init -> init()
is Action.UpdateTask -> updateTask()
@ -48,9 +48,9 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
return@forEachIndexed
}
if (!photoTemplateInfo.photoLocalWaterMarkerPath.isNullOrBlank() && photoTemplateInfo.photoUploadPath.isNullOrBlank()) {
val offlineUpdateTaskBean = OfflineUpdateTaskBean(
realTakePhotoTime = photoTemplateInfo.realTakePhotoTime,
if (! photoTemplateInfo.photoLocalWaterMarkerPath.isNullOrBlank() && photoTemplateInfo.photoUploadPath.isNullOrBlank()) {
val offlineUpdateTaskBean =
OfflineUpdateTaskBean(realTakePhotoTime = photoTemplateInfo.realTakePhotoTime,
photoSource = photoTemplateInfo.photoSource,
time = photoTemplateInfo.time,
imageLat = photoTemplateInfo.lat,
@ -91,18 +91,23 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
}
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(isNeedAddress = true,
success = {
ZdLocationManager.getSingleLocation(isNeedAddress = true, success = {
LoadingManager.hideLoading()
doUploadOfflineTask(it, tempPhotoList = tempPhotoList)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
LogUtil.print("$tag updateOffline", "定位获取失败$it")
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doUploadOfflineTask(GlobalData.currentLocation, tempPhotoList = tempPhotoList)
} else {
LogUtil.print("$tag updateOffline", "全局定位获取失败$it")
showTipDialog(it)
}
})
}
private fun doUploadOfflineTask(it: AMapLocation?, tempPhotoList: ArrayList<String?>) {
private fun doUploadOfflineTask(it : AMapLocation?, tempPhotoList : ArrayList<String?>) {
val taskRequest = UpdateTaskRequest(type = "OPERATION",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
@ -116,9 +121,8 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
address = it?.address,
templatePhotoInfoList = tempPhotoList.toList())
if (!getCurrentOrderOfflineTask().isNullOrEmpty()) {
val offlineUpdateTaskBean = OfflineUpdateTaskBean(
type = taskRequest.type,
if (! getCurrentOrderOfflineTask().isNullOrEmpty()) {
val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = taskRequest.type,
taskId = taskRequest.taskId,
userId = taskRequest.userId,
vehicleId = taskRequest.vehicleId,
@ -138,13 +142,14 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
insertOfflineTask(offlineUpdateTaskBean)
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),
orderInfo = getCurrentOrder()))
}
}
private fun updateTask() {
if (uiState.value.photoTemplateList.isNullOrEmpty()) {
ToastUtils.showShort("作业照片不能为空!")
showTipDialog("作业照片不能为空!")
return
}
@ -154,13 +159,13 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
return@forEach
}
if (it.doHaveFilm == 1 && it.photoLocalWaterMarkerPath.isNullOrBlank()) {
ToastUtils.showLong("请上传 ${it.imageTitle}")
showTipDialog("请上传 ${it.imageTitle}")
return
}
}
//先判断是否有离线任务
if (!getCurrentOrderOfflineTask().isNullOrEmpty()) {
if (! getCurrentOrderOfflineTask().isNullOrEmpty()) {
updateOffline()
return
}
@ -171,11 +176,11 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
}
if (it.photoUploadStatus == 4) {
ToastUtils.showLong("${it.photoName}正在上传,请等待照片上传完成!")
showTipDialog("${it.photoName}正在上传,请等待照片上传完成!")
return
}
if (!it.photoLocalWaterMarkerPath.isNullOrBlank() && it.photoUploadPath.isNullOrBlank()) {
if (! it.photoLocalWaterMarkerPath.isNullOrBlank() && it.photoUploadPath.isNullOrBlank()) {
updateState(uiState.value.copy(showOfflineDialog = true))
return
}
@ -217,22 +222,42 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "OPERATION",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
flowType = GlobalData.currentOrder?.flowType,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = "OPERATION",
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude,
address = GlobalData.currentLocation?.address,
templatePhotoInfoList = tempPhotoList.toList())
doUploadTask(request = taskRequest)
} else {
LogUtil.print("$tag updateOffline", "全局定位获取失败$it")
showTipDialog(it)
}
})
}
private fun doUploadTask(request: UpdateTaskRequest) {
private fun doUploadTask(request : UpdateTaskRequest) {
LoadingManager.showLoading()
CommonMethod.updateTask(request, success = {
LoadingManager.hideLoading()
updateOrder(getCurrentOrder()?.copy(taskState = it?.nextState))
updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder()))
}, failed = { msg, code ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true))
} else {
showTipDialog(msg ?: "提交失败")
}
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
})
@ -250,16 +275,16 @@ class InOperationVm : IServicingVm<InOperationVm.Action, InOperationVm.UiState>(
sealed class Action {
data object Init : Action()
data object UpdateTask : Action()
data class UpdatePhotoTemplate(val photoTemplateInfo: PhotoTemplateInfo) : Action()
data class UpdateState(val uiState: UiState) : Action()
data class UpdatePhotoTemplate(val photoTemplateInfo : PhotoTemplateInfo) : Action()
data class UpdateState(val uiState : UiState) : Action()
data object UpdateOffline : Action()
}
data class UiState(val orderInfo: OrderInfo? = null,
val verifyValue: String? = null,
val goNextPage: UpdateTaskBean? = null,
val isGoNextPageDialog: Boolean? = null,
val showCallPhoneDialog: Boolean? = null,
val showOfflineDialog: Boolean? = null,
val photoTemplateList: List<PhotoTemplateInfo>? = null)
data class UiState(val orderInfo : OrderInfo? = null,
val verifyValue : String? = null,
val goNextPage : UpdateTaskBean? = null,
val isGoNextPageDialog : Boolean? = null,
val showCallPhoneDialog : Boolean? = null,
val showOfflineDialog : Boolean? = null,
val photoTemplateList : List<PhotoTemplateInfo>? = null)
}

View File

@ -33,7 +33,7 @@ import com.za.ext.goStatusPage
import com.za.ui.servicing.InServicingPhotoView
@Composable
fun ChangeBatteryScreen(vm: ChangeBatteryVm = viewModel()) {
fun ChangeBatteryScreen(vm : ChangeBatteryVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
LaunchedEffect(key1 = Unit) {
@ -57,7 +57,8 @@ fun ChangeBatteryScreen(vm: ChangeBatteryVm = viewModel()) {
contentPadding = PaddingValues(10.dp)) {
item {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.background(color = Color.White, shape = RoundedCornerShape(4.dp))
@ -66,11 +67,13 @@ fun ChangeBatteryScreen(vm: ChangeBatteryVm = viewModel()) {
Spacer(modifier = Modifier.width(10.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
Text(text = "更换", color = Color.Black)
Checkbox(checked = uiState.value.eleWorkOrderBean?.changeBattery == true, onCheckedChange = {
Checkbox(checked = uiState.value.eleWorkOrderBean?.changeBattery == true,
onCheckedChange = {
val eleWorkOrderBean = uiState.value.eleWorkOrderBean
vm.dispatch(ChangeBatteryVm.Action.UpdateState(uiState.value.copy(eleWorkOrderBean = eleWorkOrderBean?.copy(changeBattery = true))))
}, colors = CheckboxDefaults.colors()
.copy(uncheckedBoxColor = Color.Gray,
vm.dispatch(ChangeBatteryVm.Action.UpdateState(uiState.value.copy(
eleWorkOrderBean = eleWorkOrderBean?.copy(changeBattery = true))))
},
colors = CheckboxDefaults.colors().copy(uncheckedBoxColor = Color.Gray,
checkedBorderColor = Color.Transparent,
uncheckedBorderColor = Color.Transparent,
checkedBoxColor = Color.Red))
@ -83,9 +86,10 @@ fun ChangeBatteryScreen(vm: ChangeBatteryVm = viewModel()) {
Checkbox(checked = uiState.value.eleWorkOrderBean?.changeBattery == false,
onCheckedChange = {
val eleWorkOrderBean = uiState.value.eleWorkOrderBean
vm.dispatch(ChangeBatteryVm.Action.UpdateState(uiState.value.copy(eleWorkOrderBean = eleWorkOrderBean?.copy(changeBattery = false))))
}, colors = CheckboxDefaults.colors()
.copy(uncheckedBoxColor = Color.Gray,
vm.dispatch(ChangeBatteryVm.Action.UpdateState(uiState.value.copy(
eleWorkOrderBean = eleWorkOrderBean?.copy(changeBattery = false))))
},
colors = CheckboxDefaults.colors().copy(uncheckedBoxColor = Color.Gray,
checkedBorderColor = Color.Transparent,
uncheckedBorderColor = Color.Transparent,
checkedBoxColor = Color.Red))
@ -93,9 +97,9 @@ fun ChangeBatteryScreen(vm: ChangeBatteryVm = viewModel()) {
}
}
itemsIndexed(items = uiState.value.changeBatteryPhoto
?: arrayListOf(), key = { _, item -> item.hashCode() }) { index: Int, item: PhotoTemplateInfo ->
InServicingPhotoView(photoTemplateInfo = item, index = index, success = {
itemsIndexed(items = uiState.value.changeBatteryPhoto ?: arrayListOf(),
key = { _, item -> item.hashCode() }) { index : Int, item : PhotoTemplateInfo ->
InServicingPhotoView(photoTemplateInfo = item, index = index + 1, success = {
vm.dispatch(ChangeBatteryVm.Action.UpdatePhotoTemplate(it))
})
Spacer(modifier = Modifier.height(10.dp))

View File

@ -67,6 +67,7 @@ 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
@ -153,6 +154,46 @@ fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) {
})
}
if (uiState.value.showServiceSignatureUploadFailedDialog == true) {
CommonDialog(cancelText = "取消",
confirmText = "离线上传",
title = "服务人员签名上传失败,是否进行离线上传?",
cancelEnable = true,
cancel = {
vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy(
showServiceSignatureUploadFailedDialog = false)))
},
dismiss = {
vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy(
showServiceSignatureUploadFailedDialog = false)))
},
confirm = {
vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy(
showServiceSignatureUploadFailedDialog = false)))
vm.dispatch(ConfirmEleVm.Action.UploadOfflineServicePeopleSignature)
})
}
if (uiState.value.showAcceptCarSignUploadFailedDialog == true) {
CommonDialog(cancelText = "取消",
confirmText = "离线上传",
title = "接车人员签名上传失败,是否进行离线上传?",
cancelEnable = true,
cancel = {
vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy(
showAcceptCarSignUploadFailedDialog = false)))
},
dismiss = {
vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy(
showAcceptCarSignUploadFailedDialog = false)))
},
confirm = {
vm.dispatch(ConfirmEleVm.Action.UpdateState(uiState.value.copy(
showAcceptCarSignUploadFailedDialog = false)))
vm.dispatch(ConfirmEleVm.Action.UploadOfflineAcceptCarSignature)
})
}
Scaffold(topBar = {
HeadView(title = "客户签字", onBack = { context.finish() })
@ -249,7 +290,9 @@ fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) {
.padding(horizontal = 16.dp)) {
Spacer(modifier = Modifier.height(10.dp))
Row(verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxHeight().fillMaxWidth()) {
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()) {
Text(text = "*",
fontWeight = FontWeight.Bold,
color = Color.Red,
@ -403,8 +446,7 @@ fun ConfirmEleScreen(vm : ConfirmEleVm = viewModel()) {
if (! FileUtils.isFileExists(File(AppFileManager.getDriverSignPath(
context)))
) {
vm.updateState(uiState.value.copy(
showServicePeopleSignDialog = true))
vm.updateState(uiState.value.copy(showServicePeopleSignDialog = true))
}
},
serverPath = uiState.value.eleWorkOrderBean?.serverServicePeopleSignPath
@ -487,9 +529,11 @@ private fun EleWorkOrderDetailView(eleWorkOrderBean : EleWorkOrderBean?,
Spacer(modifier = Modifier.weight(1f))
Text(text = "车架号后6位", fontSize = 12.sp, color = black65)
Spacer(modifier = Modifier.width(5.dp))
Text(text = eleWorkOrderBean?.carVin ?: "",
Text(text = eleWorkOrderBean?.carVin?.getLastSix()
?: GlobalData.currentOrder?.carNo?.getLastSix() ?: "",
textDecoration = TextDecoration.Underline,
fontSize = 12.sp,
fontWeight = FontWeight.Medium,

View File

@ -1,8 +1,11 @@
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
import com.za.base.IServicingVm
@ -24,7 +27,10 @@ import com.za.room.RoomHelper
import com.za.service.location.ZdLocationManager
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
@ -45,9 +51,30 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
is Action.UploadServiceSignature -> updateServiceSignature(action.path)
is Action.IsChangeBattery -> updateIsChangeBattery(action.isChange)
is Action.UploadOffline -> uploadOffline()
is Action.UploadOfflineAcceptCarSignature -> uploadOfflineAcceptCarSignature()
is Action.UploadOfflineServicePeopleSignature -> uploadOfflineServicePeopleSignature()
}
}
private fun uploadOfflineAcceptCarSignature() {
val signOfflineUpdateTaskBean =
OfflineUpdateTaskBean(imageLocalPath = uiState.value.eleWorkOrderBean?.localAcceptCarSignPath,
taskId = getCurrentOrder()?.taskId,
taskCode = getCurrentOrder()?.taskCode,
offlineTitle = "电子工单-接车人签字",
offlineType = 6)
insertOfflineTask(signOfflineUpdateTaskBean)
}
private fun uploadOfflineServicePeopleSignature() {
val signOfflineUpdateTaskBean =
OfflineUpdateTaskBean(imageLocalPath = uiState.value.eleWorkOrderBean?.localServicePeopleSignPath,
taskId = getCurrentOrder()?.taskId,
taskCode = getCurrentOrder()?.taskCode,
offlineTitle = "电子工单-服务人员签字",
offlineType = 7)
insertOfflineTask(signOfflineUpdateTaskBean)
}
private fun updateIsChangeBattery(isChange : Boolean) {
updateState(uiState.value.copy(eleWorkOrderBean = uiState.value.eleWorkOrderBean?.copy(
@ -85,6 +112,17 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
}
}, failed = {
LoadingManager.hideLoading()
viewModelScope.launch(Dispatchers.IO) {
if (! NetworkUtils.isAvailable()) {
withContext(Dispatchers.Main) {
updateState(uiState.value.copy(showServiceSignatureUploadFailedDialog = true))
}
} else {
withContext(Dispatchers.Main) {
showTipDialog("服务人员签名上传失败,请重新签名上传")
}
}
}
LogUtil.print("updateServiceSignature", "failed==$it")
})
}
@ -97,6 +135,7 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
updateState(uiState.value.copy(eleWorkOrderBean = eleWorkOrderBean))
LogUtil.print("updateServiceSignature success", eleWorkOrderBean.toJson() ?: "")
}
CommonMethod.uploadImage(File(path), success = {
LoadingManager.hideLoading()
if (eleWorkOrderBean != null) {
@ -107,39 +146,30 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
}
}, failed = {
LoadingManager.hideLoading()
viewModelScope.launch(Dispatchers.IO) {
if (! NetworkUtils.isAvailable()) {
withContext(Dispatchers.Main) {
updateState(uiState.value.copy(showAcceptCarSignUploadFailedDialog = true))
}
} else {
withContext(Dispatchers.Main) {
showTipDialog("接车人签字上传失败,请重新签名上传")
}
}
}
LogUtil.print("uploadAcceptSignature", "failed==$it")
})
}
private fun uploadOffline() {
val eleWorkOrderBean =
RoomHelper.db?.eleWorkOrderDao()?.getEleWorkOrder(getCurrentOrder()?.taskId ?: 0)
if (eleWorkOrderBean == null) {
ToastUtils.showLong("数据获取失败,请返回首页重试!")
showTipDialog("数据获取失败,请返回首页重试!")
return
}
if (uiState.value.eleWorkOrderBean?.serverAcceptCarSignPath.isNullOrBlank()) {
val signOfflineUpdateTaskBean =
OfflineUpdateTaskBean(imageLocalPath = uiState.value.eleWorkOrderBean?.localAcceptCarSignPath,
taskId = getCurrentOrder()?.taskId,
taskCode = getCurrentOrder()?.taskCode,
offlineTitle = "电子工单-接车人签字",
offlineType = 6)
insertOfflineTask(signOfflineUpdateTaskBean)
}
if (uiState.value.eleWorkOrderBean?.serverServicePeopleSignPath.isNullOrBlank()) {
val signOfflineUpdateTaskBean =
OfflineUpdateTaskBean(imageLocalPath = uiState.value.eleWorkOrderBean?.localServicePeopleSignPath,
taskId = getCurrentOrder()?.taskId,
taskCode = getCurrentOrder()?.taskCode,
offlineTitle = "电子工单-服务人员签字",
offlineType = 7)
insertOfflineTask(signOfflineUpdateTaskBean)
}
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = {
LoadingManager.hideLoading()
@ -189,7 +219,7 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
private fun upload() {
val eleWorkOrderBean = uiState.value.eleWorkOrderBean
if (eleWorkOrderBean == null) {
ToastUtils.showLong("数据获取失败,请返回首页重试!")
showTipDialog("数据获取失败,请返回首页重试!")
return
}
@ -221,11 +251,26 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = {
LoadingManager.hideLoading()
doUpload(eleWorkOrderBean, it)
}, failed = {
LoadingManager.hideLoading()
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doUpload(eleWorkOrderBean, GlobalData.currentLocation)
} else {
LogUtil.print("$tag Upload", "全局定位获取失败$it")
showTipDialog(it)
}
})
}
private fun doUpload(eleWorkOrderBean : EleWorkOrderBean, location : AMapLocation? = null) {
val saveEleOrderRequest = SaveEleOrderRequest(state = 3,
userOrderId = GlobalData.currentOrder?.userOrderId,
taskOrderId = GlobalData.currentOrder?.taskId,
lat = it.latitude,
lng = it.longitude,
lat = location?.latitude,
lng = location?.longitude,
offlineMode = 0,
isFinish = true,
tyreNumber = if (uiState.value.isAddSmallWheel == true) {
@ -243,21 +288,19 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
updateCurrentEleWorkOrder(eleWorkOrderBean.copy(orderWorkStatus = 3))
updateState(uiState.value.copy(goNextPage = UpdateTaskBean(getCurrentOrder()?.taskState),
orderInfo = getCurrentOrder()))
updateOrder(orderInfo = getCurrentOrder()?.copy(tyreNumber = uiState.value.wheelNum))
}
override fun doFailure(code : Int, msg : String?) {
LoadingManager.hideLoading()
if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true))
} else {
showTipDialog(msg ?: "数据提交异常")
}
LogUtil.print("eleSign upload failed", msg ?: "")
}
})
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
})
}
private fun init() {
@ -295,6 +338,8 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
data class IsChangeBattery(val isChange : Boolean) : Action()
data class UpdateAcceptSignature(val path : String) : Action()
data class UploadServiceSignature(val path : String) : Action()
data object UploadOfflineServicePeopleSignature : Action()
data object UploadOfflineAcceptCarSignature : Action()
}
data class UiState(
@ -307,6 +352,8 @@ class ConfirmEleVm : IServicingVm<ConfirmEleVm.Action, ConfirmEleVm.UiState>() {
val isAddSmallWheel : Boolean? = null,
val wheelNum : Int? = null,
val showOfflineDialog : Boolean? = null,
val showAcceptCarSignUploadFailedDialog : Boolean? = null,
val showServiceSignatureUploadFailedDialog : Boolean? = null,
val showServicePeopleSignDialog : Boolean? = null, //服务人员签名弹窗
)
}

View File

@ -127,23 +127,17 @@ fun ConfirmH5SuccessScreen(vm : ConfirmH5SuccessVm = viewModel()) {
vm.updateState(uiState.value.copy(showSignDialog = null))
}, cancelEnable = false, confirm = {
vm.updateState(uiState.value.copy(showSignDialog = null))
val intent = Intent(context, GridPaintActivity::class.java)
intent.putExtra("background", android.graphics.Color.WHITE)
intent.putExtra("crop", true)
intent.putExtra("fontSize", 50) //手写字体大小
intent.putExtra("format", PenConfig.FORMAT_PNG)
intent.putExtra("lineLength", 10) //每行显示字数(超出屏幕支持横向滚动)
when (uiState.value.showSignDialog) {
1 -> {
customerSignatureLauncher.launch(intent)
GridPaintActivity.goGridPaintActivity(customerSignatureLauncher, context)
}
2 -> {
receivePeopleSignatureLauncher.launch(intent)
GridPaintActivity.goGridPaintActivity(receivePeopleSignatureLauncher, context)
}
3 -> {
servicePeopleSignatureLauncher.launch(intent)
GridPaintActivity.goGridPaintActivity(servicePeopleSignatureLauncher, context)
}
}
}, cancelText = "取消", dismiss = {

View File

@ -1,5 +1,6 @@
package com.za.ui.servicing.order_confirm
import com.amap.api.location.AMapLocation
import com.blankj.utilcode.util.ToastUtils
import com.za.base.Const
import com.za.base.IServicingVm
@ -11,6 +12,7 @@ import com.za.bean.request.QueryEleOrderRequest
import com.za.bean.request.SaveEleOrderRequest
import com.za.bean.request.TaskFinishRequest
import com.za.bean.request.TaskFinishResponse
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.ext.toJson
import com.za.net.BaseObserver
@ -174,7 +176,6 @@ class ConfirmH5SuccessVm : IServicingVm<ConfirmH5SuccessVm.Action, ConfirmH5Succ
updateState(uiState.value.copy(showOfflineTaskDialog = true))
return
}
queryEleWorkOrder(success = {
doTaskFinish()
}, failed = {
@ -186,9 +187,23 @@ class ConfirmH5SuccessVm : IServicingVm<ConfirmH5SuccessVm.Action, ConfirmH5Succ
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = { it ->
LoadingManager.hideLoading()
taskFinishImpl()
}, failed = {
LoadingManager.hideLoading()
if (GlobalData.currentLocation != null) {
LogUtil.print("taskFinish", "使用全局定位${GlobalData.currentLocation?.toJson()}")
taskFinishImpl(GlobalData.currentLocation)
} else {
LogUtil.print("taskFinish", "定位获取失败$it")
updateState(uiState.value.copy(loadingState = LoadingState.LoadingFailed(it)))
}
})
}
private fun taskFinishImpl(location : AMapLocation? = null) {
val taskFinishRequest = TaskFinishRequest(uiState.value.orderInfo?.userOrderId,
it.latitude,
it.longitude,
location?.latitude,
location?.longitude,
System.currentTimeMillis())
LoadingManager.showLoading()
RetrofitHelper.getDefaultService().taskFinish(taskFinishRequest)
@ -219,11 +234,6 @@ class ConfirmH5SuccessVm : IServicingVm<ConfirmH5SuccessVm.Action, ConfirmH5Succ
LogUtil.print("任务失败", "code==$code msg==$msg")
}
})
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showLong(it)
updateState(uiState.value.copy(loadingState = LoadingState.LoadingFailed(it)))
})
}
sealed class Action {

View File

@ -1,3 +1,5 @@
package com.za.ui.servicing.order_confirm.modify_money
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row

View File

@ -45,9 +45,8 @@ class ModifyMoneyViewModel : BaseVm<Action, UiState>() {
userOrderId = userOrderId,
taskId = taskId,
unitPrice = it?.unitPrice,
mileage = it?.mileage?.plus(uiState.value.paymentInfoBean?.limitedMileage
?: 0),
mileageText = "${it?.mileage?.plus(uiState.value.paymentInfoBean?.limitedMileage ?: 0)}",
mileage = it?.mileage?.plus(it.limitedMileage ?: 0),
mileageText = "${it?.mileage?.plus(it.limitedMileage ?: 0)}",
calculateAmount = it?.calculateAmount,
adjustAmount = it?.adjustAmount?.toFloat(),
adjustAmountText = "${it?.adjustAmount ?: ""}",

View File

@ -293,6 +293,12 @@ private fun OrderConfirmEditView(value : String? = null,
placeholder = {
Text(text = title, fontSize = 14.sp, color = black65)
},
label = {
Text(text = title,
fontSize = 10.sp,
color = black65,
style = TextStyle.Default.copy())
},
trailingIcon = {
Text(text = unit,
fontSize = 14.sp,

View File

@ -2,7 +2,7 @@ package com.za.ui.servicing.order_confirm.real_order_confirm
import com.alibaba.fastjson.JSONObject
import com.blankj.utilcode.util.ToastUtils
import com.amap.api.location.AMapLocation
import com.za.base.Const
import com.za.base.IServicingVm
import com.za.base.view.LoadingManager
@ -65,19 +65,19 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
if ((uiState.value.abRoadFee
?: 0) > 0 && uiState.value.aBAndBCPhotos?.find { it.numbering == "P.1" }?.photoUploadPath.isNullOrBlank()
) {
ToastUtils.showShort("请在出发段路桥费下方,拍摄发车段路桥费照片")
showTipDialog("请在出发段路桥费下方,拍摄发车段路桥费照片")
return
}
if ((uiState.value.bcRoadFee
?: 0) > 0 && uiState.value.aBAndBCPhotos?.find { it.numbering == "P.2" }?.photoUploadPath.isNullOrBlank()
) {
ToastUtils.showShort("请在背车段路桥费下方,拍摄背车段路桥费照片")
showTipDialog("请在背车段路桥费下方,拍摄背车段路桥费照片")
return
}
uiState.value.photoTemplateList?.forEach {
if (it.doHaveFilm == 1 && it.photoUploadPath.isNullOrBlank()) {
ToastUtils.showShort("请拍摄${it.imageTitle}照片")
showTipDialog("请拍摄${it.imageTitle}照片")
return
}
}
@ -86,11 +86,11 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
// AB段不为0 BC段拖车流程不为0
if (uiState.value.abKm == null || uiState.value.abKm == 0) {
ToastUtils.showShort("出发地-事发地距离不可为0")
showTipDialog("出发地-事发地距离不可为0")
return
}
if (uiState.value.orderInfo?.flowType == Const.TUO_CHE && (uiState.value.bcKm == null || uiState.value.bcKm == 0)) {
ToastUtils.showShort("事发地-目的地距离不可为0")
showTipDialog("事发地-目的地距离不可为0")
return
}
}
@ -117,6 +117,21 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = { it ->
LoadingManager.hideLoading()
doSubmit(tempPhotoList,it)
}, failed = {
LoadingManager.hideLoading()
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doSubmit(tempPhotoList, GlobalData.currentLocation)
} else {
LogUtil.print("$tag updateOffline", "全局定位获取失败$it")
showTipDialog(it)
}
})
}
private fun doSubmit(tempPhotoList : List<String?>? = null, location : AMapLocation? = null) {
val orderConfirmTaskRequest = UpdateOrderConfirmTaskRequest(type = "SETTLEMENT",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
@ -126,11 +141,16 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
supplierType = GlobalData.driverInfoBean?.supplierType,
settleType = GlobalData.currentOrder?.settleType,
carryMileage = uiState.value.bcKm,
mileage = uiState.value.overKm,
unitPrice = uiState.value.unitKmPrice?.toDouble(),
startPrice = uiState.value.startPrice,
startMileage = uiState.value.abKm,
startRoadFee = uiState.value.abRoadFee,
carryRoadFee = uiState.value.bcRoadFee,
dilemmaFee = uiState.value.dilemmaFee,
basementFee = uiState.value.basementFee,
wheelNum = GlobalData.currentOrder?.tyreNumber ?: 0,
wheelPrice = 25,
basePrice = if (GlobalData.driverInfoBean?.supplierType == Const.CHILD_COMPANY) {
computerBaseFee()
} else null,
@ -139,9 +159,10 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
} else null,
totalFee = computerTotalFee(),
offlineMode = 0,
lat = it.latitude,
lng = it.longitude,
templatePhotoInfoList = tempPhotoList.toList())
lat = location?.latitude,
lng = location?.longitude,
templatePhotoInfoList = tempPhotoList?.toList())
LogUtil.print("$tag updateRequest", orderConfirmTaskRequest.toJson() ?: "")
LoadingManager.showLoading()
RetrofitHelper.getDefaultService().submitOrderConfirmTask(orderConfirmTaskRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
@ -149,20 +170,14 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
override fun doSuccess(it : UpdateTaskBean?) {
LoadingManager.hideLoading()
updateOrder(getCurrentOrder()?.copy(taskState = it?.nextState))
updateState(uiState.value.copy(goNextPage = it,
orderInfo = getCurrentOrder()))
updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder()))
}
override fun doFailure(code : Int, msg : String?) {
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
showTipDialog(msg ?: "提交失败")
}
})
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
})
}
private fun computerBaseFee() : Double {
@ -172,7 +187,8 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
private fun computerAssistantsFee() : Double {
return (uiState.value.abRoadFee ?: 0) + (uiState.value.bcRoadFee
?: 0) + (uiState.value.dilemmaFee ?: 0) + (uiState.value.basementFee ?: 0).toDouble()
?: 0) + (uiState.value.dilemmaFee ?: 0) + (uiState.value.basementFee
?: 0).toDouble() + (uiState.value.orderInfo?.tyreNumber ?: 0) * 25
}
private fun computerTotalFee() : Double {
@ -220,6 +236,7 @@ class OrderConfirmVm : IServicingVm<OrderConfirmVm.Action, OrderConfirmVm.UiStat
val isGoNextPageDialog : Boolean? = null,
val aBAndBCPhotos : List<PhotoTemplateInfo>? = null,
val photoTemplateList : List<PhotoTemplateInfo>? = null,
val updateFailedMessage : String? = null,
val startPrice : Int? = null, //起步价
val unitKmPrice : Int? = null, //每公里价格
val overKm : Int? = null, //超出公里数

View File

@ -31,12 +31,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import com.za.base.BaseActivity
import com.za.base.Const
import com.za.base.view.CommonButton
import com.za.base.view.CommonDialog
import com.za.base.view.HeadView
import com.za.bean.db.order.OrderInfo
import com.za.bean.db.order.PhotoTemplateInfo
import com.za.ext.finish
import com.za.service.ServiceManager
import com.za.servicing.R
import com.za.ui.servicing.InServicingPhotoView
import com.za.ui.view.SignatureView
@ -53,8 +55,7 @@ class OrderGiveUpActivity : BaseActivity() {
OrderGiveUpScreen(orderInfo = orderInfo,
taskId = intent.getIntExtra("taskId", 0),
giveUpType = intent.getIntExtra("giveUpType", 0)) {
}
giveUpType = intent.getIntExtra("giveUpType", 0)) { }
}
companion object {
@ -93,14 +94,17 @@ fun OrderGiveUpScreen(vm : OrderGiveUpVm = viewModel(),
}
if (uiState.value.orderGiveUpSuccess == true) {
ServiceManager.sendMessageToMainProcess(type = Const.PushMessageType.GO_MAIN_PAGE,
message = "goMain",
context = context)
context.finish()
onBack()
}
if (uiState.value.isGoNextPageDialog == true) {
CommonDialog(cancelText = "取消",
confirmText = "是否确认放弃订单",
title = "放弃订单",
confirmText = "放弃订单",
title = "是否确认放弃订单",
cancelEnable = true,
cancel = {
vm.dispatch(OrderGiveUpVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))

View File

@ -178,7 +178,21 @@ class OrderGiveUpVm : BaseVm<OrderGiveUpVm.Action, OrderGiveUpVm.UiState>() {
doGiveUpTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = GiveUpTaskRequest(taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
lat = GlobalData.currentLocation?.latitude,
address = GlobalData.currentLocation?.address,
pushGiveUpFlag = 1,
lng = GlobalData.currentLocation?.longitude,
templatePhotoInfoList = tempPhotoList.toList())
doGiveUpTask(request = taskRequest)
} else {
showTipDialog(it)
}
})
}
@ -228,7 +242,21 @@ class OrderGiveUpVm : BaseVm<OrderGiveUpVm.Action, OrderGiveUpVm.UiState>() {
doGiveUpTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = GiveUpTaskRequest(taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
lat = GlobalData.currentLocation?.latitude,
address = GlobalData.currentLocation?.address,
lng = GlobalData.currentLocation?.longitude,
templatePhotoInfoList = tempPhotoList.toList())
doGiveUpTask(request = taskRequest)
} else {
showTipDialog(it)
}
})
}
}

View File

@ -1,5 +1,9 @@
package com.za.ui.servicing.verify
import android.app.Activity
import android.content.Intent
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
@ -22,6 +26,10 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
@ -34,16 +42,19 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
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.black65
import com.za.base.theme.buttonBgColor
import com.za.base.view.CommonDialog
import com.za.bean.db.order.OrderInfo
import com.za.common.log.LogUtil
import com.za.common.util.QRCodeUtil
import com.za.ext.callPhone
import com.za.ext.finish
import com.za.ext.goNextPage
import com.za.servicing.R
import com.za.ui.camera.ZdCameraXActivity
import com.za.ui.servicing.view.InServicingHeadView
class VerifyOrderActivity : BaseActivity() {
@ -53,9 +64,8 @@ class VerifyOrderActivity : BaseActivity() {
}
}
@Composable
fun VerifyOrderScreen(vm: VerifyOrderVm = viewModel()) {
fun VerifyOrderScreen(vm : VerifyOrderVm = viewModel()) {
val uiState = vm.uiState.collectAsStateWithLifecycle()
val context = LocalContext.current
LaunchedEffect(key1 = Unit) {
@ -63,15 +73,16 @@ fun VerifyOrderScreen(vm: VerifyOrderVm = viewModel()) {
}
if (uiState.value.isGoNextPageDialog == true) {
CommonDialog(
cancelText = "取消",
CommonDialog(cancelText = "取消",
confirmText = "前往下一步",
title = "是否前往下一步?",
cancelEnable = true,
cancel = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
},
dismiss = { vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false))) },
dismiss = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
},
confirm = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = false)))
vm.dispatch(VerifyOrderVm.Action.UpdateTask)
@ -83,15 +94,16 @@ fun VerifyOrderScreen(vm: VerifyOrderVm = viewModel()) {
}
if (uiState.value.showCallPhoneDialog == true) {
CommonDialog(
cancelText = "取消",
CommonDialog(cancelText = "取消",
confirmText = "确定",
title = "是否联系中道客服?",
cancelEnable = true,
cancel = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showCallPhoneDialog = false)))
},
dismiss = { vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showCallPhoneDialog = false))) },
dismiss = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showCallPhoneDialog = false)))
},
confirm = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showCallPhoneDialog = false)))
context.callPhone(uiState.value.orderInfo?.hotline)
@ -100,22 +112,26 @@ fun VerifyOrderScreen(vm: VerifyOrderVm = viewModel()) {
//离线操作框
if (uiState.value.showOfflineDialog == true) {
CommonDialog(
cancelText = "取消",
CommonDialog(cancelText = "取消",
confirmText = "离线上传",
title = "是否进行离线提交?",
cancelEnable = true,
cancel = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false)))
},
dismiss = { vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false))) },
dismiss = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false)))
},
confirm = {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showOfflineDialog = false)))
vm.dispatch(VerifyOrderVm.Action.UploadOffline)
})
}
Scaffold(topBar = { InServicingHeadView(title = "验证资格", orderInfo = uiState.value.orderInfo, onBack = { context.finish() }) }, bottomBar = {
Scaffold(topBar = {
InServicingHeadView(title = "验证资格",
orderInfo = uiState.value.orderInfo,
onBack = { context.finish() })
}, bottomBar = {
Row(modifier = Modifier
.fillMaxWidth()
.background(Color.White, shape = RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp))
@ -125,10 +141,19 @@ fun VerifyOrderScreen(vm: VerifyOrderVm = viewModel()) {
if (uiState.value.orderInfo?.verifyType != 5) {
Box(modifier = Modifier
.weight(1f)
.clickable { vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(showCallPhoneDialog = true))) }
.border(width = 0.8.dp, color = Color(0xFFDDDDDD), shape = RoundedCornerShape(4.dp))
.padding(vertical = 10.dp), contentAlignment = Alignment.Center) {
Text(text = "不符合,联系客服", fontSize = 14.sp, fontWeight = FontWeight.Medium, color = black65)
.clickable {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(
showCallPhoneDialog = true)))
}
.border(width = 0.8.dp,
color = Color(0xFFDDDDDD),
shape = RoundedCornerShape(4.dp))
.padding(vertical = 10.dp),
contentAlignment = Alignment.Center) {
Text(text = "不符合,联系客服",
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
color = black65)
}
Spacer(modifier = Modifier.width(5.dp))
}
@ -147,41 +172,59 @@ fun VerifyOrderScreen(vm: VerifyOrderVm = viewModel()) {
}
Box(modifier = Modifier
.weight(1f)
.clickable { vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = true))) }
.clickable {
vm.dispatch(VerifyOrderVm.Action.UpdateState(uiState.value.copy(
isGoNextPageDialog = true)))
}
.background(color = buttonBgColor, shape = RoundedCornerShape(4.dp))
.padding(vertical = 10.dp), contentAlignment = Alignment.Center) {
Text(text = buttonText, fontSize = 14.sp, fontWeight = FontWeight.Medium, color = Color.White)
Text(text = buttonText,
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
color = Color.White)
}
}
}) {
LazyColumn(modifier = Modifier
.fillMaxSize()
.padding(it), contentPadding = PaddingValues(vertical = 5.dp)) {
.padding(it),
contentPadding = PaddingValues(vertical = 5.dp)) {
if (uiState.value.orderInfo?.verifyType != null && uiState.value.orderInfo?.verifyType != 0) {
item {
VerifyCarView(orderInfo = uiState.value.orderInfo)
VerifyCarView(orderInfo = uiState.value.orderInfo,
newCarVin = uiState.value.newCarVin,
newCarVinPath = uiState.value.newCarPhotoPath,
recognize = {
vm.dispatch(VerifyOrderVm.Action.Recognize(it))
})
}
}
if (!uiState.value.orderInfo?.arriveRemindLink.isNullOrBlank()) {
if (! uiState.value.orderInfo?.arriveRemindLink.isNullOrBlank()) {
item {
VerifyTipView(arriveRemind = uiState.value.orderInfo?.arriveRemind
?: "", uiState.value.orderInfo?.arriveRemindLink ?: "")
VerifyTipView(arriveRemind = uiState.value.orderInfo?.arriveRemind ?: "",
uiState.value.orderInfo?.arriveRemindLink ?: "")
}
}
//重要提示
if (!uiState.value.orderInfo?.importantTip.isNullOrBlank()) {
if (! uiState.value.orderInfo?.importantTip.isNullOrBlank()) {
item {
Row(modifier = Modifier
.fillMaxWidth()
.background(color = Color(0xFFFFF7EE), shape = RoundedCornerShape(4.dp))
.padding(vertical = 5.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
AsyncImage(model = R.drawable.sv_warn_yellow, contentDescription = "", modifier = Modifier.size(12.5.dp, 12.5.dp))
.padding(vertical = 5.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically) {
AsyncImage(model = R.drawable.sv_warn_yellow,
contentDescription = "",
modifier = Modifier.size(12.5.dp, 12.5.dp))
Spacer(modifier = Modifier.width(5.dp))
Text(text = uiState.value.orderInfo?.importantTip
?: "", fontSize = 12.sp, fontWeight = FontWeight.Medium, color = Color.Red)
Text(text = uiState.value.orderInfo?.importantTip ?: "",
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
color = Color.Red)
}
}
}
@ -191,7 +234,27 @@ fun VerifyOrderScreen(vm: VerifyOrderVm = viewModel()) {
}
@Composable
private fun VerifyCarView(orderInfo: OrderInfo?) {
private fun VerifyCarView(
orderInfo : OrderInfo?,
newCarVin : String? = null,
newCarVinPath : String? = null,
recognize : (String) -> Unit,
) {
val context = LocalContext.current
var localCarVinPath by remember { mutableStateOf<String?>(null) }
val getResult =
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { it ->
if (it.resultCode == Activity.RESULT_OK) {
val value = it.data?.getStringExtra("path")
LogUtil.print("takePhoto", "path==$value")
if (value.isNullOrBlank()) {
ToastUtils.showLong("照片路径为空,请重新拍摄!")
return@rememberLauncherForActivityResult
}
localCarVinPath = value
recognize(value)
}
}
Column(modifier = Modifier
.fillMaxWidth()
@ -200,10 +263,13 @@ private fun VerifyCarView(orderInfo: OrderInfo?) {
.padding(10.dp)) {
Box(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp), contentAlignment = Alignment.CenterStart) {
.padding(vertical = 10.dp),
contentAlignment = Alignment.CenterStart) {
Text(text = "请确认本次服务车辆信息".takeIf { orderInfo?.verifyType != 5 }
?: ("本次服务车辆为新车\n" +
"需要填写车架号 "), color = Color(0xFF323643), fontWeight = FontWeight.Medium, fontSize = 14.sp)
?: ("本次服务车辆为新车\n" + "需要填写车架号 "),
color = Color(0xFF323643),
fontWeight = FontWeight.Medium,
fontSize = 14.sp)
}
HorizontalDivider(modifier = Modifier.alpha(0.2f))
@ -211,37 +277,61 @@ private fun VerifyCarView(orderInfo: OrderInfo?) {
Spacer(modifier = Modifier.height(10.dp))
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "车牌号:", color = black65, fontSize = 13.sp, fontWeight = FontWeight.Medium)
Text(text = "车牌号:",
color = black65,
fontSize = 13.sp,
fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.width(10.dp))
Text(text = orderInfo?.carNo
?: "", fontWeight = FontWeight.Medium, fontSize = 16.sp, color = Color.Black)
Text(text = orderInfo?.carNo ?: "",
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
color = Color.Black)
}
Spacer(modifier = Modifier.height(10.dp))
if (orderInfo?.verifyType == 5) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "车架号:", color = black65, fontSize = 13.sp, fontWeight = FontWeight.Medium)
Row(modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically) {
Text(text = "车架号:",
color = black65,
fontSize = 13.sp,
fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.width(10.dp))
Text(text = orderInfo.carVin
?: "", fontWeight = FontWeight.Medium, fontSize = 16.sp, color = Color.Black)
Text(text = newCarVin ?: "",
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
color = Color.Black)
}
Spacer(modifier = Modifier.height(10.dp))
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
AsyncImage(model = R.drawable.sv_verify_vin, contentDescription = "", modifier = Modifier.size(220.dp, 123.dp))
Box(modifier = Modifier
.fillMaxWidth()
.clickable {
val intent = Intent(context, ZdCameraXActivity::class.java)
getResult.launch(intent)
}, contentAlignment = Alignment.Center) {
AsyncImage(model = newCarVinPath ?: R.drawable.sv_verify_vin,
contentDescription = "",
modifier = Modifier.size(220.dp, 123.dp))
}
Spacer(modifier = Modifier.height(10.dp))
} else if (orderInfo?.verifyType == 1 || orderInfo?.verifyType == 2) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
Text(text = "车架号:", color = black65, fontSize = 13.sp, fontWeight = FontWeight.Medium)
Row(modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically) {
Text(text = "车架号:",
color = black65,
fontSize = 13.sp,
fontWeight = FontWeight.Medium)
Spacer(modifier = Modifier.width(10.dp))
Text(text = orderInfo.carVin
?: "", fontWeight = FontWeight.Medium, fontSize = 16.sp, color = Color.Black)
Text(text = orderInfo.carVin ?: "",
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
color = Color.Black)
}
Spacer(modifier = Modifier.height(10.dp))
@ -258,30 +348,36 @@ private fun VerifyCarView(orderInfo: OrderInfo?) {
contentDescription = "",
modifier = Modifier.size(12.5.dp, 12.5.dp))
Spacer(modifier = Modifier.width(5.dp))
Text(text = "请确认以上信息至少一项符合否则将无法结算", fontSize = 12.sp, fontWeight = FontWeight.Medium, color = Color(0xFFFF8F37))
Text(text = "请确认以上信息至少一项符合否则将无法结算",
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
color = Color(0xFFFF8F37))
}
}
}
@Composable
private fun VerifyTipView(arriveRemind: String, arriveRemindUrl: String) {
private fun VerifyTipView(arriveRemind : String, arriveRemindUrl : String) {
Column(modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.background(color = Color.White, shape = RoundedCornerShape(6.dp))
.padding(10.dp), horizontalAlignment = Alignment.CenterHorizontally) {
.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
Box(modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp), contentAlignment = Alignment.CenterStart) {
Text(text = arriveRemind, color = Color(0xFF323643), fontWeight = FontWeight.Medium, fontSize = 14.sp)
.padding(vertical = 10.dp),
contentAlignment = Alignment.CenterStart) {
Text(text = arriveRemind,
color = Color(0xFF323643),
fontWeight = FontWeight.Medium,
fontSize = 14.sp)
}
HorizontalDivider(modifier = Modifier.alpha(0.2f))
Spacer(modifier = Modifier.height(10.dp))
if (arriveRemindUrl.endsWith("png")
|| arriveRemindUrl.endsWith("jpg")
|| arriveRemindUrl.endsWith("jpeg")
|| arriveRemindUrl.endsWith("WebP")
if (arriveRemindUrl.endsWith("png") || arriveRemindUrl.endsWith("jpg") || arriveRemindUrl.endsWith(
"jpeg") || arriveRemindUrl.endsWith("WebP")
) {
AsyncImage(model = arriveRemindUrl, contentDescription = "")
} else {

View File

@ -1,41 +1,91 @@
package com.za.ui.servicing.verify
import com.amap.api.location.AMapLocation
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.db.order.OrderInfo
import com.za.bean.request.OrderPhotoOcrRecognizeRequest
import com.za.bean.request.UpdateTaskBean
import com.za.bean.request.UpdateTaskRequest
import com.za.common.GlobalData
import com.za.common.log.LogUtil
import com.za.ext.getNextStatus
import com.za.ext.toJson
import com.za.net.BaseObserver
import com.za.net.CommonMethod
import com.za.net.RetrofitHelper
import com.za.offline.OfflineUpdateTaskBean
import com.za.service.location.ZdLocationManager
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.flow.MutableStateFlow
import java.io.File
class VerifyOrderVm : IServicingVm<VerifyOrderVm.Action, VerifyOrderVm.UiState>() {
private val _uiState = MutableStateFlow(UiState())
val uiState get() = _uiState
override fun updateState(uiState: UiState) {
override fun updateState(uiState : UiState) {
_uiState.value = uiState
}
override fun dispatch(action: Action) {
override fun dispatch(action : Action) {
when (action) {
is Action.Init -> init()
is Action.UpdateTask -> updateTask()
is Action.UpdateState -> updateState(action.uiState)
is Action.UploadOffline -> uploadOffline()
is Action.Recognize -> recognize(action.localPath)
}
}
private fun uploadOffline(taskRequest: UpdateTaskRequest? = null) {
private fun recognize(localPath : String) {
LoadingManager.showLoading()
CommonMethod.uploadImage(file = File(localPath), success = {
LoadingManager.hideLoading()
if (it.isNullOrBlank() == true) {
return@uploadImage
}
doRecognize(it)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
})
}
private fun doRecognize(uploadPath : String) {
LoadingManager.showLoading()
val orderPhotoOcrRecognizeRequest =
OrderPhotoOcrRecognizeRequest(GlobalData.currentOrder?.userOrderId, 2, uploadPath)
LogUtil.print("$tag doRecognize", "请求参数==${orderPhotoOcrRecognizeRequest.toJson()}")
RetrofitHelper.getDefaultService().orderPhotoOcrRecognize(orderPhotoOcrRecognizeRequest)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BaseObserver<String>() {
override fun doSuccess(it : String?) {
LoadingManager.hideLoading()
if (it.isNullOrBlank()) {
showTipDialog("识别失败")
return
}
if (it.contains("失败")) {
showTipDialog(it)
return
}
updateState(uiState.value.copy(newCarVin = it, newCarPhotoPath = uploadPath))
}
override fun doFailure(code : Int, msg : String?) {
LoadingManager.hideLoading()
showTipDialog(msg ?: "识别失败")
}
})
}
private fun uploadOffline(taskRequest : UpdateTaskRequest? = null) {
if (taskRequest != null) {
val offlineUpdateTaskBean = OfflineUpdateTaskBean(
type = taskRequest.type,
val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = taskRequest.type,
taskId = taskRequest.taskId,
userId = taskRequest.userId,
vehicleId = taskRequest.vehicleId,
@ -51,34 +101,45 @@ class VerifyOrderVm : IServicingVm<VerifyOrderVm.Action, VerifyOrderVm.UiState>(
offlineType = 1)
insertOfflineTask(offlineUpdateTaskBean)
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),
orderInfo = getCurrentOrder()))
return
}
ZdLocationManager.getSingleLocation(isNeedAddress = false,
success = { it ->
val temp = UpdateTaskRequest(
type = "VERIFY",
ZdLocationManager.getSingleLocation(isNeedAddress = false, success = { it ->
doUploadOfflineTask(it)
}, failed = {
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
doUploadOfflineTask(GlobalData.currentLocation)
} else {
showTipDialog(it)
}
})
}
private fun doUploadOfflineTask(it : AMapLocation?) {
val temp = UpdateTaskRequest(type = "VERIFY",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = GlobalData.currentOrder?.taskState,
offlineMode = 0,
newCarCode = if (uiState.value.orderInfo?.verifyType == 5) {
uiState.value.verifyValue
uiState.value.newCarVin
} else {
""
},
content = if (uiState.value.orderInfo?.verifyType == 5) {
uiState.value.verifyValue
uiState.value.newCarVin
} else {
uiState.value.orderInfo?.verifyValue
},
operateTime = System.currentTimeMillis().toString(),
lat = it.latitude,
lng = it.longitude)
lat = it?.latitude,
lng = it?.longitude)
val offlineUpdateTaskBean = OfflineUpdateTaskBean(
type = temp.type,
val offlineUpdateTaskBean = OfflineUpdateTaskBean(type = temp.type,
taskId = temp.taskId,
userId = temp.userId,
vehicleId = temp.vehicleId,
@ -94,36 +155,33 @@ class VerifyOrderVm : IServicingVm<VerifyOrderVm.Action, VerifyOrderVm.UiState>(
offlineType = 1)
insertOfflineTask(offlineUpdateTaskBean)
updateOrder(getCurrentOrder()?.copy(taskState = getCurrentOrder()?.getNextStatus()))
updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState), orderInfo = getCurrentOrder()))
}, failed = {
ToastUtils.showShort(it)
})
updateState(uiState.value.copy(goNextPage = UpdateTaskBean(nextState = getCurrentOrder()?.taskState),
orderInfo = getCurrentOrder()))
}
private fun updateTask() {
if (uiState.value.orderInfo?.verifyType == 5 && uiState.value.verifyValue.isNullOrBlank()) {
ToastUtils.showShort("验证信息不能为空")
if (uiState.value.orderInfo?.verifyType == 5 && uiState.value.newCarVin.isNullOrBlank()) {
showTipDialog(msg = "验证信息不能为空!")
return
}
LoadingManager.showLoading()
ZdLocationManager.getSingleLocation(success = {
LoadingManager.hideLoading()
val taskRequest = UpdateTaskRequest(
type = "VERIFY",
val taskRequest = UpdateTaskRequest(type = "VERIFY",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = GlobalData.currentOrder?.taskState,
offlineMode = 0,
newCarCode = if (uiState.value.orderInfo?.verifyType == 5) {
uiState.value.verifyValue
uiState.value.newCarVin
} else {
""
},
content = if (uiState.value.orderInfo?.verifyType == 5) {
uiState.value.verifyValue
uiState.value.newCarVin
} else {
uiState.value.orderInfo?.verifyValue
},
@ -131,18 +189,46 @@ class VerifyOrderVm : IServicingVm<VerifyOrderVm.Action, VerifyOrderVm.UiState>(
lat = it.latitude,
lng = it.longitude)
if (!getCurrentOrderOfflineTask().isNullOrEmpty()) {
if (! getCurrentOrderOfflineTask().isNullOrEmpty()) {
uploadOffline(taskRequest)
return@getSingleLocation
}
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
val taskRequest = UpdateTaskRequest(type = "VERIFY",
taskId = GlobalData.currentOrder?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = GlobalData.currentOrder?.taskState,
offlineMode = 0,
newCarCode = if (uiState.value.orderInfo?.verifyType == 5) {
uiState.value.newCarVin
} else {
""
},
content = if (uiState.value.orderInfo?.verifyType == 5) {
uiState.value.newCarVin
} else {
uiState.value.orderInfo?.verifyValue
},
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude)
if (! getCurrentOrderOfflineTask().isNullOrEmpty()) {
uploadOffline(taskRequest)
return@getSingleLocation
}
doUploadTask(request = taskRequest)
} else {
showTipDialog(msg = it)
}
})
}
private fun doUploadTask(request: UpdateTaskRequest) {
private fun doUploadTask(request : UpdateTaskRequest) {
LoadingManager.showLoading()
CommonMethod.updateTask(request, success = {
LoadingManager.hideLoading()
@ -150,9 +236,10 @@ class VerifyOrderVm : IServicingVm<VerifyOrderVm.Action, VerifyOrderVm.UiState>(
updateState(uiState.value.copy(goNextPage = it, orderInfo = getCurrentOrder()))
}, failed = { msg, code ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
if (code == Const.NetWorkException) {
updateState(uiState.value.copy(showOfflineDialog = true))
} else {
showTipDialog(msg = msg ?: "提交失败")
}
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
})
@ -165,16 +252,19 @@ class VerifyOrderVm : IServicingVm<VerifyOrderVm.Action, VerifyOrderVm.UiState>(
sealed class Action {
data object Init : Action()
data object UpdateTask : Action()
data class UpdateState(val uiState: UiState) : Action()
data class UpdateState(val uiState : UiState) : Action()
data object UploadOffline : Action()
data class Recognize(val localPath : String) : Action()
}
data class UiState(
val orderInfo: OrderInfo? = null,
val verifyValue: String? = null,
val goNextPage: UpdateTaskBean? = null,
val isGoNextPageDialog: Boolean? = null,
val showCallPhoneDialog: Boolean? = null,
val showOfflineDialog: Boolean? = null,
val orderInfo : OrderInfo? = null,
val verifyValue : String? = null,
val newCarPhotoPath : String? = null,
val newCarVin : String? = null,
val goNextPage : UpdateTaskBean? = null,
val isGoNextPageDialog : Boolean? = null,
val showCallPhoneDialog : Boolean? = null,
val showOfflineDialog : Boolean? = null,
)
}

View File

@ -73,7 +73,6 @@ fun InServicingHeadView(title : String,
confirm = {
showCallPhoneDialog.value = false
context.callPhone(orderInfo?.customerPhone)
context.finish()
})
}
@ -89,7 +88,6 @@ fun InServicingHeadView(title : String,
confirm = {
showCallServicePhoneDialog.value = false
context.callPhone(orderInfo?.hotline)
context.finish()
})
}
@ -227,13 +225,13 @@ fun InServicingHeadView(title : String,
},
actions = {
Box(modifier = Modifier
.size(39.dp)
.size(46.dp)
.clickable {
OrderRequirementsActivity.goOrderRequirementsActivity(context,
orderInfo,
type = Const.InServiceSettingType.ORDER_DETAIL)
}
.padding(10.dp), contentAlignment = Alignment.Center) {
.padding(15.dp), contentAlignment = Alignment.Center) {
AsyncImage(model = R.drawable.sv_setting,
contentDescription = "",
modifier = Modifier.fillMaxSize())
@ -267,7 +265,6 @@ fun ServiceOperation(orderInfo : OrderInfo?) {
confirm = {
showCallPhoneDialog.value = false
context.callPhone(orderInfo?.customerPhone)
context.finish()
})
}
@ -283,7 +280,6 @@ fun ServiceOperation(orderInfo : OrderInfo?) {
confirm = {
showCallServicePhoneDialog.value = false
context.callPhone(orderInfo?.hotline)
context.finish()
})
}

View File

@ -3,51 +3,32 @@ package com.za.ui.servicing.wait_to_start
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
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.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.SheetValue
import androidx.compose.material3.Text
import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.material3.rememberStandardBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.AbsoluteAlignment
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import com.amap.api.location.AMapLocationClient
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.MapView
@ -58,12 +39,10 @@ import com.amap.api.maps.model.MarkerOptions
import com.amap.api.maps.model.PolylineOptions
import com.blankj.utilcode.util.ConvertUtils
import com.za.base.BaseActivity
import com.za.base.theme.headBgColor
import com.za.base.view.CommonDialog
import com.za.common.GlobalData
import com.za.common.util.ImageUtil
import com.za.common.util.ServicingSpeechManager
import com.za.ext.copy
import com.za.ext.finish
import com.za.ext.goNextPage
import com.za.ext.navigationActivity
@ -71,7 +50,6 @@ import com.za.servicing.R
import com.za.ui.new_order.NewOrderItem
import com.za.ui.new_order.NewOrderItemUIBean
import com.za.ui.new_order.NewOrderUiType
import com.za.ui.servicing.go_to_destination.GoToDestinationVm
import com.za.ui.servicing.inservice_people_confirm.ServicePeopleConfirmActivity
import com.za.ui.servicing.view.InServicingHeadView
import com.za.ui.servicing.view.ServiceOperation
@ -160,6 +138,10 @@ fun WaitToStartScreen(vm : WaitToStartVm = viewModel()) {
})
}
var sheetExpandHeight = remember { mutableStateOf(0.dp) }
val localDensity = LocalDensity.current
BottomSheetScaffold(scaffoldState = scaffoldState,
topBar = {
InServicingHeadView(title = "调度成功,等待发车",
@ -167,7 +149,6 @@ fun WaitToStartScreen(vm : WaitToStartVm = viewModel()) {
orderInfo = uiState.value.orderInfo)
},
sheetContent = {
val uiBean = NewOrderItemUIBean(taskCode = uiState.value.orderInfo?.taskCode,
addressProperty = uiState.value.orderInfo?.addressProperty,
address = uiState.value.orderInfo?.address,
@ -178,14 +159,21 @@ fun WaitToStartScreen(vm : WaitToStartVm = viewModel()) {
expectArriveTime = uiState.value.orderInfo?.expectArriveTime,
bottomTextString = "发车",
uiType = NewOrderUiType.SERVICING)
Box(modifier = Modifier
.fillMaxWidth()
.onSizeChanged { coordinates ->
sheetExpandHeight.value = with(localDensity) { coordinates.height.toDp() }
}) {
NewOrderItem(uiBean, goNextPage = {
if (! GlobalData.isMaster && GlobalData.driverInfoBean != null && GlobalData.driverInfoBean?.authStatus == 1) {
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(
showServicePeopleConfirmDialog = true)))
return@NewOrderItem
}
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(isGoNextPageDialog = true)))
vm.dispatch(WaitToStartVm.Action.UpdateState(uiState.value.copy(
isGoNextPageDialog = true)))
})
}
},
sheetPeekHeight = 180.dp,
sheetShape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
@ -193,9 +181,14 @@ fun WaitToStartScreen(vm : WaitToStartVm = viewModel()) {
sheetDragHandle = null,
sheetSwipeEnabled = true) { paddingValues ->
Box(modifier = Modifier
.fillMaxSize()
.padding(paddingValues)) {
AndroidView(modifier = Modifier.fillMaxSize(), factory = {
.wrapContentSize()
.padding(top = paddingValues.calculateTopPadding(),
bottom = if (bottomSheetState.currentValue == SheetValue.PartiallyExpanded) {
0.dp
} else {
sheetExpandHeight.value
})) {
AndroidView(modifier = Modifier.wrapContentSize(), factory = {
AMapLocationClient.updatePrivacyShow(context, true, true)
AMapLocationClient.updatePrivacyAgree(context, true)
mapView.apply {
@ -226,7 +219,8 @@ fun WaitToStartScreen(vm : WaitToStartVm = viewModel()) {
.zIndex(1f))
}
// 再添加标记点,确保标记点在路线上层
mapView.map.addMarkers(uiState.value.markers, false)
// 添加当前位置标记
if (GlobalData.currentLocation != null) {
mapView.map.addMarker(MarkerOptions().position(LatLng(GlobalData.currentLocation?.latitude !!,
@ -235,49 +229,18 @@ fun WaitToStartScreen(vm : WaitToStartVm = viewModel()) {
.anchor(0.5f, 0.5f).visible(true))
}
// 添加救援地标记
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0 && GlobalData.currentLocation != null) {
mapView.map.addMarker(MarkerOptions().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 && order.distLng != null && order.distLng != 0.0 && GlobalData.currentLocation != null) {
mapView.map.addMarker(MarkerOptions().position(LatLng(order.distLat !!,
order.distLng !!)).title("目的地")
.icon(ImageUtil.vectorToBitmap(context, R.drawable.sv_map_dist))
.anchor(0.5f, 0.5f))
}
}
// 最后调整地图显示范围
// 计算地图显示范围
val bounds = LatLngBounds.Builder().apply { // 添加当前位置
GlobalData.currentLocation?.let {
val bounds = LatLngBounds.Builder().apply {
uiState.value.routePoints?.forEach {
include(LatLng(it.latitude, it.longitude))
}
// 添加救援地点
uiState.value.orderInfo?.let { order ->
if (order.lat != null && order.lat != 0.0 && order.lng != null && order.lng != 0.0) {
include(LatLng(order.lat !!, order.lng !!))
}
// 添加目的地
if (order.distLat != null && order.distLat != 0.0 && order.distLng != null && order.distLng != 0.0) {
include(LatLng(order.distLat !!, order.distLng !!))
}
}
}.build()
// 调整地图显示范围,确保所有点都可见
try {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds,
ConvertUtils.dp2px(50f)))
} catch (e : Exception) { // 如果计算边界失败,则使用默认缩放级别
ConvertUtils.dp2px(100f)))
} catch (e : Exception) {
GlobalData.currentLocation?.let {
mapView.map.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(it.latitude,
it.longitude), 15f))

View File

@ -11,7 +11,6 @@ import com.amap.api.services.route.RideRouteResult
import com.amap.api.services.route.RouteSearch
import com.amap.api.services.route.WalkRouteResult
import com.blankj.utilcode.util.ActivityUtils
import com.blankj.utilcode.util.ToastUtils
import com.za.base.IServicingVm
import com.za.base.view.LoadingManager
import com.za.bean.db.order.OrderInfo
@ -64,7 +63,22 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
doUploadTask(request = taskRequest)
}, failed = {
LoadingManager.hideLoading()
ToastUtils.showShort(it)
if (GlobalData.currentLocation != null) {
LogUtil.print("$tag updateOffline",
"使用全局定位${GlobalData.currentLocation?.toJson()}")
val taskRequest = UpdateTaskRequest(type = "START",
taskId = getCurrentOrder()?.taskId,
userId = GlobalData.driverInfoBean?.userId,
vehicleId = GlobalData.driverInfoBean?.vehicleId,
currentState = getCurrentOrder()?.taskState,
offlineMode = 0,
operateTime = System.currentTimeMillis().toString(),
lat = GlobalData.currentLocation?.latitude,
lng = GlobalData.currentLocation?.longitude)
doUploadTask(request = taskRequest)
} else {
showTipDialog(it)
}
})
}
@ -76,7 +90,7 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
updateState(uiState.value.copy(goNextPage = data, orderInfo = getCurrentOrder()))
}, failed = { msg, _ ->
LoadingManager.hideLoading()
ToastUtils.showShort(msg)
showTipDialog(msg ?: "提交失败")
LogUtil.print("$tag doUploadTask", "状态更新失败==${request.toJson()} msg==$msg")
})
}
@ -130,6 +144,12 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
LatLonPoint(orderInfo.lat !!, orderInfo.lng !!)
} else null
// 获取救援地点坐标
val disPoint =
if (orderInfo?.distLat != null && orderInfo.distLat != 0.0 && orderInfo.distLng != null && orderInfo.distLng != 0.0) {
LatLonPoint(orderInfo.distLat !!, orderInfo.distLng !!)
} else null
// 如果没有救援地点,则不进行规划
if (rescuePoint == null) {
LogUtil.print("searchDrivingRoute", "没有有效的终点")
@ -162,10 +182,24 @@ class WaitToStartVm : IServicingVm<WaitToStartVm.Action, WaitToStartVm.UiState>(
override fun onRideRouteSearched(p0 : RideRouteResult?, p1 : Int) {}
})
val fromAndTo = RouteSearch.FromAndTo(startPoint, rescuePoint)
val query =
RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DrivingDefault, null, null, "")
if (disPoint != null) {
val fromAndTo = RouteSearch.FromAndTo(startPoint, disPoint)
val wayPoints = listOf(rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
wayPoints,
null,
"")
calculateDriveRouteAsyn(query)
} else {
val fromAndTo = RouteSearch.FromAndTo(startPoint, rescuePoint)
val query = RouteSearch.DriveRouteQuery(fromAndTo,
RouteSearch.DRIVING_SINGLE_DEFAULT,
null,
null,
"")
calculateDriveRouteAsyn(query)
}
}
}

View File

@ -8,16 +8,19 @@ import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.DialogFragment
import com.za.base.view.CommonDialog
class CommonDialogFragment(val title: String? = null,
val message: String? = null,
val cancelText: String? = null,
val confirmText: String = "确定",
val confirm: () -> Unit = {},
val cancel: () -> Unit = {}) : DialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
class CommonDialogFragment(val title : String? = null,
val message : String? = null,
val cancelText : String? = null,
val confirmText : String = "确定",
val cancelable : Boolean = true,
val confirm : () -> Unit = {},
val cancel : () -> Unit = {}) : DialogFragment() {
override fun onCreateView(inflater : LayoutInflater,
container : ViewGroup?,
savedInstanceState : Bundle?) : View? {
return ComposeView(requireContext()).apply {
setContent {
CommonDialog(
CommonDialog(cancelEnable = cancelable,
confirm = {
dismiss()
confirm()

View File

@ -1,7 +1,6 @@
package com.za.ui.view
import android.app.Activity
import android.content.Intent
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.background
@ -22,9 +21,12 @@ import com.za.signature.GridPaintActivity
import com.za.signature.config.PenConfig
@Composable
fun SignatureView(modifier: Modifier = Modifier, success: (String?) -> Unit, serverPath: String?) {
fun SignatureView(modifier : Modifier = Modifier,
success : (String?) -> Unit,
serverPath : String?) {
val context = LocalContext.current
val signatureLauncher = rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { it ->
val signatureLauncher =
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { it ->
if (it.resultCode == Activity.RESULT_OK) {
val value = it.data?.getStringExtra(PenConfig.SAVE_PATH)
LogUtil.print("pen save Path", "path==$value")
@ -42,13 +44,7 @@ fun SignatureView(modifier: Modifier = Modifier, success: (String?) -> Unit, ser
.size(142.dp, 52.dp)
.background(color = Color.White, shape = RoundedCornerShape(4.dp))
.noDoubleClick {
val intent = Intent(context, GridPaintActivity::class.java)
intent.putExtra("background", android.graphics.Color.WHITE)
intent.putExtra("crop", true)
intent.putExtra("fontSize", 30) //手写字体大小
intent.putExtra("format", PenConfig.FORMAT_PNG)
intent.putExtra("lineLength", 10) //每行显示字数(超出屏幕支持横向滚动)
signatureLauncher.launch(intent)
GridPaintActivity.goGridPaintActivity(signatureLauncher, context)
},
contentScale = ContentScale.Inside)
}

View File

@ -5,14 +5,15 @@ package com.za.water_marker.bean
* @create 2021/5/16 11:19
* @mail coldpuppy@163.com
*/
data class PhotoMarkerInfo(
val needMark: Boolean? = null, //是否显示手机型号
val needShowPhoneBrand: Boolean? = null,
val path: String? = null,
val from: String? = null,
var lat: Double? = null,
var lng: Double? = null,
val address: String? = null,
val time: String? = null,
val driverName: String? = null,
val taskCode: String? = null)
data class PhotoMarkerInfo(val needMark : Boolean? = null, //是否显示手机型号
val needShowPhoneBrand : Boolean? = null,
val path : String? = null,
val from : String? = null,
var lat : Double? = null,
var lng : Double? = null,
val address : String? = null,
val exifTime : String? = null, //照片中获取到的时间 //服务中照片不需要次字段
val time : String? = null,
val photoSource : Int? = null, //服务中照片不需要
val driverName : String? = null,
val taskCode : String? = null)

View File

@ -4,31 +4,31 @@
android:viewportWidth="164"
android:viewportHeight="94">
<path
android:fillColor="#F8FBFF"
android:fillType="evenOdd"
android:pathData="M3.5,0.5L160.5,0.5A3,3 0,0 1,163.5 3.5L163.5,90.5A3,3 0,0 1,160.5 93.5L3.5,93.5A3,3 0,0 1,0.5 90.5L0.5,3.5A3,3 0,0 1,3.5 0.5z"
android:strokeWidth="1"
android:fillColor="#F8FBFF"
android:strokeColor="#EDEEF2"
android:fillType="evenOdd"/>
android:strokeColor="#EDEEF2" />
<path
android:fillAlpha="0.49723306"
android:fillColor="#0057F5"
android:fillType="nonZero"
android:pathData="M75.33,49a6.4,6.22 0,1 0,12.8 0a6.4,6.22 0,1 0,-12.8 0z"
android:strokeAlpha="0.49723306"
android:strokeWidth="1"
android:strokeAlpha="0.49723306"
android:strokeColor="#00000000" />
<path
android:fillAlpha="0.49723306"
android:fillColor="#0057F5"
android:fillType="nonZero"
android:strokeColor="#00000000"
android:fillAlpha="0.49723306"/>
<path
android:pathData="M75.73,29.57L72.07,33.46L65.73,33.46C63.52,33.46 61.73,35.2 61.73,37.34L61.73,60.65C61.73,62.8 63.52,64.53 65.73,64.53L97.73,64.53C99.94,64.53 101.73,62.8 101.73,60.65L101.73,37.34C101.73,35.2 99.94,33.46 97.73,33.46L91.39,33.46L87.73,29.57L75.73,29.57ZM81.73,58.71C76.21,58.71 71.73,54.36 71.73,49C71.73,43.64 76.21,39.29 81.73,39.29C87.25,39.29 91.73,43.64 91.73,49C91.73,54.36 87.25,58.71 81.73,58.71Z"
android:strokeWidth="1"
android:strokeAlpha="0.49723306"
android:strokeWidth="1"
android:fillColor="#0057F5"
android:fillType="nonZero"
android:strokeColor="#00000000"
android:fillAlpha="0.49723306"/>
android:strokeColor="#00000000" />
<path
android:pathData="M7.33,84.32C7.33,85.78 8.52,86.97 9.97,86.97L9.97,86.97L9.97,88.42C7.79,88.42 6,86.69 5.9,84.52L5.89,84.32L7.33,84.32ZM157.65,84.32L159.09,84.32C159.09,86.58 157.26,88.42 155.01,88.42L155.01,86.97C156.47,86.97 157.65,85.78 157.65,84.32L157.65,84.32ZM9.97,6.91L9.97,8.36C8.51,8.36 7.33,9.55 7.33,11.01L5.89,11.01C5.89,8.81 7.61,7.02 9.77,6.92L9.97,6.91ZM155.01,6.91C157.26,6.91 159.09,8.75 159.09,11.01L159.09,11.01L157.65,11.01C157.65,9.6 156.56,8.45 155.17,8.36L155.01,8.36Z"
android:strokeWidth="1"
android:fillColor="#206FFF"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
android:pathData="M7.33,84.32C7.33,85.78 8.52,86.97 9.97,86.97L9.97,86.97L9.97,88.42C7.79,88.42 6,86.69 5.9,84.52L5.89,84.32L7.33,84.32ZM157.65,84.32L159.09,84.32C159.09,86.58 157.26,88.42 155.01,88.42L155.01,86.97C156.47,86.97 157.65,85.78 157.65,84.32L157.65,84.32ZM9.97,6.91L9.97,8.36C8.51,8.36 7.33,9.55 7.33,11.01L5.89,11.01C5.89,8.81 7.61,7.02 9.77,6.92L9.97,6.91ZM155.01,6.91C157.26,6.91 159.09,8.75 159.09,11.01L159.09,11.01L157.65,11.01C157.65,9.6 156.56,8.45 155.17,8.36L155.01,8.36Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64.3dp"
android:height="64dp"
android:viewportWidth="1028"
android:width="128.8dp"
android:height="128dp"
android:viewportWidth="1030"
android:viewportHeight="1024">
<path
android:pathData="M370,493.1L105.8,493.1c-58.4,0 -105.8,-47.5 -105.8,-105.8L0,105.8C0,47.5 47.5,0 105.8,0h264.1c58.3,0 105.8,47.5 105.8,105.8v281.4c-0,58.4 -47.5,105.8 -105.8,105.8zM94.5,47.9c-25.3,0 -45.9,20.6 -45.9,45.9v305.5c0,25.3 20.6,45.9 45.9,45.9L381.3,445.2c25.3,0 45.9,-20.6 45.9,-45.9L427.1,93.8c0,-25.3 -20.6,-45.9 -45.9,-45.9L94.5,47.9zM790.4,1023.9c-130.8,0 -237.3,-106.4 -237.3,-237.3s106.5,-237.3 237.3,-237.3c130.8,0 237.3,106.4 237.3,237.3s-106.4,237.3 -237.3,237.3zM790.4,595.4c-105.5,0 -191.3,85.8 -191.3,191.3 0,105.5 85.8,191.3 191.3,191.3 105.4,0 191.3,-85.8 191.3,-191.3 0,-105.5 -85.8,-191.3 -191.3,-191.3zM922.5,493.1h-264.1c-58.4,0 -105.8,-47.5 -105.8,-105.9L552.5,105.8C552.5,47.5 600,0 658.3,0h264.1c58.3,0 105.8,47.5 105.8,105.8L1028.3,387.2c-0,58.4 -47.5,105.9 -105.8,105.9zM647,47.9c-25.3,0 -45.9,20.6 -45.9,45.9v305.5c0,25.3 20.6,45.9 45.9,45.9h286.8c25.3,0 45.9,-20.6 45.9,-45.9L979.7,93.8c0,-25.3 -20.6,-45.9 -45.9,-45.9h-286.8zM370,1017L105.8,1017c-58.4,0 -105.8,-47.5 -105.8,-105.9v-281.4c0,-58.4 47.5,-105.8 105.8,-105.8h264.1c58.3,0 105.8,47.5 105.8,105.8v281.4c-0,58.4 -47.5,105.9 -105.8,105.9zM94.5,571.8c-25.3,0 -45.9,20.6 -45.9,45.9v305.5c0,25.3 20.6,45.9 45.9,45.9h286.8c25.3,0 45.9,-20.6 45.9,-45.9v-305.5c0,-25.3 -20.6,-45.9 -45.9,-45.9L94.5,571.8z"
android:pathData="M0,132.9c0,52.2 42.3,94.5 94.5,94.5 52.2,0 94.5,-42.3 94.5,-94.5C189,80.7 146.7,38.4 94.5,38.4 42.3,38.4 0,80.7 0,132.9zM0,510.8c0,52.2 42.3,94.5 94.5,94.5 52.2,0 94.5,-42.3 94.5,-94.5s-42.3,-94.5 -94.5,-94.5C42.3,416.3 0,458.6 0,510.8zM0,888.8c0,52.2 42.3,94.5 94.5,94.5 52.2,0 94.5,-42.3 94.5,-94.5 0,-52.2 -42.3,-94.5 -94.5,-94.5C42.3,794.3 0,836.6 0,888.8zM961,69.9a63,63 0,1 1,6 125.7l-6,0.3L340.8,195.9c-34.8,-0 -63,-28.2 -63,-63a63,63 0,0 1,56.9 -62.7l6,-0.3h620.3zM961,447.8a63,63 0,1 1,6 125.7l-6,0.3L340.8,573.8c-34.8,-0 -63,-28.2 -63,-63a63,63 0,0 1,56.9 -62.7l6,-0.3h620.3zM961,825.8a63,63 0,1 1,6 125.7l-6,0.3L340.8,951.8c-34.8,-0 -63,-28.2 -63,-63a63,63 0,0 1,56.9 -62.7l6,-0.3h620.3z"
android:fillColor="#ffffff"/>
</vector>

View File

@ -80,14 +80,16 @@
android:layout_width="@dimen/sign_tool_icon_size"
android:layout_height="@dimen/sign_tool_icon_size"
android:layout_weight="1"
android:src="@mipmap/sign_ic_space" />
android:src="@mipmap/sign_ic_space"
android:visibility="gone" />
<com.za.signature.view.CircleImageView
android:id="@+id/enter"
android:layout_width="@dimen/sign_tool_icon_size"
android:layout_height="@dimen/sign_tool_icon_size"
android:layout_weight="1"
android:src="@mipmap/sign_ic_enter" />
android:src="@mipmap/sign_ic_enter"
android:visibility="gone" />
<com.za.signature.view.CircleImageView
android:id="@+id/delete"
@ -114,6 +116,7 @@
android:layout_width="@dimen/sign_tool_icon_size"
android:layout_height="@dimen/sign_tool_icon_size"
android:layout_centerInParent="true"
android:visibility="gone"
app:showOutBorder="true"
app:sizeLevel="2" />
</RelativeLayout>

View File

@ -151,10 +151,7 @@
<com.za.signature.view.GridPaintView
android:id="@+id/paint_view"
android:layout_width="@dimen/sign_grid_size"
android:layout_height="@dimen/sign_grid_size"
android:layout_gravity="center"
android:layout_margin="10dp"
android:padding="10dp" />
android:layout_height="@dimen/sign_grid_size" />
</LinearLayout>

Binary file not shown.

Binary file not shown.