feat(network): 优化网络异常处理和环境切换
- 新增网络异常统一处理逻辑 - 实现环境切换功能 - 更新 API接口 - 重构部分代码以提高可维护性
This commit is contained in:
@ -73,7 +73,7 @@ publishing {
|
||||
release(MavenPublication) {
|
||||
groupId = 'io.github.szl9'
|
||||
artifactId = 'zd_servicing'
|
||||
version = "1.0.1.9.9.68"
|
||||
version = "1.0.1.9.9.100"
|
||||
|
||||
pom {
|
||||
packaging = "aar"
|
||||
@ -219,5 +219,7 @@ dependencies {
|
||||
|
||||
api libs.org.eclipse.paho.client.mqttv3
|
||||
api libs.org.eclipse.paho.android.service
|
||||
|
||||
api libs.face.detection
|
||||
}
|
||||
|
||||
|
@ -77,10 +77,19 @@
|
||||
</queries>
|
||||
|
||||
<application
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="24">
|
||||
|
||||
<activity
|
||||
android:name="com.za.base.NetworkRouteSelectionActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Dealer" />
|
||||
|
||||
<activity
|
||||
android:name="com.za.ui.camera.ServicePeopleRealActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Dealer" />
|
||||
|
||||
<activity
|
||||
android:name="com.za.ui.servicing.inservice_people_confirm.ServicePeopleConfirmActivity"
|
||||
android:exported="true"
|
||||
|
@ -1,98 +1,152 @@
|
||||
package com.za.base
|
||||
|
||||
import com.za.common.GlobalData
|
||||
import com.za.net.RetrofitHelper
|
||||
|
||||
object AppConfig {
|
||||
var isRelease = false
|
||||
var isRelease = false
|
||||
|
||||
// API 相关地址
|
||||
lateinit var BASE_URL: String // API 主地址
|
||||
lateinit var IMG_BASE_URL: String // 图片服务器地址
|
||||
lateinit var Resource_URL: String // 资源服务器地址
|
||||
// API 相关地址
|
||||
lateinit var BASE_URL : String // API 主地址
|
||||
lateinit var IMG_BASE_URL : String // 图片服务器地址
|
||||
lateinit var Resource_URL : String // 资源服务器地址
|
||||
|
||||
// H5 相关地址
|
||||
lateinit var TRAIN_URL: String // 培训文档地址
|
||||
lateinit var DOCMENT_URL: String // 中道资料地址
|
||||
|
||||
/**
|
||||
* 正式环境配置
|
||||
*/
|
||||
fun release() {
|
||||
isRelease = true
|
||||
// H5 相关地址
|
||||
lateinit var trainUrl : String // 培训文档地址
|
||||
lateinit var documentUrl : String // 中道资料地址
|
||||
lateinit var newDriverTrainUrl : String // 新司机培训地址
|
||||
|
||||
// API 配置
|
||||
BASE_URL = "https://api.sinoassist.com"
|
||||
IMG_BASE_URL = "https://api.sinoassist.com"
|
||||
Resource_URL = "https://www.sinoassist.com/res"
|
||||
|
||||
// H5 配置
|
||||
TRAIN_URL = "https://www.sinoassist.com/h5/supplier/dispatch/diverTrainDocment"
|
||||
DOCMENT_URL = "https://www.sinoassist.com/h5/supplier/dispatch/docmentList"
|
||||
}
|
||||
fun init(isRelease : Boolean? = false) {
|
||||
val envType = GlobalData.networkEnv
|
||||
if (isRelease == true) {
|
||||
when (envType) {
|
||||
Const.NetEnv.Main -> release()
|
||||
Const.NetEnv.Review -> review()
|
||||
}
|
||||
} else {
|
||||
when (envType) {
|
||||
Const.NetEnv.CRM1 -> crm1()
|
||||
Const.NetEnv.CRM2 -> crm2()
|
||||
Const.NetEnv.UAT -> uat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核环境配置
|
||||
*/
|
||||
fun review() {
|
||||
isRelease = true
|
||||
fun changeEnv(envType : Int) {
|
||||
GlobalData.networkEnv = envType
|
||||
when (envType) {
|
||||
Const.NetEnv.Main -> release()
|
||||
Const.NetEnv.Review -> review()
|
||||
Const.NetEnv.CRM1 -> crm1()
|
||||
Const.NetEnv.CRM2 -> crm2()
|
||||
Const.NetEnv.UAT -> uat()
|
||||
}
|
||||
RetrofitHelper.reset()
|
||||
}
|
||||
|
||||
// API 配置
|
||||
BASE_URL = "http://interface.review.sino-assist.com"
|
||||
IMG_BASE_URL = "http://interface.review.sino-assist.com"
|
||||
Resource_URL = "https://www.sinoassist.com/res"
|
||||
}
|
||||
|
||||
/**
|
||||
* CRM1 环境配置
|
||||
*/
|
||||
fun crm1() {
|
||||
isRelease = false
|
||||
fun release() {
|
||||
isRelease = true // API 配置
|
||||
GlobalData.networkEnv = Const.NetEnv.Main
|
||||
BASE_URL = "https://api.sinoassist.com"
|
||||
IMG_BASE_URL = "https://api.sinoassist.com"
|
||||
Resource_URL = "https://www.sinoassist.com/res"
|
||||
|
||||
// API 配置
|
||||
BASE_URL = "https://api1.sino-assist.com"
|
||||
IMG_BASE_URL = "https://api1.sino-assist.com"
|
||||
Resource_URL = "https://crm1.sino-assist.com/res"
|
||||
// H5 配置
|
||||
trainUrl = "https://www.sinoassist.com/h5/supplier/dispatch/diverTrainDocment"
|
||||
documentUrl = "https://www.sinoassist.com/h5/supplier/dispatch/docmentList"
|
||||
newDriverTrainUrl = "https://www.sinoassist.com/h5/supplier/dispatch/driverTrainingList";
|
||||
}
|
||||
|
||||
// H5 配置
|
||||
TRAIN_URL = "https://crm1.sino-assist.com/h5/supplier/dispatch/diverTrainDocment"
|
||||
DOCMENT_URL = "https://crm1.sino-assist.com/h5/supplier/dispatch/docmentList"
|
||||
}
|
||||
|
||||
/**
|
||||
* CRM2 环境配置
|
||||
*/
|
||||
fun crm2() {
|
||||
isRelease = false
|
||||
/**
|
||||
* 审核环境配置
|
||||
*/
|
||||
private fun review() {
|
||||
isRelease = true // API 配置
|
||||
GlobalData.networkEnv = Const.NetEnv.Review
|
||||
|
||||
// API 配置
|
||||
BASE_URL = "https://api2.sino-assist.com"
|
||||
IMG_BASE_URL = "https://api2.sino-assist.com"
|
||||
Resource_URL = "https://crm2.sino-assist.com/res"
|
||||
}
|
||||
// API 配置
|
||||
BASE_URL = "http://interface.review.sino-assist.com"
|
||||
IMG_BASE_URL = "http://interface.review.sino-assist.com"
|
||||
Resource_URL = "https://www.sinoassist.com/res"
|
||||
documentUrl = "http://interface.review.sino-assist.com/h5/supplier/dispatch/docmentList"
|
||||
trainUrl = "http://interface.review.sino-assist.com/h5/supplier/dispatch/diverTrainDocment"
|
||||
newDriverTrainUrl =
|
||||
"http://interface.review.sino-assist.com/h5/supplier/dispatch/driverTrainingList"
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取培训文档完整地址
|
||||
* @param driverId 司机ID
|
||||
* @param keyword 关键字
|
||||
* @return 完整的培训文档URL
|
||||
*/
|
||||
fun getTrainUrl(keyWord: String = ""): String {
|
||||
if (keyWord.isEmpty()) {
|
||||
return TRAIN_URL + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}"
|
||||
}
|
||||
return TRAIN_URL + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}&keyword=$keyWord"
|
||||
}
|
||||
/**
|
||||
* CRM1 环境配置
|
||||
*/
|
||||
fun crm1() {
|
||||
isRelease = false
|
||||
GlobalData.networkEnv = Const.NetEnv.CRM1
|
||||
|
||||
/**
|
||||
* 获取中道资料完整地址
|
||||
* @param driverId 司机ID
|
||||
* @param keyword 关键字
|
||||
* @return 完整的中道资料URL
|
||||
*/
|
||||
fun getDocmentUrl(keyWord: String = ""): String {
|
||||
if (keyWord.isEmpty()) {
|
||||
return DOCMENT_URL + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}"
|
||||
}
|
||||
return DOCMENT_URL + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}&keyword=$keyWord"
|
||||
}
|
||||
}
|
||||
// API 配置
|
||||
BASE_URL = "https://api1.sino-assist.com"
|
||||
IMG_BASE_URL = "https://api1.sino-assist.com"
|
||||
Resource_URL = "https://crm1.sino-assist.com/res"
|
||||
|
||||
documentUrl = "https://crm1.sino-assist.com/h5/supplier/dispatch/docmentList";
|
||||
trainUrl = "https://crm1.sino-assist.com/h5/supplier/dispatch/diverTrainDocment";
|
||||
newDriverTrainUrl = "https://crm1.sino-assist.com/h5/supplier/dispatch/driverTrainingList";
|
||||
}
|
||||
|
||||
/**
|
||||
* CRM2 环境配置
|
||||
*/
|
||||
fun crm2() {
|
||||
isRelease = false
|
||||
GlobalData.networkEnv = Const.NetEnv.CRM2
|
||||
|
||||
// API 配置
|
||||
BASE_URL = "https://api2.sino-assist.com"
|
||||
IMG_BASE_URL = "https://api2.sino-assist.com"
|
||||
Resource_URL = "https://crm2.sino-assist.com/res"
|
||||
}
|
||||
|
||||
|
||||
fun uat() {
|
||||
isRelease = false
|
||||
GlobalData.networkEnv = Const.NetEnv.UAT
|
||||
|
||||
BASE_URL = "https://api-uat.sino-assist.com" //crm2
|
||||
IMG_BASE_URL = "https://api-uat.sino-assist.com"
|
||||
Resource_URL = "https://uat.sino-assist.com/res"
|
||||
documentUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/docmentList"
|
||||
trainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/diverTrainDocment"
|
||||
newDriverTrainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/driverTrainingList"
|
||||
documentUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/docmentList";
|
||||
trainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/diverTrainDocment";
|
||||
newDriverTrainUrl = "https://uat.sino-assist.com/h5/supplier/dispatch/driverTrainingList";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取培训文档完整地址
|
||||
* @param driverId 司机ID
|
||||
* @param keyword 关键字
|
||||
* @return 完整的培训文档URL
|
||||
*/
|
||||
fun getTrainUrl(keyWord : String = "") : String {
|
||||
if (keyWord.isEmpty()) {
|
||||
return trainUrl + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}"
|
||||
}
|
||||
return trainUrl + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}&keyword=$keyWord"
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中道资料完整地址
|
||||
* @param driverId 司机ID
|
||||
* @param keyword 关键字
|
||||
* @return 完整的中道资料URL
|
||||
*/
|
||||
fun getDocmentUrl(keyWord : String = "") : String {
|
||||
if (keyWord.isEmpty()) {
|
||||
return documentUrl + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}"
|
||||
}
|
||||
return documentUrl + "?token=${GlobalData.token}&driverId=${GlobalData.driverInfoBean?.userId}&keyword=$keyWord"
|
||||
}
|
||||
}
|
||||
|
@ -42,4 +42,12 @@ object Const {
|
||||
const val ORDER_DETAIL = 2 //案件详情
|
||||
const val ORDER_GIVE_UP = 3 //订单放弃
|
||||
}
|
||||
|
||||
object NetEnv {
|
||||
const val Main = 0 //正线
|
||||
const val Review = 1 //正线
|
||||
const val CRM1 = 2 //测试环境
|
||||
const val CRM2 = 3 //测试环境
|
||||
const val UAT = 4 //测试环境
|
||||
}
|
||||
}
|
@ -0,0 +1,442 @@
|
||||
package com.za.base
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Build
|
||||
import android.telephony.PhoneStateListener
|
||||
import android.telephony.SignalStrength
|
||||
import android.telephony.TelephonyCallback
|
||||
import android.telephony.TelephonyManager
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
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.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.RadioButton
|
||||
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.mutableIntStateOf
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.app.ActivityCompat
|
||||
import com.blankj.utilcode.util.AppUtils
|
||||
import com.za.base.theme.bgColor
|
||||
import com.za.base.view.HeadView
|
||||
import com.za.bean.BaseResponse
|
||||
import com.za.bean.UpdateVersionBean
|
||||
import com.za.bean.UpdateVersionRequest
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.ext.finish
|
||||
import com.za.net.BaseObserver
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.OkHttpClient
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
data class Route(val name : String,
|
||||
val url : String,
|
||||
val id : String = name,
|
||||
val type : Int) // 添加id字段用于唯一标识
|
||||
|
||||
// 定义所有可用线路
|
||||
val availableRoutes = if (AppConfig.isRelease) {
|
||||
listOf(
|
||||
Route("主线路", "https://api.sinoassist.com", "main", type = Const.NetEnv.Main),
|
||||
Route("备用线路",
|
||||
"http://interface.review.sino-assist.com",
|
||||
"review",
|
||||
type = Const.NetEnv.Review),
|
||||
)
|
||||
} else {
|
||||
listOf(Route("CRM1", "https://api1.sino-assist.com", "crm1", type = Const.NetEnv.CRM1),
|
||||
Route("CRM2", "https://api2.sino-assist.com", "crm2", type = Const.NetEnv.CRM2),
|
||||
Route("UAT", "https://api-uat.sino-assist.com", "uat", type = Const.NetEnv.UAT))
|
||||
}
|
||||
|
||||
// 定义检测状态枚举
|
||||
enum class DetectionStatus {
|
||||
UNKNOWN, // 未检测
|
||||
CHECKING, // 检测中
|
||||
NORMAL, // 正常
|
||||
ABNORMAL // 异常
|
||||
}
|
||||
|
||||
class NetworkRouteSelectionActivity : BaseActivity() {
|
||||
@Composable
|
||||
override fun ContentView() {
|
||||
NetworkRouteScreen(telephonyManager = getSystemService(TELEPHONY_SERVICE) as TelephonyManager,
|
||||
connectivityManager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NetworkInfo(telephonyManager : TelephonyManager, connectivityManager : ConnectivityManager) {
|
||||
val context = LocalContext.current
|
||||
var networkType by remember { mutableStateOf("") }
|
||||
var signalStrength by remember { mutableIntStateOf(- 1) }
|
||||
var operatorName by remember { mutableStateOf("") }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
// 更新网络信息
|
||||
LaunchedEffect(Unit) {
|
||||
if (ActivityCompat.checkSelfPermission(context,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
) { // 获取运营商名称
|
||||
operatorName = telephonyManager.networkOperatorName
|
||||
|
||||
// 使用新的 API 获取网络类型
|
||||
val networkCapabilities =
|
||||
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
|
||||
|
||||
networkType = when {
|
||||
networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) == true -> "WiFi"
|
||||
networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
when (telephonyManager.dataNetworkType) {
|
||||
TelephonyManager.NETWORK_TYPE_LTE -> "4G"
|
||||
TelephonyManager.NETWORK_TYPE_NR -> "5G"
|
||||
TelephonyManager.NETWORK_TYPE_UMTS -> "3G"
|
||||
TelephonyManager.NETWORK_TYPE_EDGE -> "2G"
|
||||
else -> "未知"
|
||||
}
|
||||
} else {
|
||||
"未知"
|
||||
}
|
||||
}
|
||||
|
||||
else -> "无网络"
|
||||
}
|
||||
|
||||
// 使用新的 TelephonyCallback API 监听信号强度变化
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val callback =
|
||||
object : TelephonyCallback(), TelephonyCallback.SignalStrengthsListener {
|
||||
override fun onSignalStrengthsChanged(signalStrengths : SignalStrength) {
|
||||
scope.launch(Dispatchers.Main) {
|
||||
signalStrength = signalStrengths.level
|
||||
LogUtil.print("NetworkInfo", "signalStrength: $signalStrength")
|
||||
}
|
||||
}
|
||||
}
|
||||
telephonyManager.registerTelephonyCallback(context.mainExecutor, callback)
|
||||
} else {
|
||||
@Suppress("DEPRECATION") telephonyManager.listen(object : PhoneStateListener() {
|
||||
override fun onSignalStrengthsChanged(signalStrengths : SignalStrength) {
|
||||
super.onSignalStrengthsChanged(signalStrengths)
|
||||
scope.launch(Dispatchers.Main) {
|
||||
signalStrength = signalStrengths.level
|
||||
LogUtil.print("NetworkInfo", "signalStrength: $signalStrength")
|
||||
}
|
||||
}
|
||||
}, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Card(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||
elevation = CardDefaults.elevatedCardElevation(4.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text(text = "当前手机网络",
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = Color(0xFF2E7D32))
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Column {
|
||||
Text("运营商:$operatorName", fontSize = 16.sp)
|
||||
Text("网络类型:$networkType", fontSize = 16.sp)
|
||||
Text(text = "信号强度:${
|
||||
when (signalStrength) {
|
||||
0 -> "无信号"
|
||||
1 -> "弱"
|
||||
2 -> "一般"
|
||||
3 -> "良好"
|
||||
4 -> "极好"
|
||||
else -> "未知"
|
||||
}
|
||||
}", fontSize = 16.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RouteItem(
|
||||
route : Route,
|
||||
isSelected : Boolean,
|
||||
onSelect : () -> Unit,
|
||||
) {
|
||||
var detectionStatus by remember { mutableStateOf(DetectionStatus.UNKNOWN) }
|
||||
var errorMessage by remember { mutableStateOf<String?>(null) }
|
||||
var isDetecting by remember { mutableStateOf(false) }
|
||||
var detectionTime by remember { mutableStateOf(0L) }
|
||||
|
||||
// 检测函数
|
||||
fun detectRoute() {
|
||||
if (isDetecting) return
|
||||
|
||||
isDetecting = true
|
||||
detectionStatus = DetectionStatus.CHECKING
|
||||
val startTime = System.currentTimeMillis()
|
||||
|
||||
try {
|
||||
val request = UpdateVersionRequest(appVersion = AppUtils.getAppVersionName())
|
||||
NetWorkRetrofit.getDefaultService(route.url).checkConnection(request)
|
||||
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<UpdateVersionBean>() {
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
detectionTime = System.currentTimeMillis() - startTime
|
||||
if (code == 999) {
|
||||
detectionStatus = DetectionStatus.ABNORMAL
|
||||
errorMessage = msg
|
||||
} else {
|
||||
detectionStatus = DetectionStatus.NORMAL
|
||||
}
|
||||
isDetecting = false
|
||||
}
|
||||
|
||||
override fun doSuccess(it : UpdateVersionBean?) {
|
||||
detectionTime = System.currentTimeMillis() - startTime
|
||||
detectionStatus = DetectionStatus.NORMAL
|
||||
isDetecting = false
|
||||
}
|
||||
})
|
||||
} catch (e : Exception) {
|
||||
detectionTime = System.currentTimeMillis() - startTime
|
||||
detectionStatus = DetectionStatus.ABNORMAL
|
||||
errorMessage = e.message ?: "连接失败"
|
||||
isDetecting = false
|
||||
}
|
||||
}
|
||||
|
||||
// 初始检测
|
||||
LaunchedEffect(Unit) {
|
||||
detectRoute()
|
||||
}
|
||||
|
||||
Column {
|
||||
Row(verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onSelect() }
|
||||
.padding(vertical = 5.dp)
|
||||
.border(width = if (isSelected) 1.dp else 0.dp,
|
||||
color = if (isSelected) MaterialTheme.colorScheme.primary else Color.Transparent,
|
||||
shape = RoundedCornerShape(4.dp))
|
||||
.padding(8.dp)) {
|
||||
RadioButton(selected = isSelected, onClick = { onSelect() })
|
||||
|
||||
Text(text = route.name,
|
||||
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal,
|
||||
modifier = Modifier.padding(start = 8.dp))
|
||||
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
if (isDetecting) {
|
||||
CircularProgressIndicator(modifier = Modifier.size(16.dp), strokeWidth = 2.dp)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
|
||||
val statusText = when (detectionStatus) {
|
||||
DetectionStatus.NORMAL -> "正常 (${detectionTime}ms)"
|
||||
DetectionStatus.ABNORMAL -> "异常 (${detectionTime}ms)"
|
||||
DetectionStatus.CHECKING -> "检测中..."
|
||||
DetectionStatus.UNKNOWN -> ""
|
||||
}
|
||||
|
||||
val statusColor = when (detectionStatus) {
|
||||
DetectionStatus.NORMAL -> Color(0xFF2E7D32)
|
||||
DetectionStatus.ABNORMAL -> Color(0xFFC62828)
|
||||
DetectionStatus.CHECKING -> Color(0xFF1565C0)
|
||||
DetectionStatus.UNKNOWN -> Color.Gray
|
||||
}
|
||||
|
||||
Text(text = statusText,
|
||||
color = statusColor,
|
||||
fontSize = 14.sp,
|
||||
modifier = Modifier.padding(horizontal = 8.dp))
|
||||
|
||||
Box(modifier = Modifier
|
||||
.clickable(enabled = ! isDetecting) { detectRoute() }
|
||||
.background(color = MaterialTheme.colorScheme.primary,
|
||||
shape = RoundedCornerShape(5.dp))
|
||||
.padding(vertical = 5.dp, horizontal = 10.dp)) {
|
||||
Text("检测", fontSize = 12.sp, color = Color.White)
|
||||
}
|
||||
}
|
||||
|
||||
// 显示错误信息(如果有)
|
||||
if (detectionStatus == DetectionStatus.ABNORMAL && errorMessage != null) {
|
||||
Text(text = "错误: $errorMessage",
|
||||
color = Color(0xFFC62828),
|
||||
fontSize = 12.sp,
|
||||
modifier = Modifier.padding(start = 40.dp, bottom = 8.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NetworkRouteScreen(telephonyManager : TelephonyManager,
|
||||
connectivityManager : ConnectivityManager) {
|
||||
|
||||
|
||||
// 原有的线路选择部分
|
||||
val context = LocalContext.current
|
||||
var selectedRoute by remember { mutableStateOf(availableRoutes.find { GlobalData.networkEnv == it.type }) }
|
||||
var showApplyDialog by remember { mutableStateOf(false) }
|
||||
|
||||
// 应用当前选中的线路
|
||||
fun applySelectedRoute() {
|
||||
selectedRoute?.let {
|
||||
showApplyDialog = false
|
||||
GlobalData.networkEnv = it.type
|
||||
AppConfig.changeEnv(it.type)
|
||||
}
|
||||
}
|
||||
|
||||
// 显示确认对话框
|
||||
if (showApplyDialog) {
|
||||
AlertDialog(onDismissRequest = { showApplyDialog = false },
|
||||
title = { Text("确认应用线路") },
|
||||
text = { Text("确定要将当前线路切换为 ${selectedRoute?.name} 吗?") },
|
||||
confirmButton = {
|
||||
Button(onClick = { applySelectedRoute() }) {
|
||||
Text("确定")
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
OutlinedButton(onClick = { showApplyDialog = false }) {
|
||||
Text("取消")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Scaffold(topBar = { HeadView(title = "线路选择", onBack = { context.finish() }) }) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(it)
|
||||
.background(color = bgColor)
|
||||
.padding(20.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally) { // 标题卡片
|
||||
NetworkInfo(telephonyManager, connectivityManager)
|
||||
|
||||
// 线路选择区域
|
||||
Card(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||
elevation = CardDefaults.elevatedCardElevation(4.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Text("选择线路",
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = Modifier.padding(bottom = 8.dp))
|
||||
|
||||
Divider()
|
||||
|
||||
availableRoutes.forEachIndexed { index, route ->
|
||||
RouteItem(route = route,
|
||||
isSelected = route == selectedRoute,
|
||||
onSelect = { selectedRoute = route })
|
||||
|
||||
if (index < availableRoutes.size - 1) {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 应用按钮
|
||||
Button(onClick = { showApplyDialog = true },
|
||||
enabled = selectedRoute != null,
|
||||
modifier = Modifier.fillMaxWidth()) {
|
||||
Icon(Icons.Default.Check, contentDescription = null)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text("应用选中线路")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 定义API接口
|
||||
private interface RouteCheckApi {
|
||||
@POST("/driverApp/base/appVersion")
|
||||
fun checkConnection(@Body versionRequest : UpdateVersionRequest) : Observable<BaseResponse<UpdateVersionBean>>
|
||||
}
|
||||
|
||||
// 在类的外部定义Retrofit管理器
|
||||
private object NetWorkRetrofit {
|
||||
private val client =
|
||||
OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
private val retrofitMap = mutableMapOf<String, Retrofit>()
|
||||
|
||||
private fun getRetrofit(baseUrl : String) : Retrofit {
|
||||
return retrofitMap.getOrPut(baseUrl) {
|
||||
Retrofit.Builder().baseUrl(baseUrl).client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create()) // Add this line
|
||||
.addCallAdapterFactory(RxJava3CallAdapterFactory.create()).build()
|
||||
}
|
||||
}
|
||||
|
||||
fun getDefaultService(baseUrl : String) : RouteCheckApi {
|
||||
return getRetrofit(baseUrl).create(RouteCheckApi::class.java)
|
||||
}
|
||||
|
||||
fun clearCache() {
|
||||
retrofitMap.clear()
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@ 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.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
@ -31,21 +30,14 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.za.base.NetworkRouteSelectionActivity
|
||||
import com.za.base.theme.headBgColor
|
||||
import com.za.base.theme.white95
|
||||
import com.za.bean.request.ReadTrainingCountRequest
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.net.BaseObserver
|
||||
import com.za.net.RetrofitHelper
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import com.za.ext.navigationActivity
|
||||
|
||||
|
||||
val warnBean = mutableStateOf<IWarnBean?>(null)
|
||||
@ -60,59 +52,19 @@ fun AppTipsView() {
|
||||
|
||||
when (warnBean) {
|
||||
is NetWarnBean -> {
|
||||
// NetTipView(warnBean as NetWarnBean)
|
||||
}
|
||||
|
||||
is ReadTrainingCountBean -> {
|
||||
// TrainingDocView(warnBean as ReadTrainingCountBean)
|
||||
NetworkWeakView(warnBean as NetWarnBean)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NetTipView(tipsBean : NetWarnBean) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(20.dp)
|
||||
.background(color = Color.Yellow)
|
||||
.padding(top = 20.dp, start = 20.dp, end = 20.dp, bottom = 5.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Center) {
|
||||
Text(tipsBean.message, color = white95)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TrainingDocView(readTrainingCountBean : ReadTrainingCountBean) {
|
||||
val showTrainingDialog = remember { mutableStateOf(false) }
|
||||
fun NetworkWeakView(netWarnBean : NetWarnBean) {
|
||||
val context = LocalContext.current
|
||||
|
||||
if (showTrainingDialog.value) {
|
||||
CommonDialog(title = "培训提醒",
|
||||
message = buildAnnotatedString {
|
||||
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold, fontSize = 16.sp)) {
|
||||
append("重要提示:\n")
|
||||
}
|
||||
withStyle(style = SpanStyle(fontSize = 14.sp)) {
|
||||
append("您有未完成的培训任务,为确保工作顺利开展,请尽快完成培训。\n\n")
|
||||
}
|
||||
withStyle(style = SpanStyle(color = Color(0xFFE65100),
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium)) {
|
||||
append("剩余培训任务:${readTrainingCountBean.mustReadTrainingCount ?: 0} 个")
|
||||
}
|
||||
}.toString(),
|
||||
confirmText = "立即前往",
|
||||
cancelText = "稍后提醒",
|
||||
cancelEnable = true,
|
||||
confirm = {
|
||||
showTrainingDialog.value = false
|
||||
},
|
||||
dismiss = { showTrainingDialog.value = false })
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = true,
|
||||
AnimatedVisibility(context !is NetworkRouteSelectionActivity,
|
||||
modifier = Modifier.background(color = headBgColor),
|
||||
enter = fadeIn(animationSpec = tween(300)) + expandVertically(animationSpec = tween(300),
|
||||
expandFrom = Alignment.Top),
|
||||
@ -138,11 +90,12 @@ fun TrainingDocView(readTrainingCountBean : ReadTrainingCountBean) {
|
||||
modifier = Modifier.size(24.dp))
|
||||
}
|
||||
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
Text(text = "培训提醒",
|
||||
Text(text = "提醒",
|
||||
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Bold),
|
||||
color = Color(0xFF424242),
|
||||
fontSize = 14.sp)
|
||||
Text(text = "您有 ${readTrainingCountBean.mustReadTrainingCount ?: 0} 个培训任务待完成",
|
||||
|
||||
Text(text = "当前线路异常,是否前往切换线路",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = Color(0xFF757575),
|
||||
fontSize = 12.sp)
|
||||
@ -150,18 +103,20 @@ fun TrainingDocView(readTrainingCountBean : ReadTrainingCountBean) {
|
||||
}
|
||||
|
||||
Box(modifier = Modifier
|
||||
.clickable {}
|
||||
.clickable {
|
||||
context.navigationActivity(NetworkRouteSelectionActivity::class.java)
|
||||
}
|
||||
.background(color = Color(0xFFFF9800), shape = RoundedCornerShape(5.dp))
|
||||
.padding(horizontal = 10.dp, vertical = 5.dp),
|
||||
contentAlignment = Alignment.Center) {
|
||||
Text("去完成", color = Color.White, style = MaterialTheme.typography.labelLarge)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun fetchAppTipsData() {
|
||||
if (GlobalData.currentOrder != null) {
|
||||
return
|
||||
@ -169,20 +124,6 @@ private fun fetchAppTipsData() {
|
||||
if (GlobalData.token == null) {
|
||||
return
|
||||
}
|
||||
val request = ReadTrainingCountRequest(driverId = GlobalData.driverInfoBean?.userId?.toInt(),
|
||||
userId = GlobalData.driverInfoBean?.userId,
|
||||
supplierId = GlobalData.driverInfoBean?.supplierId.toString())
|
||||
RetrofitHelper.getDefaultService().getReadTrainingCount(request).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<ReadTrainingCountBean>() {
|
||||
override fun doSuccess(it : ReadTrainingCountBean?) {
|
||||
warnBean.value = it
|
||||
}
|
||||
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
LogUtil.print("fetchAppTipsData ", "doFailure==$msg")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
abstract class IWarnBean
|
||||
|
@ -33,188 +33,220 @@ import com.za.common.util.MapUtil
|
||||
import com.za.servicing.R
|
||||
|
||||
@Composable
|
||||
fun CommonDialog(
|
||||
title: String? = null,
|
||||
confirmText: String = "确定",
|
||||
confirm: () -> Unit,
|
||||
content: @Composable () -> Unit = {},
|
||||
message: String? = null,
|
||||
cancelText: String? = "取消",
|
||||
cancelEnable: Boolean = true,
|
||||
cancel: () -> Unit = {},
|
||||
dismiss: () -> Unit
|
||||
) {
|
||||
Dialog(onDismissRequest = { dismiss() },
|
||||
properties = DialogProperties(
|
||||
dismissOnBackPress = cancelEnable,
|
||||
dismissOnClickOutside = cancelEnable)) {
|
||||
Box(modifier = Modifier
|
||||
.background(color = Color.White, shape = RoundedCornerShape(13.dp))) {
|
||||
Spacer(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(105.dp)
|
||||
.background(brush = Brush.verticalGradient(colors = arrayListOf(Color(0xFFDAE8FF),
|
||||
Color(0x00DAE8FF))),
|
||||
shape = RoundedCornerShape(topStart = 13.dp, topEnd = 13.dp)))
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center) {
|
||||
Spacer(modifier = Modifier.height(35.dp))
|
||||
Text(text = "$title", fontSize = 16.sp, fontWeight = FontWeight.Medium, color = Color(0xFF2A4054))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (message == null) {
|
||||
content()
|
||||
} else {
|
||||
Text(text = message, fontSize = 14.sp, color = Color(0xFF536475))
|
||||
}
|
||||
fun CommonDialog(title : String? = null,
|
||||
confirmText : String = "确定",
|
||||
confirm : () -> Unit,
|
||||
content : @Composable () -> Unit = {},
|
||||
message : String? = null,
|
||||
cancelText : String? = "取消",
|
||||
cancelEnable : Boolean = true,
|
||||
cancel : () -> Unit = {},
|
||||
dismiss : () -> Unit) {
|
||||
Dialog(onDismissRequest = { dismiss() },
|
||||
properties = DialogProperties(dismissOnBackPress = cancelEnable,
|
||||
dismissOnClickOutside = cancelEnable)) {
|
||||
Box(modifier = Modifier.background(color = Color.White,
|
||||
shape = RoundedCornerShape(13.dp))) {
|
||||
Spacer(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(105.dp)
|
||||
.background(brush = Brush.verticalGradient(colors = arrayListOf(Color(0xFFDAE8FF),
|
||||
Color(0x00DAE8FF))),
|
||||
shape = RoundedCornerShape(topStart = 13.dp, topEnd = 13.dp)))
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center) {
|
||||
Spacer(modifier = Modifier.height(35.dp))
|
||||
Text(text = "$title",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color(0xFF2A4054))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
if (message == null) {
|
||||
content()
|
||||
} else {
|
||||
Text(text = message, fontSize = 14.sp, color = Color(0xFF536475))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Box(modifier = Modifier
|
||||
.width(202.dp)
|
||||
.clickable { confirm() }
|
||||
.background(color = Color(0xFF3A58B1), shape = RoundedCornerShape(23.dp))
|
||||
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
|
||||
Text(text = confirmText, color = Color.White, fontSize = 15.sp, fontWeight = FontWeight.Medium)
|
||||
}
|
||||
Box(modifier = Modifier
|
||||
.width(202.dp)
|
||||
.clickable { confirm() }
|
||||
.background(color = Color(0xFF3A58B1), shape = RoundedCornerShape(23.dp))
|
||||
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
|
||||
Text(text = confirmText,
|
||||
color = Color.White,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
if (!cancelText.isNullOrBlank() && cancelEnable) {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { cancel() }, contentAlignment = Alignment.Center) {
|
||||
Text(text = cancelText, fontSize = 15.sp, fontWeight = FontWeight.Medium, color = black90)
|
||||
}
|
||||
}
|
||||
if (! cancelText.isNullOrBlank() && cancelEnable) {
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { cancel() },
|
||||
contentAlignment = Alignment.Center) {
|
||||
Text(text = cancelText,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = black90)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun ReTakePhotoDialog(
|
||||
title: String? = null,
|
||||
confirm: () -> Unit,
|
||||
againSubmit: () -> Unit,
|
||||
path: String? = null,
|
||||
showAgain: Boolean = false,
|
||||
cancel: () -> Unit = {},
|
||||
dismiss: () -> Unit
|
||||
) {
|
||||
Dialog(onDismissRequest = { dismiss() },
|
||||
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = true)) {
|
||||
Box(modifier = Modifier
|
||||
.background(color = Color.White, shape = RoundedCornerShape(13.dp))) {
|
||||
Spacer(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(105.dp)
|
||||
.background(brush = Brush.verticalGradient(colors = arrayListOf(Color(0xFFDAE8FF),
|
||||
Color(0x00DAE8FF))),
|
||||
shape = RoundedCornerShape(topStart = 13.dp, topEnd = 13.dp)))
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center) {
|
||||
Spacer(modifier = Modifier.height(35.dp))
|
||||
Text(text = "$title", fontSize = 16.sp, fontWeight = FontWeight.Medium, color = Color(0xFF2A4054))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp), contentAlignment = Alignment.Center) {
|
||||
AsyncImage(model = path,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.FillWidth)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
fun ReTakePhotoDialog(title : String? = null,
|
||||
confirm : () -> Unit,
|
||||
againSubmit : () -> Unit,
|
||||
path : String? = null,
|
||||
showAgain : Boolean = false,
|
||||
cancel : () -> Unit = {},
|
||||
dismiss : () -> Unit) {
|
||||
Dialog(onDismissRequest = { dismiss() },
|
||||
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = true)) {
|
||||
Box(modifier = Modifier.background(color = Color.White,
|
||||
shape = RoundedCornerShape(13.dp))) {
|
||||
Spacer(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(105.dp)
|
||||
.background(brush = Brush.verticalGradient(colors = arrayListOf(Color(0xFFDAE8FF),
|
||||
Color(0x00DAE8FF))),
|
||||
shape = RoundedCornerShape(topStart = 13.dp, topEnd = 13.dp)))
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 30.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center) {
|
||||
Spacer(modifier = Modifier.height(35.dp))
|
||||
Text(text = "$title",
|
||||
fontSize = 16.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = Color(0xFF2A4054))
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(300.dp),
|
||||
contentAlignment = Alignment.Center) {
|
||||
AsyncImage(model = path,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.FillWidth)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
Box(modifier = Modifier
|
||||
.width(202.dp)
|
||||
.clickable { confirm() }
|
||||
.background(color = Color(0xFF3A58B1), shape = RoundedCornerShape(23.dp))
|
||||
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
|
||||
Text(text = "重拍", color = Color.White, fontSize = 15.sp, fontWeight = FontWeight.Medium)
|
||||
}
|
||||
Box(modifier = Modifier
|
||||
.width(202.dp)
|
||||
.clickable { confirm() }
|
||||
.background(color = Color(0xFF3A58B1), shape = RoundedCornerShape(23.dp))
|
||||
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
|
||||
Text(text = "重拍",
|
||||
color = Color.White,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
|
||||
if (showAgain) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
if (showAgain) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Box(modifier = Modifier
|
||||
.width(202.dp)
|
||||
.clickable { againSubmit() }
|
||||
.background(color = Color.Red, shape = RoundedCornerShape(23.dp))
|
||||
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
|
||||
Text(text = "再次上传", color = Color.White, fontSize = 15.sp, fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier
|
||||
.width(202.dp)
|
||||
.clickable { againSubmit() }
|
||||
.background(color = Color.Red, shape = RoundedCornerShape(23.dp))
|
||||
.padding(vertical = 12.dp), contentAlignment = Alignment.Center) {
|
||||
Text(text = "再次上传",
|
||||
color = Color.White,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { cancel() }, contentAlignment = Alignment.Center) {
|
||||
Text(text = "取消", fontSize = 15.sp, fontWeight = FontWeight.Medium, color = black90)
|
||||
}
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { cancel() },
|
||||
contentAlignment = Alignment.Center) {
|
||||
Text(text = "取消",
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = black90)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun ChoiceMapDialog(dismiss: () -> Unit,
|
||||
lat: Double?,
|
||||
lng: Double?,
|
||||
address: String?) {
|
||||
val context = LocalContext.current
|
||||
Dialog(onDismissRequest = { dismiss() }) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(180.dp)
|
||||
.background(color = Color.White, shape = RoundedCornerShape(8.dp))
|
||||
.padding(10.dp), verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceAround) {
|
||||
if (MapUtil.isGdMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
MapUtil.startNavigationGd(context, lat = lat, lng = lng, address = address)
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_amap_icon, contentDescription = "", modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "高德地图", color = Color.Black, fontWeight = FontWeight.Medium, fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
fun ChoiceMapDialog(dismiss : () -> Unit, lat : Double?, lng : Double?, address : String?) {
|
||||
val context = LocalContext.current
|
||||
Dialog(onDismissRequest = { dismiss() }) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(180.dp)
|
||||
.background(color = Color.White, shape = RoundedCornerShape(8.dp))
|
||||
.padding(10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceAround) {
|
||||
if (MapUtil.isGdMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
MapUtil.startNavigationGd(context, lat = lat, lng = lng, address = address)
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_amap_icon,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "高德地图",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
|
||||
if (MapUtil.isBaiduMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
MapUtil.startNavigationBd(context, lat = lat, lng = lng, address = address)
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_baidu_icon, contentDescription = "", modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "百度地图", color = Color.Black, fontWeight = FontWeight.Medium, fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
if (MapUtil.isBaiduMapInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
MapUtil.startNavigationBd(context, lat = lat, lng = lng, address = address)
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_baidu_icon,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "百度地图",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
|
||||
if (MapUtil.isTencentInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
MapUtil.startNavigationTencent(context, lat = lat, lng = lng, address = address)
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_tencent_icon, contentDescription = "", modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "腾讯地图", color = Color.Black, fontWeight = FontWeight.Medium, fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MapUtil.isTencentInstalled(context)) {
|
||||
Column(modifier = Modifier.clickable {
|
||||
MapUtil.startNavigationTencent(context, lat = lat, lng = lng, address = address)
|
||||
dismiss()
|
||||
}) {
|
||||
AsyncImage(model = R.drawable.sv_tencent_icon,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(60.dp))
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(text = "腾讯地图",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ import com.za.servicing.R
|
||||
@Composable
|
||||
fun HeadView(title : String,
|
||||
onBack : () -> Unit = {},
|
||||
warnType : WarnType = WarnType.NULL,
|
||||
isCanBack : Boolean = true,
|
||||
action : @Composable () -> Unit = {}) {
|
||||
Column {
|
||||
@ -43,9 +42,7 @@ fun HeadView(title : String,
|
||||
},
|
||||
actions = { action() })
|
||||
|
||||
if (warnType != WarnType.NULL) {
|
||||
AppTipsView()
|
||||
}
|
||||
AppTipsView()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,31 +16,31 @@ import com.za.servicing.R
|
||||
|
||||
|
||||
object LoadingManager {
|
||||
val showLoading = mutableStateOf(false)
|
||||
val showLoading = mutableStateOf(false)
|
||||
|
||||
fun showLoading() {
|
||||
showLoading.value = true
|
||||
}
|
||||
fun showLoading() {
|
||||
showLoading.value = true
|
||||
}
|
||||
|
||||
fun hideLoading() {
|
||||
showLoading.value = false
|
||||
}
|
||||
fun hideLoading() {
|
||||
showLoading.value = false
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadingView() {
|
||||
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
|
||||
AsyncImage(model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(R.drawable.gif_loading)
|
||||
.decoderFactory(GifDecoder.Factory())
|
||||
.build(), contentDescription = "加载中", modifier = Modifier
|
||||
.size(70.dp)
|
||||
.align(Alignment.Center))
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
fun LoadingView() {
|
||||
Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
|
||||
AsyncImage(model = ImageRequest.Builder(LocalContext.current)
|
||||
.data(R.drawable.gif_loading).decoderFactory(GifDecoder.Factory()).build(),
|
||||
contentDescription = "加载中",
|
||||
modifier = Modifier
|
||||
.size(70.dp)
|
||||
.align(Alignment.Center))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class LoadingState {
|
||||
data object Loading : LoadingState()
|
||||
data object LoadingFailed : LoadingState()
|
||||
data object LoadingSuccess : LoadingState()
|
||||
data object Loading : LoadingState()
|
||||
data class LoadingFailed(val msg : String? = "加载失败") : LoadingState()
|
||||
data object LoadingSuccess : LoadingState()
|
||||
}
|
@ -25,3 +25,10 @@ data class ReportHistoryBean(val reportType : String? = null,
|
||||
val reportTemplate : String? = null,
|
||||
val createTime : Long? = null,
|
||||
val state : Int? = null)
|
||||
|
||||
data class TaskNotesBean(val taskNotes : String? = null, //救援要求
|
||||
val feeStandard : String? = null, //收费标准
|
||||
val customerNotes : String? = null, //客户提醒
|
||||
val otherNotes : String? = null, //特殊提醒
|
||||
val modelVinNo : String? = null, //车型
|
||||
val contract : String? = null) //车型
|
@ -4,23 +4,23 @@ import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "ele_work_order")
|
||||
data class EleWorkOrderBean(
|
||||
@PrimaryKey(autoGenerate = false) val orderId: Int,
|
||||
val userOrderId: Int? = null,
|
||||
val date: String? = null, //日期 2023-10-20
|
||||
val serviceContent: String? = null, //服务须知内容
|
||||
val orderWorkStatus: Int? = null, //电子工单状态 1车辆损伤照片 2 客户签名页面 3 服务完成 接车人签名和服务人员签名状态
|
||||
val hasBad: Boolean? = null, //车辆是否有损伤
|
||||
val carNO: String? = null,//车牌号
|
||||
val carVin: String? = null,//车架号
|
||||
val orderType: String? = null, //救援类型
|
||||
val isSuccess: Int? = null, //服务是否成功 1 成功 其他失败
|
||||
val localCustomSignPath: String? = null,
|
||||
val localAcceptCarSignPath: String? = null,//接车人本地路径
|
||||
val localServicePeopleSignPath: String? = null, //服务人员签名
|
||||
val serverCustomSignPath: String? = null,
|
||||
val serverAcceptCarSignPath: String? = null, //远程地址
|
||||
val serverServicePeopleSignPath: String? = null,
|
||||
val hasCreatedEleWorkOrderPhoto: Boolean? = null, //是否已经生成电子工单照片
|
||||
val changeBattery: Boolean? = null //是否更换电瓶
|
||||
)
|
||||
data class EleWorkOrderBean(@PrimaryKey(autoGenerate = false) val orderId : Int,
|
||||
val userOrderId : Int? = null,
|
||||
val date : String? = null, //日期 2023-10-20
|
||||
val serviceContent : String? = null, //服务须知内容
|
||||
val orderWorkStatus : Int? = null, //电子工单状态 1车辆损伤照片 2 客户签名页面 3 服务完成 接车人签名和服务人员签名状态
|
||||
val hasBad : Boolean? = null, //车辆是否有损伤
|
||||
val carNO : String? = null, //车牌号
|
||||
val carVin : String? = null, //车架号
|
||||
val orderType : String? = null, //救援类型
|
||||
val isSuccess : Int? = null, //服务是否成功 1 成功 其他失败
|
||||
val localCustomSignPath : String? = null,
|
||||
val localAcceptCarSignPath : String? = null, //接车人本地路径
|
||||
val localServicePeopleSignPath : String? = null, //服务人员签名
|
||||
val serverCustomSignPath : String? = null,
|
||||
val serverAcceptCarSignPath : String? = null, //远程地址
|
||||
val serverServicePeopleSignPath : String? = null,
|
||||
val hasCreatedEleWorkOrderPhoto : Boolean? = null, //是否已经生成电子工单照片
|
||||
val changeBattery : Boolean? = null, //是否更换电瓶
|
||||
var driverChoiceNoNeedReceiveMoney : Boolean? = null) //师傅是否选择了无需收款
|
||||
|
||||
|
@ -7,231 +7,230 @@ import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "order_info")
|
||||
data class OrderInfo(
|
||||
@PrimaryKey(autoGenerate = false) var taskId: Int? = null, //订单号 "taskId":5313005
|
||||
var userOrderId: Int? = null, //订单id
|
||||
var taskCode: String? = null, //订单编码 "taskCode":"ZD20190308009965"
|
||||
var customerName: String? = null, //客户姓名 "customerName":"越继安"
|
||||
var customerPhone: String? = null,//客户电话 "customerPhone":"18078815268"
|
||||
var carBrand: String? = null,//车辆品牌 "carBrand":""
|
||||
var modelVinNo: String? = null,
|
||||
var carModel: String? = null, //车辆型号 "carModel":"秦"
|
||||
var carNo: String? = null, //客户车车牌号 "carNo":"粤AF53918"
|
||||
var carVin: String? = null,//客户车Vin码 "carVin":"LGXC76C30J0132942"
|
||||
var taskState: String? = null, //订单状态 "taskState":"GOTO"
|
||||
var nextState: String? = null,//下一步状态
|
||||
var electronOrderState: Int? = null, //电子工单状态:1检查损伤 2生成车辆检查表签字 3作业完成签字
|
||||
var address: String? = null, //任务地址 "address":"广东省广州市白云区107国道石井凰岗路342号(白云黄石、同德围地区近庆丰兴隆公园)美景大酒店"
|
||||
var addressProperty: String? = null, //任务地址类型 "addressProperty":"地面"
|
||||
var addressRemark: String? = null, //事发地地址补充
|
||||
var distAddress: String? = null, //目的地地址 "distAddress":"广东省广州市白云区雅岗南大道"
|
||||
var distAddressRemark: String? = null,//目的地地址补充
|
||||
var expectArriveTime: String? = null, //预计到达时间 "expectArriveTime":"2019-03-08 05:11:07"
|
||||
var serviceTypeName: String? = null, //服务类型 "serviceTypeName":"故障--平板拖车"
|
||||
var orderSource: String? = null, // "orderSource":"中道救援-比亚迪道路救援项目"
|
||||
var flowType: Int? = null, //流程类型 0 综合服务 1小修 2拖车 3取送件 4在线技术解决 5组合服务 6拖车简化流程 7武汉交管服务
|
||||
var settleType: Int? = null,//结算类型 1 月结 2 现金
|
||||
var settleTypeStr: String? = null, //结算类型
|
||||
var supplierId: Int? = null,
|
||||
var startTime: String? = null,//发车时间
|
||||
var operationTime: String? = null, //作业完成时间
|
||||
var dispatchTime: String? = null,//派单时间 "dispatchTime":"2019-03-08 04:26:07"
|
||||
var verifyType: Int? = null,//验证类型 "verifyType": 0 跳过验证 1和2 车牌和车架号验证 5 新车验证
|
||||
var verifyValue: String? = null,//验证内容 "verifyValue":"粤AF53918"
|
||||
var holdon: Boolean? = null,//是否被挂起 "holdon":false
|
||||
var isCurrent: Boolean? = null, //是否为正在做的任务
|
||||
var flow: String? = null, //流程状态 "flow":"START,GOTO,VERIFY,EXAMINE,OPERATION,SENDTO,SETTLEMENT,FINISH"
|
||||
var externalCode: String? = null, //
|
||||
var plateNumber: String? = null,
|
||||
var distaddressProperty: String? = null,
|
||||
var vehiclePointRemark: String? = null,
|
||||
var destinationRemark: String? = null,
|
||||
var lat: Double? = null,
|
||||
var lng: Double? = null,
|
||||
var distLat: Double? = null,
|
||||
var distLng: Double? = null,
|
||||
var hotline: String? = null,
|
||||
var createTime: String? = null,
|
||||
var acceptTime: String? = null,
|
||||
var arriveTime: String? = null,
|
||||
var arriveDestTime: String? = null,
|
||||
var needECDevice: Boolean? = null,
|
||||
var needDestAddress: Boolean? = null,
|
||||
var linkToDocs: Boolean? = null,
|
||||
var linkToDaDianH5: Boolean? = null,
|
||||
var carFactory: Boolean? = null,
|
||||
var needWaterMarker: Boolean? = null,
|
||||
var needShowPhoneBrand: Boolean? = null,
|
||||
var taskNotes: String? = null, //救援要求
|
||||
var feeStandard: String? = null, //收费标准
|
||||
var customerNotes: String? = null, //客户提醒
|
||||
var otherNotes: String? = null, //特殊提醒
|
||||
var isNewCar: Boolean? = null, //是否新车
|
||||
var ECDeviceString: String? = null,//搭电设备照片提示
|
||||
var customerReportImgs: String? = null, //客户上报照片,多张照片用;分隔
|
||||
var arriveRemind: String? = null,
|
||||
var arriveRemindLink: String? = null,
|
||||
var policyNo: String? = null, // 平安拖车责任险 保单号
|
||||
var advanceTime: Long? = null,
|
||||
var importantTip: String? = null,
|
||||
var hasReplaceBatteryCapable: Int? = null, //是否有更换电瓶的能力 1 搭电可以更换电瓶 2搭电不可以更换电瓶 其他的不展示
|
||||
var taskSuccessStatus: Int? = null, //作业是否完成 0 完成 1未完成 拖车默认完成
|
||||
var tyreNumber: Int? = null, //辅助费用
|
||||
@PrimaryKey(autoGenerate = false) var taskId : Int? = null, //订单号 "taskId":5313005
|
||||
var userOrderId : Int? = null, //订单id
|
||||
var taskCode : String? = null, //订单编码 "taskCode":"ZD20190308009965"
|
||||
var customerName : String? = null, //客户姓名 "customerName":"越继安"
|
||||
var customerPhone : String? = null, //客户电话 "customerPhone":"18078815268"
|
||||
var carBrand : String? = null, //车辆品牌 "carBrand":""
|
||||
var modelVinNo : String? = null,
|
||||
var carModel : String? = null, //车辆型号 "carModel":"秦"
|
||||
var carNo : String? = null, //客户车车牌号 "carNo":"粤AF53918"
|
||||
var carVin : String? = null, //客户车Vin码 "carVin":"LGXC76C30J0132942"
|
||||
var taskState : String? = null, //订单状态 "taskState":"GOTO"
|
||||
var nextState : String? = null, //下一步状态
|
||||
var electronOrderState : Int? = null, //电子工单状态:1检查损伤 2生成车辆检查表签字 3作业完成签字
|
||||
var address : String? = null, //任务地址 "address":"广东省广州市白云区107国道石井凰岗路342号(白云黄石、同德围地区近庆丰兴隆公园)美景大酒店"
|
||||
var addressProperty : String? = null, //任务地址类型 "addressProperty":"地面"
|
||||
var addressRemark : String? = null, //事发地地址补充
|
||||
var distAddress : String? = null, //目的地地址 "distAddress":"广东省广州市白云区雅岗南大道"
|
||||
var distAddressRemark : String? = null, //目的地地址补充
|
||||
var expectArriveTime : String? = null, //预计到达时间 "expectArriveTime":"2019-03-08 05:11:07"
|
||||
var serviceTypeName : String? = null, //服务类型 "serviceTypeName":"故障--平板拖车"
|
||||
var orderSource : String? = null, // "orderSource":"中道救援-比亚迪道路救援项目"
|
||||
var flowType : Int? = null, //流程类型 0 综合服务 1小修 2拖车 3取送件 4在线技术解决 5组合服务 6拖车简化流程 7武汉交管服务
|
||||
var settleType : Int? = null, //结算类型 1 月结 2 现金
|
||||
var settleTypeStr : String? = null, //结算类型
|
||||
var supplierId : Int? = null,
|
||||
var startTime : String? = null, //发车时间
|
||||
var operationTime : String? = null, //作业完成时间
|
||||
var dispatchTime : String? = null, //派单时间 "dispatchTime":"2019-03-08 04:26:07"
|
||||
var verifyType : Int? = null, //验证类型 "verifyType": 0 跳过验证 1和2 车牌和车架号验证 5 新车验证
|
||||
var verifyValue : String? = null, //验证内容 "verifyValue":"粤AF53918"
|
||||
var holdon : Boolean? = null, //是否被挂起 "holdon":false
|
||||
var isCurrent : Boolean? = null, //是否为正在做的任务
|
||||
var flow : String? = null, //流程状态 "flow":"START,GOTO,VERIFY,EXAMINE,OPERATION,SENDTO,SETTLEMENT,FINISH"
|
||||
var externalCode : String? = null, //
|
||||
var plateNumber : String? = null,
|
||||
var distaddressProperty : String? = null,
|
||||
var vehiclePointRemark : String? = null,
|
||||
var destinationRemark : String? = null,
|
||||
var lat : Double? = null,
|
||||
var lng : Double? = null,
|
||||
var distLat : Double? = null,
|
||||
var distLng : Double? = null,
|
||||
var hotline : String? = null,
|
||||
var createTime : String? = null,
|
||||
var acceptTime : String? = null,
|
||||
var arriveTime : String? = null,
|
||||
var arriveDestTime : String? = null,
|
||||
var needECDevice : Boolean? = null,
|
||||
var needDestAddress : Boolean? = null,
|
||||
var linkToDocs : Boolean? = null,
|
||||
var linkToDaDianH5 : Boolean? = null,
|
||||
var carFactory : Boolean? = null,
|
||||
var needWaterMarker : Boolean? = null,
|
||||
var needShowPhoneBrand : Boolean? = null,
|
||||
var taskNotes : String? = null, //救援要求
|
||||
var feeStandard : String? = null, //收费标准
|
||||
var customerNotes : String? = null, //客户提醒
|
||||
var otherNotes : String? = null, //特殊提醒
|
||||
var isNewCar : Boolean? = null, //是否新车
|
||||
var ECDeviceString : String? = null, //搭电设备照片提示
|
||||
var customerReportImgs : String? = null, //客户上报照片,多张照片用;分隔
|
||||
var arriveRemind : String? = null,
|
||||
var arriveRemindLink : String? = null,
|
||||
var policyNo : String? = null, // 平安拖车责任险 保单号
|
||||
var advanceTime : Long? = null,
|
||||
var importantTip : String? = null,
|
||||
var hasReplaceBatteryCapable : Int? = null, //是否有更换电瓶的能力 1 搭电可以更换电瓶 2搭电不可以更换电瓶 其他的不展示
|
||||
var taskSuccessStatus : Int? = null, //作业是否完成 0 完成 1未完成 拖车默认完成
|
||||
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,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Long::class.java.classLoader) as? Long,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int) {
|
||||
}
|
||||
constructor(parcel : Parcel) : this(parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readValue(Double::class.java.classLoader) as? Double,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Boolean::class.java.classLoader) as? Boolean,
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readValue(Long::class.java.classLoader) as? Long,
|
||||
parcel.readString(),
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int,
|
||||
parcel.readValue(Int::class.java.classLoader) as? Int) {
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
parcel.writeValue(taskId)
|
||||
parcel.writeValue(userOrderId)
|
||||
parcel.writeString(taskCode)
|
||||
parcel.writeString(customerName)
|
||||
parcel.writeString(customerPhone)
|
||||
parcel.writeString(carBrand)
|
||||
parcel.writeString(modelVinNo)
|
||||
parcel.writeString(carModel)
|
||||
parcel.writeString(carNo)
|
||||
parcel.writeString(carVin)
|
||||
parcel.writeString(taskState)
|
||||
parcel.writeString(nextState)
|
||||
parcel.writeValue(electronOrderState)
|
||||
parcel.writeString(address)
|
||||
parcel.writeString(addressProperty)
|
||||
parcel.writeString(addressRemark)
|
||||
parcel.writeString(distAddress)
|
||||
parcel.writeString(distAddressRemark)
|
||||
parcel.writeString(expectArriveTime)
|
||||
parcel.writeString(serviceTypeName)
|
||||
parcel.writeString(orderSource)
|
||||
parcel.writeValue(flowType)
|
||||
parcel.writeValue(settleType)
|
||||
parcel.writeString(settleTypeStr)
|
||||
parcel.writeValue(supplierId)
|
||||
parcel.writeString(startTime)
|
||||
parcel.writeString(operationTime)
|
||||
parcel.writeString(dispatchTime)
|
||||
parcel.writeValue(verifyType)
|
||||
parcel.writeString(verifyValue)
|
||||
parcel.writeValue(holdon)
|
||||
parcel.writeValue(isCurrent)
|
||||
parcel.writeString(flow)
|
||||
parcel.writeString(externalCode)
|
||||
parcel.writeString(plateNumber)
|
||||
parcel.writeString(distaddressProperty)
|
||||
parcel.writeString(vehiclePointRemark)
|
||||
parcel.writeString(destinationRemark)
|
||||
parcel.writeValue(lat)
|
||||
parcel.writeValue(lng)
|
||||
parcel.writeValue(distLat)
|
||||
parcel.writeValue(distLng)
|
||||
parcel.writeString(hotline)
|
||||
parcel.writeString(createTime)
|
||||
parcel.writeString(acceptTime)
|
||||
parcel.writeString(arriveTime)
|
||||
parcel.writeString(arriveDestTime)
|
||||
parcel.writeValue(needECDevice)
|
||||
parcel.writeValue(needDestAddress)
|
||||
parcel.writeValue(linkToDocs)
|
||||
parcel.writeValue(linkToDaDianH5)
|
||||
parcel.writeValue(carFactory)
|
||||
parcel.writeValue(needWaterMarker)
|
||||
parcel.writeValue(needShowPhoneBrand)
|
||||
parcel.writeString(taskNotes)
|
||||
parcel.writeString(feeStandard)
|
||||
parcel.writeString(customerNotes)
|
||||
parcel.writeString(otherNotes)
|
||||
parcel.writeValue(isNewCar)
|
||||
parcel.writeString(ECDeviceString)
|
||||
parcel.writeString(customerReportImgs)
|
||||
parcel.writeString(arriveRemind)
|
||||
parcel.writeString(arriveRemindLink)
|
||||
parcel.writeString(policyNo)
|
||||
parcel.writeValue(advanceTime)
|
||||
parcel.writeString(importantTip)
|
||||
parcel.writeValue(hasReplaceBatteryCapable)
|
||||
parcel.writeValue(taskSuccessStatus)
|
||||
parcel.writeValue(tyreNumber)
|
||||
}
|
||||
override fun writeToParcel(parcel : Parcel, flags : Int) {
|
||||
parcel.writeValue(taskId)
|
||||
parcel.writeValue(userOrderId)
|
||||
parcel.writeString(taskCode)
|
||||
parcel.writeString(customerName)
|
||||
parcel.writeString(customerPhone)
|
||||
parcel.writeString(carBrand)
|
||||
parcel.writeString(modelVinNo)
|
||||
parcel.writeString(carModel)
|
||||
parcel.writeString(carNo)
|
||||
parcel.writeString(carVin)
|
||||
parcel.writeString(taskState)
|
||||
parcel.writeString(nextState)
|
||||
parcel.writeValue(electronOrderState)
|
||||
parcel.writeString(address)
|
||||
parcel.writeString(addressProperty)
|
||||
parcel.writeString(addressRemark)
|
||||
parcel.writeString(distAddress)
|
||||
parcel.writeString(distAddressRemark)
|
||||
parcel.writeString(expectArriveTime)
|
||||
parcel.writeString(serviceTypeName)
|
||||
parcel.writeString(orderSource)
|
||||
parcel.writeValue(flowType)
|
||||
parcel.writeValue(settleType)
|
||||
parcel.writeString(settleTypeStr)
|
||||
parcel.writeValue(supplierId)
|
||||
parcel.writeString(startTime)
|
||||
parcel.writeString(operationTime)
|
||||
parcel.writeString(dispatchTime)
|
||||
parcel.writeValue(verifyType)
|
||||
parcel.writeString(verifyValue)
|
||||
parcel.writeValue(holdon)
|
||||
parcel.writeValue(isCurrent)
|
||||
parcel.writeString(flow)
|
||||
parcel.writeString(externalCode)
|
||||
parcel.writeString(plateNumber)
|
||||
parcel.writeString(distaddressProperty)
|
||||
parcel.writeString(vehiclePointRemark)
|
||||
parcel.writeString(destinationRemark)
|
||||
parcel.writeValue(lat)
|
||||
parcel.writeValue(lng)
|
||||
parcel.writeValue(distLat)
|
||||
parcel.writeValue(distLng)
|
||||
parcel.writeString(hotline)
|
||||
parcel.writeString(createTime)
|
||||
parcel.writeString(acceptTime)
|
||||
parcel.writeString(arriveTime)
|
||||
parcel.writeString(arriveDestTime)
|
||||
parcel.writeValue(needECDevice)
|
||||
parcel.writeValue(needDestAddress)
|
||||
parcel.writeValue(linkToDocs)
|
||||
parcel.writeValue(linkToDaDianH5)
|
||||
parcel.writeValue(carFactory)
|
||||
parcel.writeValue(needWaterMarker)
|
||||
parcel.writeValue(needShowPhoneBrand)
|
||||
parcel.writeString(taskNotes)
|
||||
parcel.writeString(feeStandard)
|
||||
parcel.writeString(customerNotes)
|
||||
parcel.writeString(otherNotes)
|
||||
parcel.writeValue(isNewCar)
|
||||
parcel.writeString(ECDeviceString)
|
||||
parcel.writeString(customerReportImgs)
|
||||
parcel.writeString(arriveRemind)
|
||||
parcel.writeString(arriveRemindLink)
|
||||
parcel.writeString(policyNo)
|
||||
parcel.writeValue(advanceTime)
|
||||
parcel.writeString(importantTip)
|
||||
parcel.writeValue(hasReplaceBatteryCapable)
|
||||
parcel.writeValue(taskSuccessStatus)
|
||||
parcel.writeValue(tyreNumber)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
override fun describeContents() : Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<OrderInfo> {
|
||||
override fun createFromParcel(parcel: Parcel): OrderInfo {
|
||||
return OrderInfo(parcel)
|
||||
}
|
||||
companion object CREATOR : Parcelable.Creator<OrderInfo> {
|
||||
override fun createFromParcel(parcel : Parcel) : OrderInfo {
|
||||
return OrderInfo(parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<OrderInfo?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
override fun newArray(size : Int) : Array<OrderInfo?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,56 +1,55 @@
|
||||
package com.za.bean.request
|
||||
|
||||
data class OrderListRequest(
|
||||
val vehicleId: Int? = null,
|
||||
val deviceId: String? = null,
|
||||
val vehicleId : Int? = null,
|
||||
val deviceId : String? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* 照片模版请求数据
|
||||
*/
|
||||
data class PhotoTemplateRequest(val userOrderId: Int? = null)
|
||||
data class PhotoTemplateRequest(val userOrderId : Int? = null)
|
||||
|
||||
|
||||
//照片识别
|
||||
data class OrderPhotoOcrRecognizeRequest(
|
||||
val userOrderId: Int? = null,
|
||||
val recognizeType: Int? = null,
|
||||
val imgUrl: String? = null,
|
||||
val userOrderId : Int? = null,
|
||||
val recognizeType : Int? = null,
|
||||
val imgUrl : String? = null,
|
||||
)
|
||||
|
||||
data class TaskFinishRequest(
|
||||
val userOrderId: Int? = null,
|
||||
val lat: Double? = null,
|
||||
val lng: Double? = null,
|
||||
val operateTime: Long? = null)
|
||||
data class TaskFinishRequest(val userOrderId : Int? = null,
|
||||
val lat : Double? = null,
|
||||
val lng : Double? = null,
|
||||
val operateTime : Long? = null)
|
||||
|
||||
data class GiveUpTaskRequest(
|
||||
val taskId: Int? = null, //任务id
|
||||
val userId: Int? = null, //用户id
|
||||
val vehicleId: Int? = null, //车辆id
|
||||
val lat: Double? = null,
|
||||
val lng: Double? = null,
|
||||
val address: String? = null,
|
||||
val templatePhotoInfoList: List<String?>? = null, //照片数据
|
||||
val pushGiveUpFlag: Int? = null, //1 是 0否
|
||||
val taskId : Int? = null, //任务id
|
||||
val userId : Int? = null, //用户id
|
||||
val vehicleId : Int? = null, //车辆id
|
||||
val lat : Double? = null,
|
||||
val lng : Double? = null,
|
||||
val address : String? = null,
|
||||
val templatePhotoInfoList : List<String?>? = null, //照片数据
|
||||
val pushGiveUpFlag : Int? = null, //1 是 0否
|
||||
)
|
||||
|
||||
data class UpdatePhotoRequest(
|
||||
val taskId: Int? = null,
|
||||
val taskState: String? = null,
|
||||
val picturePosition: Int? = null, //图片位置
|
||||
val picturePath: String? = null,//图片路径
|
||||
val imgInfo: String? = null
|
||||
)
|
||||
data class UpdatePhotoRequest(val taskId : Int? = null,
|
||||
val taskState : String? = null,
|
||||
val picturePosition : Int? = null, //图片位置
|
||||
val picturePath : String? = null, //图片路径
|
||||
val imgInfo : String? = null)
|
||||
|
||||
data class SwitchTaskRequest(val currentTaskId: Int? = null,
|
||||
val nextTaskId: Int? = null,
|
||||
val userId: Int? = null,
|
||||
val vehicleId: Int? = null)
|
||||
data class SwitchTaskRequest(val currentTaskId : Int? = null,
|
||||
val nextTaskId : Int? = null,
|
||||
val userId : Int? = null,
|
||||
val vehicleId : Int? = null)
|
||||
|
||||
data class HistoryTasksRequest(val userId: Int? = null, val vehicleId: Int? = null)
|
||||
data class HistoryTasksRequest(val userId : Int? = null, val vehicleId : Int? = null)
|
||||
|
||||
data class HistoryPhotoTemplateRequest(val taskId: Int? = null)
|
||||
data class HistoryPhotoTemplateRequest(val taskId : Int? = null)
|
||||
|
||||
data class HistoryDetailRequest(val taskId: Int? = null)
|
||||
data class HistoryDetailRequest(val taskId : Int? = null)
|
||||
|
||||
data class TaskNotesRequest(val taskId : Int? = null)
|
||||
|
||||
|
@ -4,6 +4,8 @@ import android.app.Application
|
||||
import com.amap.api.location.AMapLocation
|
||||
import com.blankj.utilcode.util.AppUtils
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.za.base.AppConfig
|
||||
import com.za.base.Const
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.room.RoomHelper
|
||||
@ -112,6 +114,18 @@ object GlobalData : GlobalLocalData() {
|
||||
field = value
|
||||
}
|
||||
|
||||
var networkEnv : Int
|
||||
get() {
|
||||
return if (AppConfig.isRelease) {
|
||||
mmkv.decodeInt("isReviewEnv", Const.NetEnv.Main)
|
||||
} else {
|
||||
mmkv.decodeInt("isReviewEnv", Const.NetEnv.CRM1)
|
||||
}
|
||||
}
|
||||
set(value) {
|
||||
mmkv.encode("isReviewEnv", value)
|
||||
}
|
||||
|
||||
fun clearUserCache() {
|
||||
token = null
|
||||
aesKey = null
|
||||
@ -119,6 +133,16 @@ object GlobalData : GlobalLocalData() {
|
||||
driverInfoBean = null
|
||||
loginTime = null
|
||||
isLoginRecognition = null
|
||||
|
||||
if (AppConfig.isRelease) {
|
||||
networkEnv = if (AppConfig.isRelease) {
|
||||
Const.NetEnv.Main
|
||||
} else {
|
||||
Const.NetEnv.CRM1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun clearAllOrderCache() {
|
||||
|
@ -18,13 +18,9 @@ object ZDManager {
|
||||
}
|
||||
|
||||
private fun thirdSdkInit(isRelease : Boolean = false) {
|
||||
if (isRelease) {
|
||||
AppConfig.release()
|
||||
} else {
|
||||
AppConfig.crm1()
|
||||
}
|
||||
GlobalData.application = application // 在 Application 中初始化 MMKV,所有进程共享同一存储路径
|
||||
MMKV.initialize(application)
|
||||
AppConfig.init(isRelease)
|
||||
Bugly.init(application, "6972a6b56d", true)
|
||||
LogUtil.init(application)
|
||||
RoomHelper.init(application)
|
||||
|
@ -0,0 +1,5 @@
|
||||
package com.za.common.util
|
||||
|
||||
class PermissionUtil {
|
||||
|
||||
}
|
@ -23,6 +23,7 @@ import com.za.bean.ReportHistoryRequest
|
||||
import com.za.bean.ReportInfoRequest
|
||||
import com.za.bean.ReportItem
|
||||
import com.za.bean.SettleInfoRequest
|
||||
import com.za.bean.TaskNotesBean
|
||||
import com.za.bean.TaskSettlementAndTraceBean
|
||||
import com.za.bean.UpdateVersionBean
|
||||
import com.za.bean.UpdateVersionRequest
|
||||
@ -61,6 +62,7 @@ import com.za.bean.request.SaveEleOrderRequest
|
||||
import com.za.bean.request.SwitchTaskRequest
|
||||
import com.za.bean.request.TaskFinishRequest
|
||||
import com.za.bean.request.TaskFinishResponse
|
||||
import com.za.bean.request.TaskNotesRequest
|
||||
import com.za.bean.request.TodayMaintainRequest
|
||||
import com.za.bean.request.TodayMaintainUploadRequest
|
||||
import com.za.bean.request.TodayMaintainbean
|
||||
@ -284,4 +286,7 @@ interface ApiService {
|
||||
|
||||
@POST("driverApp/supplier/iaiCompareFace")
|
||||
fun iaiCompareFace(@Body info : DriverFaceCompareRequest) : Observable<BaseResponse<IaiCompareFaceBean>>
|
||||
|
||||
@POST("driverApp/task/getTaskNotes")
|
||||
fun getTaskNotes(@Body request : TaskNotesRequest) : Observable<BaseResponse<TaskNotesBean>>
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import com.blankj.utilcode.util.ThreadUtils
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.google.gson.JsonParseException
|
||||
import com.za.base.Const
|
||||
import com.za.base.view.NetWarnBean
|
||||
import com.za.base.view.warnBean
|
||||
import com.za.bean.BaseResponse
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
@ -32,6 +34,11 @@ abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
|
||||
override fun onNext(tBaseResponse : BaseResponse<T>) {
|
||||
if (tBaseResponse.isOk) {
|
||||
doSuccess(tBaseResponse.result)
|
||||
ThreadUtils.runOnUiThread {
|
||||
if (warnBean.value != null && warnBean.value is NetWarnBean) {
|
||||
warnBean.value = null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
when (tBaseResponse.code) {
|
||||
3, 401 -> handlerTokenExpired()
|
||||
@ -67,15 +74,18 @@ abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
|
||||
|
||||
is ConnectException -> {
|
||||
doFailure(Const.NetWorkException, "与服务器断开连接")
|
||||
handlerNetError()
|
||||
}
|
||||
|
||||
is UnknownHostException -> {
|
||||
doFailure(Const.NetWorkException, "与服务器断开连接")
|
||||
handlerNetError()
|
||||
}
|
||||
|
||||
is SSLHandshakeException -> {
|
||||
doFailure(1, "证书验证失败")
|
||||
LogUtil.print("SSLHandshakeException", e)
|
||||
handlerNetError()
|
||||
}
|
||||
|
||||
is TimeoutException -> {
|
||||
@ -86,6 +96,7 @@ abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
|
||||
is SocketTimeoutException -> {
|
||||
doFailure(Const.NetWorkException, "网络连接超时2")
|
||||
LogUtil.print("SocketTimeoutException2", e)
|
||||
handlerNetError()
|
||||
}
|
||||
|
||||
else -> {
|
||||
@ -102,6 +113,15 @@ abstract class BaseObserver<T> : Observer<BaseResponse<T>> {
|
||||
|
||||
abstract fun doFailure(code : Int, msg : String?)
|
||||
|
||||
private fun handlerNetError() {
|
||||
ThreadUtils.runOnUiThread {
|
||||
if (warnBean.value == null) {
|
||||
warnBean.value = NetWarnBean("当前网络异常")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun handlerTokenExpired() {
|
||||
ThreadUtils.runOnUiThread {
|
||||
try {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.za.net
|
||||
|
||||
import android.util.Log
|
||||
import com.za.base.AppConfig
|
||||
import com.za.common.log.LogUtil
|
||||
import okhttp3.OkHttpClient
|
||||
@ -38,6 +37,11 @@ object RetrofitHelper {
|
||||
|
||||
}.setLevel(HttpLoggingInterceptor.Level.BODY)
|
||||
|
||||
fun reset() {
|
||||
apiService = null
|
||||
retrofit = null
|
||||
}
|
||||
|
||||
fun getDefaultService() : ApiService {
|
||||
return if (apiService == null) {
|
||||
apiService = getDefaultRetrofit().create(ApiService::class.java)
|
||||
|
@ -11,7 +11,7 @@ import com.za.room.db.GlobalRoom
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
object RoomHelper {
|
||||
const val VERSION: Int = 40
|
||||
const val VERSION: Int = 41
|
||||
private lateinit var mContext: Context
|
||||
var db: GlobalRoom? = null
|
||||
|
||||
|
@ -3,6 +3,7 @@ package com.za.service.mqtt
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.service.ServiceManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -59,7 +60,7 @@ object MyMqttClient {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
val message = String(mqttMessage.payload)
|
||||
LogUtil.print("MyMqttClient ", "Message arrived: $message")
|
||||
ServiceManager.handlerPushMsg(message) // Pass the message to ServiceManager for processing
|
||||
ServiceManager.handlerPushMsg(message)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,10 +97,11 @@ object MyMqttClient {
|
||||
//检测mqtt连接状态
|
||||
fun publishMessage() {
|
||||
if (mqttClient.isConnected) {
|
||||
LogUtil.print("MyMqttClient ", "publishMessage success")
|
||||
LogUtil.print("MyMqttClient ", "mqttClient.hasConnected")
|
||||
return
|
||||
}
|
||||
connect()
|
||||
LogUtil.print("MyMqttClient ", "mqttClient 断开重新初始化")
|
||||
ServiceManager.initialize(GlobalData.application)
|
||||
}
|
||||
|
||||
private fun subscribeTopic() {
|
||||
|
@ -7,7 +7,6 @@ import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.os.BaseBundle;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
|
@ -84,7 +84,6 @@ public class HandWriteEditView extends AppCompatEditText {
|
||||
|
||||
/**
|
||||
* 设置行高
|
||||
*
|
||||
*/
|
||||
public void setLineHeight(float lineHeight) {
|
||||
this.lineHeight = lineHeight;
|
||||
@ -102,7 +101,7 @@ public class HandWriteEditView extends AppCompatEditText {
|
||||
return null;
|
||||
}
|
||||
SpannableString mSpan = new SpannableString("1");
|
||||
mSpan.setSpan(new ImageSpan(getContext(), srcBitmap), mSpan.length() - 1, mSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
mSpan.setSpan(new ImageSpan(getContext(), srcBitmap, ImageSpan.ALIGN_BASELINE), mSpan.length() - 1, mSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
Editable editable = getText();
|
||||
//获取光标所在位置
|
||||
|
@ -0,0 +1,461 @@
|
||||
package com.za.ui.camera
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Bitmap.CompressFormat
|
||||
import android.graphics.Matrix
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.camera.core.CameraSelector
|
||||
import androidx.camera.core.ExperimentalGetImage
|
||||
import androidx.camera.core.ImageAnalysis
|
||||
import androidx.camera.core.ImageCapture
|
||||
import androidx.camera.core.ImageCaptureException
|
||||
import androidx.camera.core.ImageProxy
|
||||
import androidx.camera.view.LifecycleCameraController
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.blankj.utilcode.util.ImageUtils
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.mlkit.vision.common.InputImage
|
||||
import com.google.mlkit.vision.face.Face
|
||||
import com.google.mlkit.vision.face.FaceDetection
|
||||
import com.google.mlkit.vision.face.FaceDetectorOptions
|
||||
import com.za.bean.request.DriverFaceCompareBean
|
||||
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.net.BaseObserver
|
||||
import com.za.net.CommonMethod
|
||||
import com.za.net.RetrofitHelper
|
||||
import com.za.servicing.R
|
||||
import com.za.signature.view.CircleImageView
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.math.abs
|
||||
|
||||
class ServicePeopleRealActivity : AppCompatActivity() {
|
||||
private lateinit var lifecycleCameraController : LifecycleCameraController
|
||||
private lateinit var cameraExecutor : ExecutorService
|
||||
private var avatarBitmap : Bitmap? = null
|
||||
private var isActivityActive = true
|
||||
|
||||
private var currentStep = 0
|
||||
private val steps = listOf("请保持面部居中", "请向左转头", "请向右转头", "请保持面部居中")
|
||||
|
||||
private var isStepCompleted = false
|
||||
private lateinit var viewFinder : PreviewView
|
||||
private lateinit var stepText : TextView
|
||||
private lateinit var confirmationLayout : FrameLayout
|
||||
private lateinit var previewImage : CircleImageView
|
||||
private lateinit var retryButton : Button
|
||||
private lateinit var confirmButton : Button
|
||||
|
||||
private val faceDetector = FaceDetection.getClient(FaceDetectorOptions.Builder()
|
||||
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
|
||||
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
|
||||
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL).build())
|
||||
|
||||
private var loadingDialog : AlertDialog? = null
|
||||
|
||||
override fun onCreate(savedInstanceState : Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_service_people_real) // 初始化控制器
|
||||
lifecycleCameraController = LifecycleCameraController(this).apply {
|
||||
cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA
|
||||
setEnabledUseCases(LifecycleCameraController.IMAGE_CAPTURE or LifecycleCameraController.IMAGE_ANALYSIS)
|
||||
}
|
||||
|
||||
initializeViews()
|
||||
setupClickListeners()
|
||||
|
||||
if (allPermissionsGranted()) {
|
||||
startCamera()
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
|
||||
}
|
||||
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
updateStepUI()
|
||||
}
|
||||
|
||||
private fun initializeViews() {
|
||||
viewFinder = findViewById(R.id.viewFinder)
|
||||
viewFinder.controller = lifecycleCameraController // 将控制器与生命周期绑定
|
||||
lifecycleCameraController.bindToLifecycle(this)
|
||||
|
||||
stepText = findViewById(R.id.stepText)
|
||||
confirmationLayout = findViewById(R.id.confirmationLayout)
|
||||
previewImage = findViewById(R.id.previewImage)
|
||||
retryButton = findViewById(R.id.retryButton)
|
||||
confirmButton = findViewById(R.id.confirmButton)
|
||||
}
|
||||
|
||||
private fun setupClickListeners() {
|
||||
retryButton.setOnClickListener {
|
||||
resetDetection()
|
||||
}
|
||||
|
||||
confirmButton.setOnClickListener {
|
||||
returnPhotoResult()
|
||||
}
|
||||
}
|
||||
|
||||
private fun captureImage() {
|
||||
lifecycleCameraController.takePicture(ContextCompat.getMainExecutor(this),
|
||||
object : ImageCapture.OnImageCapturedCallback() {
|
||||
@OptIn(ExperimentalGetImage::class)
|
||||
override fun onCaptureSuccess(image : ImageProxy) {
|
||||
|
||||
val mediaImage = image.image
|
||||
LogUtil.print("拍照成功", image.imageInfo.toString())
|
||||
if (mediaImage != null) {
|
||||
val inputImage =
|
||||
InputImage.fromMediaImage(mediaImage, image.imageInfo.rotationDegrees)
|
||||
|
||||
faceDetector.process(inputImage).addOnSuccessListener { faces ->
|
||||
when {
|
||||
faces.isEmpty() -> {
|
||||
runOnUiThread {
|
||||
Toast.makeText(this@ServicePeopleRealActivity,
|
||||
"未检测到人脸",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
faces.size > 1 -> {
|
||||
runOnUiThread {
|
||||
Toast.makeText(this@ServicePeopleRealActivity,
|
||||
"检测到多个人脸,请确保画面中只有一个人脸",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
LogUtil.print("人脸检测成功", faces[0].toString())
|
||||
avatarBitmap = handlerBitmap(image.toBitmap(), image.imageInfo.rotationDegrees)
|
||||
LogUtil.print("人脸认证通过", faces[0].toString())
|
||||
runOnUiThread {
|
||||
showConfirmation()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.addOnFailureListener { e ->
|
||||
LogUtil.print("人脸检测失败", e)
|
||||
if (isActivityActive) {
|
||||
Toast.makeText(this@ServicePeopleRealActivity,
|
||||
"人脸检测失败",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}.addOnCompleteListener {
|
||||
image.close()
|
||||
}
|
||||
} else {
|
||||
image.close()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError(exc : ImageCaptureException) {
|
||||
LogUtil.print("拍照失败", exc)
|
||||
if (isActivityActive) {
|
||||
Toast.makeText(this@ServicePeopleRealActivity,
|
||||
"拍照失败",
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun isValidFace(face : Face, imageWidth : Int, imageHeight : Int) : Boolean {
|
||||
val faceBounds = face.boundingBox
|
||||
val faceCenterX = faceBounds.centerX()
|
||||
val faceCenterY = faceBounds.centerY()
|
||||
val imageCenterX = imageWidth / 2
|
||||
val imageCenterY = imageHeight / 2
|
||||
|
||||
// 计算人脸框占图片的比例
|
||||
val faceWidthRatio = faceBounds.width().toFloat() / imageWidth
|
||||
val faceHeightRatio = faceBounds.height().toFloat() / imageHeight
|
||||
|
||||
// 检查人脸是否居中(允许30%的偏移)
|
||||
val centerThreshold = imageWidth * 0.8f
|
||||
val isCentered =
|
||||
abs(faceCenterX - imageCenterX) < centerThreshold && abs(faceCenterY - imageCenterY) < centerThreshold
|
||||
|
||||
// 检查人脸大小是否合适(建议占据图片30%-70%的区域)
|
||||
val isProperSize = faceWidthRatio in 0.6f .. 0.7f && faceHeightRatio in 0.6f .. 0.7f
|
||||
|
||||
// 检查是否是正面人脸且睁眼
|
||||
val isFrontalFace = abs(face.headEulerAngleY) < 15 && // 左右角度
|
||||
abs(face.headEulerAngleX) < 15 && // 上下角度
|
||||
abs(face.headEulerAngleZ) < 15 && // 倾斜角度
|
||||
face.rightEyeOpenProbability != null && face.leftEyeOpenProbability != null && face.rightEyeOpenProbability !! > 0.8 && face.leftEyeOpenProbability !! > 0.8
|
||||
|
||||
return isCentered && isProperSize && isFrontalFace
|
||||
}
|
||||
|
||||
//校正图片,解决图片可能翻转的问题
|
||||
private val rotationMatrix = Matrix()
|
||||
private fun handlerBitmap(bitmap : Bitmap, degrees : Int?) : Bitmap {
|
||||
if (degrees == null || degrees == 0) return bitmap
|
||||
rotationMatrix.reset()
|
||||
rotationMatrix.postRotate(degrees.toFloat())
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, rotationMatrix, true)
|
||||
}
|
||||
|
||||
private fun resetDetection() {
|
||||
currentStep = 0
|
||||
isStepCompleted = false
|
||||
avatarBitmap = null
|
||||
confirmationLayout.visibility = View.GONE
|
||||
stepText.visibility = View.VISIBLE
|
||||
updateStepUI()
|
||||
}
|
||||
|
||||
private fun startCamera() {
|
||||
lifecycleCameraController.setImageAnalysisAnalyzer(ContextCompat.getMainExecutor(this@ServicePeopleRealActivity),
|
||||
FaceAnalyzer { handleFaceDetection(it) })
|
||||
}
|
||||
|
||||
private fun handleFaceDetection(eulerY : Float) {
|
||||
if (! isActivityActive) return
|
||||
|
||||
when (currentStep) {
|
||||
0 -> {
|
||||
if (abs(eulerY) < 15) {
|
||||
if (! isStepCompleted) {
|
||||
isStepCompleted = true
|
||||
proceedToNextStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1 -> {
|
||||
if (eulerY > 15) {
|
||||
if (! isStepCompleted) {
|
||||
isStepCompleted = true
|
||||
proceedToNextStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2 -> {
|
||||
if (eulerY < - 15) {
|
||||
if (! isStepCompleted) {
|
||||
isStepCompleted = true
|
||||
proceedToNextStep()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3 -> {
|
||||
if (abs(eulerY) < 15) {
|
||||
if (! isStepCompleted) {
|
||||
isStepCompleted = true
|
||||
runOnUiThread {
|
||||
captureImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showConfirmation() {
|
||||
avatarBitmap?.let { bitmap ->
|
||||
Glide.with(previewImage).load(bitmap).into(previewImage)
|
||||
confirmationLayout.visibility = View.VISIBLE
|
||||
stepText.visibility = View.GONE
|
||||
} ?: run {
|
||||
AlertDialog.Builder(this).setTitle("提示")
|
||||
.setMessage("未检测到有效的人脸照片,是否重新开始检测?")
|
||||
.setPositiveButton("重新检测") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
resetDetectionProcess()
|
||||
}.setNegativeButton("取消") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
}.setCancelable(false).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetDetectionProcess() {
|
||||
currentStep = 0
|
||||
isStepCompleted = false
|
||||
avatarBitmap = null
|
||||
|
||||
confirmationLayout.visibility = View.GONE
|
||||
stepText.visibility = View.VISIBLE
|
||||
stepText.text = steps[currentStep]
|
||||
|
||||
startCamera()
|
||||
}
|
||||
|
||||
private fun proceedToNextStep() {
|
||||
currentStep ++
|
||||
isStepCompleted = false
|
||||
if (currentStep < steps.size) {
|
||||
updateStepUI()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateStepUI() {
|
||||
stepText.visibility = View.VISIBLE
|
||||
stepText.text = steps[currentStep]
|
||||
|
||||
SpeechManager.releaseMediaPlayer()
|
||||
when (currentStep) {
|
||||
0 -> SpeechManager.playFaceCenter()
|
||||
1 -> SpeechManager.playFaceLeft()
|
||||
2 -> SpeechManager.playFaceRight()
|
||||
3 -> SpeechManager.playFaceCenter()
|
||||
}
|
||||
}
|
||||
|
||||
private fun returnPhotoResult() {
|
||||
avatarBitmap?.let { bitmap -> // 保存图片到临时文件
|
||||
val file = ImageUtils.save2Album(bitmap, CompressFormat.JPEG, 100)
|
||||
if (file?.exists() == true) { // 创建返回结果
|
||||
val resultIntent = Intent()
|
||||
resultIntent.putExtra("path", file.absolutePath)
|
||||
setResult(RESULT_OK, resultIntent)
|
||||
finish()
|
||||
} else {
|
||||
Toast.makeText(this, "照片保存失败,请重试", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
} ?: run {
|
||||
Toast.makeText(this, "未获取到有效的人脸照片,请重试", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissLoadingDialog() {
|
||||
loadingDialog?.dismiss()
|
||||
}
|
||||
|
||||
private fun showUploadFailedDialog() {
|
||||
AlertDialog.Builder(this).setTitle("上传失败").setMessage("人脸照片上传失败,请重新识别")
|
||||
.setPositiveButton("重新识别") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
resetDetection()
|
||||
}.setNegativeButton("取消") { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
}.setCancelable(false).show()
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun doUploadImg(file : File) {
|
||||
CommonMethod.uploadImage(file, success = {
|
||||
if (it.isNullOrBlank()) {
|
||||
ToastUtils.showLong("上传失败")
|
||||
return@uploadImage
|
||||
}
|
||||
doUpload(it)
|
||||
}, failed = {
|
||||
dismissLoadingDialog()
|
||||
showUploadFailedDialog()
|
||||
})
|
||||
}
|
||||
|
||||
private fun doUpload(url : String) {
|
||||
val request = DriverFaceCompareRequest(vehicleId = GlobalData.driverInfoBean?.vehicleId,
|
||||
driverId = GlobalData.driverInfoBean?.userId,
|
||||
photoUrl = url)
|
||||
RetrofitHelper.getDefaultService().driverFaceCompare(request).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<DriverFaceCompareBean>() {
|
||||
override fun doSuccess(it : DriverFaceCompareBean?) {
|
||||
ToastUtils.showLong("头像上传成功!")
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
LogUtil.print("doUpload addRealAvatarActivity failed",
|
||||
"code==$msg request==$request")
|
||||
showUploadFailedDialog()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
|
||||
ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode : Int,
|
||||
permissions : Array<String>,
|
||||
grantResults : IntArray) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
if (requestCode == REQUEST_CODE_PERMISSIONS) {
|
||||
if (allPermissionsGranted()) {
|
||||
startCamera()
|
||||
} else {
|
||||
Toast.makeText(this, "需要相机权限", Toast.LENGTH_SHORT).show()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
isActivityActive = true
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
isActivityActive = false
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
isActivityActive = false
|
||||
cameraExecutor.shutdown()
|
||||
}
|
||||
|
||||
private class FaceAnalyzer(private val listener : (Float) -> Unit) : ImageAnalysis.Analyzer {
|
||||
private val detector = FaceDetection.getClient(FaceDetectorOptions.Builder()
|
||||
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
|
||||
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_NONE)
|
||||
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_NONE).build())
|
||||
|
||||
@ExperimentalGetImage
|
||||
override fun analyze(imageProxy : ImageProxy) {
|
||||
val mediaImage = imageProxy.image
|
||||
if (mediaImage != null) {
|
||||
val image =
|
||||
InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
|
||||
|
||||
detector.process(image).addOnSuccessListener { faces ->
|
||||
if (faces.isNotEmpty()) {
|
||||
listener(faces[0].headEulerAngleY)
|
||||
}
|
||||
}.addOnCompleteListener {
|
||||
imageProxy.close()
|
||||
}
|
||||
} else {
|
||||
imageProxy.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REQUEST_CODE_PERMISSIONS = 10
|
||||
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
|
||||
}
|
||||
}
|
@ -7,12 +7,10 @@ import android.view.ViewGroup
|
||||
import android.webkit.JavascriptInterface
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.statusBarsPadding
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -33,7 +31,6 @@ import com.tencent.smtt.sdk.WebView.setWebContentsDebuggingEnabled
|
||||
import com.tencent.smtt.sdk.WebViewClient
|
||||
import com.za.base.AppConfig
|
||||
import com.za.base.BaseActivity
|
||||
import com.za.base.theme.headPadding
|
||||
import com.za.base.view.HeadView
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
@ -168,11 +165,6 @@ private fun CommonH5Screen(url : String,
|
||||
Scaffold(topBar = {
|
||||
if (title.isNotBlank()) {
|
||||
HeadView(title = title, onBack = { handleBackPress(context, webView) })
|
||||
} else {
|
||||
Spacer(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.statusBarsPadding()
|
||||
.padding(vertical = headPadding))
|
||||
}
|
||||
}) { paddingValues ->
|
||||
Box(modifier = Modifier
|
||||
|
@ -42,7 +42,6 @@ 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.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
@ -76,6 +75,7 @@ import com.za.ext.callPhone
|
||||
import com.za.ext.copy
|
||||
import com.za.ext.finish
|
||||
import com.za.servicing.R
|
||||
import com.za.ui.servicing.in_servicing_setting.OrderTaskNotesDialog
|
||||
|
||||
class NewOrderActivity : BaseActivity() {
|
||||
|
||||
@ -198,6 +198,28 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
|
||||
})
|
||||
}
|
||||
|
||||
if (uiState.value.acceptOrderDialog == true) {
|
||||
CommonDialog(title = "请确认是否接受该任务!",
|
||||
confirmText = "确认接单",
|
||||
cancelText = "再想想",
|
||||
cancelEnable = false,
|
||||
confirm = {
|
||||
vm.updateState(uiState.value.copy(acceptOrderDialog = false))
|
||||
vm.dispatch(NewOrderVm.Action.ShowTaskNotes)
|
||||
},
|
||||
cancel = {},
|
||||
dismiss = {})
|
||||
}
|
||||
|
||||
if (uiState.value.showTaskNotesDialog == true) {
|
||||
OrderTaskNotesDialog(uiState.value.taskNotesBean,
|
||||
uiState.value.jpushBean?.hasReplaceBatteryCapable == 2,
|
||||
dismiss = {},
|
||||
confirm = {
|
||||
vm.dispatch(NewOrderVm.Action.AcceptOrder)
|
||||
})
|
||||
}
|
||||
|
||||
BottomSheetScaffold(scaffoldState = scaffoldState,
|
||||
topBar = { HeadViewNotBack(title = "新订单") },
|
||||
sheetContent = {
|
||||
@ -377,7 +399,7 @@ private fun AcceptOrderScreen(jpushBean : JpushBean?, vm : NewOrderVm = viewMode
|
||||
}
|
||||
|
||||
// 接单按钮
|
||||
Button(onClick = { vm.dispatch(NewOrderVm.Action.AcceptOrder) },
|
||||
Button(onClick = { vm.dispatch(NewOrderVm.Action.ShowTaskNotes) },
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(44.dp),
|
||||
|
@ -15,8 +15,10 @@ import com.blankj.utilcode.util.ToastUtils
|
||||
import com.za.base.BaseVm
|
||||
import com.za.base.view.LoadingManager
|
||||
import com.za.bean.JpushBean
|
||||
import com.za.bean.TaskNotesBean
|
||||
import com.za.bean.request.AcceptOrderRequest
|
||||
import com.za.bean.request.RefuseOrderRequest
|
||||
import com.za.bean.request.TaskNotesRequest
|
||||
import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.common.util.DeviceUtil
|
||||
@ -37,237 +39,272 @@ import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class NewOrderVm : BaseVm<NewOrderVm.Action, NewOrderVm.UiState>() {
|
||||
private val _uiState = MutableStateFlow(UiState())
|
||||
val uiState get() = _uiState
|
||||
private val _uiState = MutableStateFlow(UiState())
|
||||
val uiState get() = _uiState
|
||||
|
||||
private var timerJob: Job? = null
|
||||
private var timerJob : Job? = null
|
||||
|
||||
override fun dispatch(action: Action) {
|
||||
when (action) {
|
||||
is Action.Init -> init(action.jpushBean)
|
||||
is Action.AcceptOrder -> acceptOrder()
|
||||
is Action.RefuseOrder -> refuseOrder()
|
||||
is Action.StartTimer -> startTimer()
|
||||
is Action.UpdateTimer -> updateTimer(action.remainingTime)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
override fun dispatch(action : Action) {
|
||||
when (action) {
|
||||
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 -> {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateState(uiState: UiState) {
|
||||
_uiState.value = uiState
|
||||
}
|
||||
override fun updateState(uiState : UiState) {
|
||||
_uiState.value = uiState
|
||||
}
|
||||
|
||||
private fun init(jpushBean: JpushBean?) {
|
||||
updateState(uiState.value.copy(jpushBean = jpushBean))
|
||||
buildMarkers(jpushBean)
|
||||
searchDrivingRoute(jpushBean)
|
||||
startTimer()
|
||||
}
|
||||
private fun init(jpushBean : JpushBean?) {
|
||||
updateState(uiState.value.copy(jpushBean = jpushBean))
|
||||
buildMarkers(jpushBean)
|
||||
searchDrivingRoute(jpushBean)
|
||||
startTimer()
|
||||
getTaskNote()
|
||||
}
|
||||
|
||||
private fun buildMarkers(jpushBean: JpushBean?) {
|
||||
val markers = arrayListOf<MarkerOptions>()
|
||||
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)
|
||||
markers.add(startMarkers)
|
||||
}
|
||||
private fun getTaskNote() {
|
||||
val taskNotesRequest = TaskNotesRequest(taskId = uiState.value.jpushBean?.taskId)
|
||||
RetrofitHelper.getDefaultService().getTaskNotes(taskNotesRequest)
|
||||
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<TaskNotesBean>() {
|
||||
override fun doSuccess(it : TaskNotesBean?) {
|
||||
updateState(uiState.value.copy(taskNotesBean = it))
|
||||
}
|
||||
|
||||
if (jpushBean?.distLat != null && jpushBean.distLat != 0.0 && jpushBean.distLng != null && jpushBean.distLng != 0.0) {
|
||||
val startMarkers = 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)
|
||||
}
|
||||
updateState(uiState.value.copy(markers = markers))
|
||||
}
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
LogUtil.print("获取任务备注失败", "request=$taskNotesRequest msg=$msg")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun acceptOrder() {
|
||||
LoadingManager.showLoading()
|
||||
ZdLocationManager.getSingleLocation(success = {
|
||||
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 = it.latitude
|
||||
acceptOrderRequest.lng = it.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()))
|
||||
}
|
||||
private fun buildMarkers(jpushBean : JpushBean?) {
|
||||
val markers = arrayListOf<MarkerOptions>()
|
||||
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)
|
||||
markers.add(startMarkers)
|
||||
}
|
||||
|
||||
override fun doFailure(code: Int, msg: String?) {
|
||||
LoadingManager.hideLoading()
|
||||
LogUtil.print("接单失败", "request=$acceptOrderRequest msg=$msg")
|
||||
}
|
||||
})
|
||||
}, failed = {
|
||||
LoadingManager.hideLoading()
|
||||
LogUtil.print("接单时获取定位失败", it)
|
||||
})
|
||||
}
|
||||
if (jpushBean?.distLat != null && jpushBean.distLat != 0.0 && jpushBean.distLng != null && jpushBean.distLng != 0.0) {
|
||||
val startMarkers =
|
||||
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)
|
||||
}
|
||||
updateState(uiState.value.copy(markers = markers))
|
||||
}
|
||||
|
||||
private fun refuseOrder() {
|
||||
LoadingManager.showLoading()
|
||||
RetrofitHelper.getDefaultService().refuseOrder(RefuseOrderRequest(taskId = uiState.value.jpushBean?.taskId,
|
||||
vehicleId = GlobalData.driverInfoBean?.vehicleId,
|
||||
taskCode = uiState.value.jpushBean?.taskCode,
|
||||
userId = GlobalData.driverInfoBean?.userId))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<String>() {
|
||||
override fun doSuccess(it: String?) {
|
||||
LoadingManager.hideLoading()
|
||||
updateState(uiState.value.copy(refuseSuccess = true))
|
||||
LogUtil.print("refuseOrder", "订单拒绝成功")
|
||||
}
|
||||
private fun showTaskNotes() {
|
||||
if (uiState.value.taskNotesBean != null && isNeedShowNotes()) {
|
||||
updateState(uiState.value.copy(showTaskNotesDialog = true))
|
||||
return
|
||||
}
|
||||
|
||||
override fun doFailure(code: Int, msg: String?) {
|
||||
LoadingManager.hideLoading()
|
||||
ToastUtils.showShort(msg)
|
||||
LogUtil.print("refuseOrder", "failed=$msg")
|
||||
}
|
||||
})
|
||||
}
|
||||
acceptOrder()
|
||||
}
|
||||
|
||||
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 acceptOrder() {
|
||||
LoadingManager.showLoading()
|
||||
ZdLocationManager.getSingleLocation(success = {
|
||||
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 = it.latitude
|
||||
acceptOrderRequest.lng = it.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()))
|
||||
}
|
||||
|
||||
private fun updateTimer(remainingTime: Int) {
|
||||
updateState(uiState.value.copy(remainingTime = remainingTime))
|
||||
}
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
LoadingManager.hideLoading()
|
||||
LogUtil.print("接单失败", "request=$acceptOrderRequest msg=$msg")
|
||||
}
|
||||
})
|
||||
}, failed = {
|
||||
LoadingManager.hideLoading()
|
||||
LogUtil.print("接单时获取定位失败", it)
|
||||
})
|
||||
}
|
||||
|
||||
private fun searchDrivingRoute(jpushBean: JpushBean?) {
|
||||
if (GlobalData.currentLocation == null) {
|
||||
ToastUtils.showShort("获取当前位置失败")
|
||||
return
|
||||
}
|
||||
private fun refuseOrder() {
|
||||
LoadingManager.showLoading()
|
||||
RetrofitHelper.getDefaultService()
|
||||
.refuseOrder(RefuseOrderRequest(taskId = uiState.value.jpushBean?.taskId,
|
||||
vehicleId = GlobalData.driverInfoBean?.vehicleId,
|
||||
taskCode = uiState.value.jpushBean?.taskCode,
|
||||
userId = GlobalData.driverInfoBean?.userId)).subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread()).subscribe(object : BaseObserver<String>() {
|
||||
override fun doSuccess(it : String?) {
|
||||
LoadingManager.hideLoading()
|
||||
updateState(uiState.value.copy(refuseSuccess = true))
|
||||
LogUtil.print("refuseOrder", "订单拒绝成功")
|
||||
}
|
||||
|
||||
updateState(uiState.value.copy(isLoading = true))
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
LoadingManager.hideLoading()
|
||||
ToastUtils.showShort(msg)
|
||||
LogUtil.print("refuseOrder", "failed=$msg")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
val startPoint = LatLonPoint(
|
||||
GlobalData.currentLocation?.latitude ?: 0.0,
|
||||
GlobalData.currentLocation?.longitude ?: 0.0
|
||||
)
|
||||
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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val endPoint = when {
|
||||
jpushBean?.distLat != null && jpushBean.distLat != 0.0 &&
|
||||
jpushBean.distLng != null && jpushBean.distLng != 0.0 -> {
|
||||
LatLonPoint(jpushBean.distLat, jpushBean.distLng)
|
||||
}
|
||||
jpushBean?.lat != null && jpushBean.lat != 0.0 &&
|
||||
jpushBean.lng != null && jpushBean.lng != 0.0 -> {
|
||||
LatLonPoint(jpushBean.lat, jpushBean.lng)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
private fun isNeedShowNotes() : Boolean {
|
||||
if (! uiState.value.taskNotesBean?.taskNotes.isNullOrBlank()) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (endPoint == null) return
|
||||
if (! uiState.value.taskNotesBean?.customerNotes.isNullOrBlank()) {
|
||||
return true
|
||||
}
|
||||
|
||||
val fromAndTo = RouteSearch.FromAndTo(startPoint, endPoint)
|
||||
val query = RouteSearch.DriveRouteQuery(fromAndTo, RouteSearch.DrivingDefault, null, null, "")
|
||||
if (! uiState.value.taskNotesBean?.feeStandard.isNullOrBlank()) {
|
||||
return true
|
||||
}
|
||||
|
||||
RouteSearch(GlobalData.application).apply {
|
||||
setRouteSearchListener(object : RouteSearch.OnRouteSearchListener {
|
||||
override fun onDriveRouteSearched(result: DriveRouteResult?, errorCode: Int) {
|
||||
updateState(uiState.value.copy(isLoading = false))
|
||||
|
||||
if (errorCode == 1000 && result != null && result.paths.isNotEmpty()) {
|
||||
val path = result.paths[0]
|
||||
val points = path.steps.flatMap { step ->
|
||||
step.polyline.map { LatLng(it.latitude, it.longitude) }
|
||||
}
|
||||
|
||||
val duration = path.duration
|
||||
val arrivalTime = System.currentTimeMillis() + duration * 1000
|
||||
val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
val estimatedTime = dateFormat.format(Date(arrivalTime))
|
||||
|
||||
updateState(uiState.value.copy(
|
||||
routePoints = points,
|
||||
remainingDistance = path.distance.toDouble(),
|
||||
estimatedArrivalTime = estimatedTime
|
||||
))
|
||||
} else {
|
||||
ToastUtils.showShort("路线规划失败,请重试")
|
||||
LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode")
|
||||
}
|
||||
}
|
||||
if (! uiState.value.taskNotesBean?.otherNotes.isNullOrBlank()) {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onBusRouteSearched(p0: BusRouteResult?, p1: Int) {}
|
||||
override fun onWalkRouteSearched(p0: WalkRouteResult?, p1: Int) {}
|
||||
override fun onRideRouteSearched(p0: RideRouteResult?, p1: Int) {}
|
||||
})
|
||||
calculateDriveRouteAsyn(query)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
try {
|
||||
timerJob?.cancel()
|
||||
timerJob = null
|
||||
} catch (e: Exception) {
|
||||
LogUtil.print("onCleared", "取消倒计时异常: ${e.message}")
|
||||
}
|
||||
}
|
||||
private fun updateTimer(remainingTime : Int) {
|
||||
updateState(uiState.value.copy(remainingTime = remainingTime))
|
||||
}
|
||||
|
||||
sealed class Action {
|
||||
data class Init(val jpushBean: JpushBean?) : Action()
|
||||
data object AcceptOrder : Action()
|
||||
data class UpdateState(val uiState: UiState) : Action()
|
||||
data object RefuseOrder : Action()
|
||||
data object StartTimer : Action()
|
||||
data class UpdateTimer(val remainingTime: Int) : Action()
|
||||
}
|
||||
private fun searchDrivingRoute(jpushBean : JpushBean?) {
|
||||
if (GlobalData.currentLocation == null) {
|
||||
ToastUtils.showShort("获取当前位置失败")
|
||||
return
|
||||
}
|
||||
|
||||
data class UiState(
|
||||
val jpushBean: JpushBean? = null,
|
||||
val showCallPhoneDialog: Boolean? = false,
|
||||
val markers: ArrayList<MarkerOptions>? = null,
|
||||
val refuseSuccess: Boolean? = false,
|
||||
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
|
||||
)
|
||||
updateState(uiState.value.copy(isLoading = true))
|
||||
|
||||
val startPoint = LatLonPoint(GlobalData.currentLocation?.latitude ?: 0.0,
|
||||
GlobalData.currentLocation?.longitude ?: 0.0)
|
||||
|
||||
val endPoint = when {
|
||||
jpushBean?.distLat != null && jpushBean.distLat != 0.0 && jpushBean.distLng != null && jpushBean.distLng != 0.0 -> {
|
||||
LatLonPoint(jpushBean.distLat, jpushBean.distLng)
|
||||
}
|
||||
|
||||
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, "")
|
||||
|
||||
RouteSearch(GlobalData.application).apply {
|
||||
setRouteSearchListener(object : RouteSearch.OnRouteSearchListener {
|
||||
override fun onDriveRouteSearched(result : DriveRouteResult?, errorCode : Int) {
|
||||
updateState(uiState.value.copy(isLoading = false))
|
||||
|
||||
if (errorCode == 1000 && result != null && result.paths.isNotEmpty()) {
|
||||
val path = result.paths[0]
|
||||
val points = path.steps.flatMap { step ->
|
||||
step.polyline.map { LatLng(it.latitude, it.longitude) }
|
||||
}
|
||||
|
||||
val duration = path.duration
|
||||
val arrivalTime = System.currentTimeMillis() + duration * 1000
|
||||
val dateFormat = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||
val estimatedTime = dateFormat.format(Date(arrivalTime))
|
||||
|
||||
updateState(uiState.value.copy(routePoints = points,
|
||||
remainingDistance = path.distance.toDouble(),
|
||||
estimatedArrivalTime = estimatedTime))
|
||||
} else {
|
||||
ToastUtils.showShort("路线规划失败,请重试")
|
||||
LogUtil.print("searchDrivingRoute", "路径规划失败: errorCode=$errorCode")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBusRouteSearched(p0 : BusRouteResult?, p1 : Int) {}
|
||||
override fun onWalkRouteSearched(p0 : WalkRouteResult?, p1 : Int) {}
|
||||
override fun onRideRouteSearched(p0 : RideRouteResult?, p1 : Int) {}
|
||||
})
|
||||
calculateDriveRouteAsyn(query)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
try {
|
||||
timerJob?.cancel()
|
||||
timerJob = null
|
||||
} catch (e : Exception) {
|
||||
LogUtil.print("onCleared", "取消倒计时异常: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Action {
|
||||
data class Init(val jpushBean : JpushBean?) : Action()
|
||||
data object AcceptOrder : Action()
|
||||
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,
|
||||
val showCallPhoneDialog : Boolean? = false,
|
||||
val markers : ArrayList<MarkerOptions>? = null,
|
||||
val refuseSuccess : Boolean? = false,
|
||||
val taskNotesBean : TaskNotesBean? = null,
|
||||
val showTaskNotesDialog : 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)
|
||||
|
||||
|
||||
}
|
@ -39,14 +39,12 @@ import com.za.base.theme.bgColor
|
||||
import com.za.base.theme.black5
|
||||
import com.za.base.theme.headBgColor
|
||||
import com.za.base.view.ChoiceMapDialog
|
||||
import com.za.base.view.CommonButton
|
||||
import com.za.base.view.CommonDialog
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
import com.za.ext.callPhone
|
||||
import com.za.ext.convertToFlowName
|
||||
import com.za.ext.copy
|
||||
import com.za.servicing.R
|
||||
import com.za.ui.servicing.order_give_up.OrderGiveUpActivity
|
||||
|
||||
@Composable
|
||||
fun OrderDetailItemScreen(orderInfo : OrderInfo?) {
|
||||
@ -57,6 +55,7 @@ fun OrderDetailItemScreen(orderInfo : OrderInfo?) {
|
||||
.padding(5.dp)) {
|
||||
OrderDetailBaseInformationView(orderInfo = orderInfo)
|
||||
OrderDetailServiceInformationView(orderInfo = orderInfo)
|
||||
OrderDetailTime(orderInfo = orderInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,18 +186,40 @@ 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?.carModel}",
|
||||
color = contentColor,
|
||||
fontSize = titleSize,
|
||||
fontWeight = FontWeight.Medium)
|
||||
|
||||
if (! orderInfo?.carModel.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?.carModel}",
|
||||
color = contentColor,
|
||||
fontSize = titleSize,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
//拖车责任险
|
||||
if (! orderInfo?.policyNo.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?.policyNo}",
|
||||
color = contentColor,
|
||||
fontSize = titleSize,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -211,7 +232,6 @@ private fun OrderDetailServiceInformationView(orderInfo : OrderInfo?) {
|
||||
val titleSize = 12.sp
|
||||
val titleColor = Color(0xFF7A7A7A)
|
||||
val contentColor = Color.Black
|
||||
val context = LocalContext.current
|
||||
|
||||
// 1 事发地 2 目的地
|
||||
var showChoiceMapDialog by remember { mutableStateOf<Int?>(null) }
|
||||
@ -355,11 +375,77 @@ private fun OrderDetailServiceInformationView(orderInfo : OrderInfo?) {
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
CommonButton(text = "客户放弃") {
|
||||
OrderGiveUpActivity.goOrderGiveUpActivity(context,
|
||||
orderInfo = orderInfo,
|
||||
userOrderId = orderInfo?.userOrderId,
|
||||
giveUpType = 0)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OrderDetailTime(orderInfo : OrderInfo?) {
|
||||
val titleSize = 12.sp
|
||||
val titleColor = Color(0xFF7A7A7A)
|
||||
val contentColor = Color.Black
|
||||
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(color = Color.White, shape = RoundedCornerShape(4.dp))
|
||||
.padding(10.dp),
|
||||
verticalArrangement = Arrangement.Top) {
|
||||
Box(contentAlignment = Alignment.CenterStart) {
|
||||
Text(text = "订单时间",
|
||||
color = Color.Black,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp)
|
||||
}
|
||||
HorizontalDivider(color = black5, modifier = Modifier.padding(vertical = 10.dp))
|
||||
|
||||
if (! orderInfo?.acceptTime.isNullOrBlank()) {
|
||||
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?.acceptTime}",
|
||||
color = contentColor,
|
||||
fontSize = titleSize,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
if (! orderInfo?.arriveTime.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?.arriveTime}",
|
||||
color = contentColor,
|
||||
fontSize = titleSize,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
if (! orderInfo?.arriveDestTime.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?.arriveDestTime}",
|
||||
color = contentColor,
|
||||
fontSize = titleSize,
|
||||
fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
@ -28,9 +28,11 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
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.ui.servicing.order_give_up.OrderGiveUpActivity
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
@ -41,6 +43,13 @@ fun OrderDetailScreen(orderInfo : OrderInfo?) {
|
||||
val scope = rememberCoroutineScope()
|
||||
Scaffold(topBar = {
|
||||
HeadView(title = "订单信息", onBack = { context.finish() })
|
||||
}, bottomBar = {
|
||||
CommonButton(text = "客户放弃") {
|
||||
OrderGiveUpActivity.goOrderGiveUpActivity(context,
|
||||
orderInfo = orderInfo,
|
||||
userOrderId = orderInfo?.userOrderId,
|
||||
giveUpType = 0)
|
||||
}
|
||||
}) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
@ -1,5 +1,8 @@
|
||||
package com.za.ui.servicing.in_servicing_setting
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
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
|
||||
@ -9,9 +12,14 @@ 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.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Warning
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -21,9 +29,13 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import coil.compose.AsyncImage
|
||||
import com.za.base.theme.black5
|
||||
import com.za.base.theme.black65
|
||||
import com.za.base.view.CommonButton
|
||||
import com.za.bean.TaskNotesBean
|
||||
import com.za.bean.db.order.OrderInfo
|
||||
import com.za.servicing.R
|
||||
|
||||
@ -49,10 +61,10 @@ fun OrderRequirementsScreen(orderInfo : OrderInfo?) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OrderRequirementsItemView(title : String?, content : String?) {
|
||||
fun OrderRequirementsItemView(title : String?, content : String?) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 12.dp)) {
|
||||
.padding(vertical = 5.dp)) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
AsyncImage(model = R.drawable.sv_warn_red,
|
||||
contentDescription = null,
|
||||
@ -76,10 +88,10 @@ private fun OrderRequirementsItemView(title : String?, content : String?) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CarModeView(orderInfo : OrderInfo?) {
|
||||
fun CarModeView(orderInfo : OrderInfo?) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 12.dp)) {
|
||||
.padding(vertical = 5.dp)) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
AsyncImage(model = R.drawable.sv_warn_red,
|
||||
contentDescription = null,
|
||||
@ -100,4 +112,90 @@ private fun CarModeView(orderInfo : OrderInfo?) {
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
HorizontalDivider(color = black5, modifier = Modifier.fillMaxWidth())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OrderTaskNotesDialog(taskNotesBean : TaskNotesBean?,
|
||||
isShowChangeBattery : Boolean? = false,
|
||||
dismiss : () -> Unit,
|
||||
confirm : () -> Unit) {
|
||||
|
||||
Dialog(onDismissRequest = { dismiss() },
|
||||
properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)) {
|
||||
Box(contentAlignment = Alignment.BottomCenter,
|
||||
modifier = Modifier.background(color = Color.White,
|
||||
shape = RoundedCornerShape(13.dp))) {
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(horizontal = 10.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Top) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 10.dp)) {
|
||||
Text("合同名称",
|
||||
color = Color.Black,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Medium)
|
||||
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
Text("平安保险",
|
||||
color = Color.Black,
|
||||
fontSize = 15.sp,
|
||||
fontWeight = FontWeight.Bold)
|
||||
}
|
||||
|
||||
HorizontalDivider(color = black5, modifier = Modifier.padding(vertical = 10.dp))
|
||||
|
||||
if (! taskNotesBean?.otherNotes.isNullOrBlank()) {
|
||||
OrderRequirementsItemView(title = "特殊提醒",
|
||||
content = taskNotesBean?.otherNotes)
|
||||
}
|
||||
|
||||
if (! taskNotesBean?.feeStandard.isNullOrBlank()) {
|
||||
OrderRequirementsItemView(title = "收费标准",
|
||||
content = taskNotesBean?.feeStandard)
|
||||
}
|
||||
|
||||
if (! taskNotesBean?.modelVinNo.isNullOrBlank()) {
|
||||
OrderRequirementsItemView(title = "车型", content = taskNotesBean?.modelVinNo)
|
||||
}
|
||||
|
||||
if (! taskNotesBean?.taskNotes.isNullOrBlank()) {
|
||||
OrderRequirementsItemView(title = "救援要求",
|
||||
content = taskNotesBean?.taskNotes)
|
||||
}
|
||||
|
||||
if (! taskNotesBean?.customerNotes.isNullOrBlank()) {
|
||||
OrderRequirementsItemView(title = "客户要求",
|
||||
content = taskNotesBean?.customerNotes)
|
||||
}
|
||||
|
||||
if (isShowChangeBattery == true) {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Row(modifier = Modifier.padding(vertical = 10.dp, horizontal = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(imageVector = Icons.Default.Warning,
|
||||
tint = Color.Red,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.size(24.dp))
|
||||
Text("此订单不允许销售电瓶",
|
||||
color = Color.Red,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
modifier = Modifier.padding(start = 8.dp))
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(65.dp))
|
||||
}
|
||||
|
||||
CommonButton(text = "我已阅读") { confirm() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ import com.za.common.GlobalData
|
||||
import com.za.common.log.LogUtil
|
||||
import com.za.ext.goNextPage
|
||||
import com.za.servicing.R
|
||||
import com.za.ui.camera.ZdCameraXActivity
|
||||
import com.za.ui.camera.ServicePeopleRealActivity
|
||||
|
||||
@Composable
|
||||
fun ServicePeopleConfirmScreen(vm : InServicePeopleConfirmVm = viewModel(),
|
||||
@ -86,8 +86,7 @@ fun ServicePeopleConfirmScreen(vm : InServicePeopleConfirmVm = viewModel(),
|
||||
confirmText = "重新认证",
|
||||
confirm = {
|
||||
vm.updateState(uiState.value.copy(showCompareFailedDialog = null))
|
||||
val intent = Intent(context, ZdCameraXActivity::class.java)
|
||||
intent.putExtra("isBack", false)
|
||||
val intent = Intent(context, ServicePeopleRealActivity::class.java)
|
||||
getResult.launch(intent)
|
||||
},
|
||||
cancelText = "关闭",
|
||||
@ -166,8 +165,7 @@ fun ServicePeopleConfirmScreen(vm : InServicePeopleConfirmVm = viewModel(),
|
||||
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
CommonButton(text = "开始核验", onClick = {
|
||||
val intent = Intent(context, ZdCameraXActivity::class.java)
|
||||
intent.putExtra("isBack", false)
|
||||
val intent = Intent(context, ServicePeopleRealActivity::class.java)
|
||||
getResult.launch(intent)
|
||||
})
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ class ConfirmH5SuccessVm : IServicingVm<ConfirmH5SuccessVm.Action, ConfirmH5Succ
|
||||
is Action.UpdateState -> updateState(action.uiState)
|
||||
is Action.TaskFinish -> taskFinish()
|
||||
is Action.ClearOfflineTask -> clearCurrentOrderOfflineTask()
|
||||
is Action.UpdateCurrentEleWorkOrder->updateCurrentEleWorkOrder(action.type, action.path)
|
||||
is Action.UpdateCurrentEleWorkOrder -> updateCurrentEleWorkOrder(action.type,
|
||||
action.path)
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,13 +215,14 @@ class ConfirmH5SuccessVm : IServicingVm<ConfirmH5SuccessVm.Action, ConfirmH5Succ
|
||||
updateState(uiState.value.copy(goNextPage = true))
|
||||
return
|
||||
}
|
||||
updateState(uiState.value.copy(loadingState = LoadingState.LoadingFailed))
|
||||
updateState(uiState.value.copy(loadingState = LoadingState.LoadingFailed(msg)))
|
||||
LogUtil.print("任务失败", "code==$code msg==$msg")
|
||||
}
|
||||
})
|
||||
}, failed = {
|
||||
LoadingManager.hideLoading()
|
||||
updateState(uiState.value.copy(loadingState = LoadingState.LoadingFailed))
|
||||
ToastUtils.showLong(it)
|
||||
updateState(uiState.value.copy(loadingState = LoadingState.LoadingFailed(it)))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -12,65 +12,77 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.za.base.BaseActivity
|
||||
import com.za.base.view.CommonDialog
|
||||
import com.za.base.view.LoadingManager
|
||||
import com.za.room.RoomHelper
|
||||
import com.za.ui.servicing.order_confirm.input_money.InputMoneyActivity
|
||||
import com.za.ui.servicing.order_confirm.real_order_confirm.RealOrderConfirmActivity
|
||||
import com.za.ui.servicing.order_confirm.receive_money.ReceiveMoneyActivity
|
||||
|
||||
class OrderConfirmActivity : BaseActivity() {
|
||||
|
||||
@Composable
|
||||
override fun ContentView() {
|
||||
OrderConfirmInitScreen()
|
||||
}
|
||||
@Composable
|
||||
override fun ContentView() {
|
||||
OrderConfirmInitScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OrderConfirmInitScreen(vm: OrderConfirmInitVm = viewModel()) {
|
||||
val uiState = vm.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
vm.dispatch(OrderConfirmInitVm.Action.Init)
|
||||
}
|
||||
fun OrderConfirmInitScreen(vm : OrderConfirmInitVm = viewModel()) {
|
||||
val uiState = vm.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
vm.dispatch(OrderConfirmInitVm.Action.Init)
|
||||
}
|
||||
|
||||
if (uiState.value.showNoNeedPayDialog == true) {
|
||||
CommonDialog(title = "是否需要收款?", confirmText = "去收款", cancelText = "无需收款",
|
||||
confirm = {
|
||||
vm.updateState(uiState.value.copy(showNoNeedPayDialog = false))
|
||||
InputMoneyActivity.goInputMoney(context, userOrderId = uiState.value.orderInfo?.userOrderId
|
||||
?: 0, taskId = uiState.value.orderInfo?.taskId ?: 0)
|
||||
},
|
||||
cancel = {
|
||||
vm.updateState(uiState.value.copy(showNoNeedPayDialog = false, orderConfirmState = OrderConfirmInitVm.OrderConfirmState.OrderConfirm))
|
||||
},
|
||||
dismiss = {
|
||||
vm.updateState(uiState.value.copy(showNoNeedPayDialog = false, orderConfirmState = OrderConfirmInitVm.OrderConfirmState.OrderConfirm))
|
||||
})
|
||||
}
|
||||
if (uiState.value.showNoNeedPayDialog == true) {
|
||||
CommonDialog(title = "是否需要收款?",
|
||||
confirmText = "去收款",
|
||||
cancelText = "无需收款",
|
||||
confirm = {
|
||||
vm.updateState(uiState.value.copy(showNoNeedPayDialog = false))
|
||||
InputMoneyActivity.goInputMoney(context,
|
||||
userOrderId = uiState.value.orderInfo?.userOrderId ?: 0,
|
||||
taskId = uiState.value.orderInfo?.taskId ?: 0)
|
||||
},
|
||||
cancel = {
|
||||
uiState.value.eleWorkOrderBean?.copy(driverChoiceNoNeedReceiveMoney = true)?.let {
|
||||
RoomHelper.db?.eleWorkOrderDao()?.update(it)
|
||||
}
|
||||
vm.updateState(uiState.value.copy(showNoNeedPayDialog = false,
|
||||
orderConfirmState = OrderConfirmInitVm.OrderConfirmState.Init))
|
||||
vm.dispatch(OrderConfirmInitVm.Action.Init)
|
||||
},
|
||||
dismiss = {
|
||||
vm.updateState(uiState.value.copy(showNoNeedPayDialog = false,
|
||||
orderConfirmState = OrderConfirmInitVm.OrderConfirmState.Init))
|
||||
vm.dispatch(OrderConfirmInitVm.Action.Init)
|
||||
})
|
||||
}
|
||||
|
||||
when (uiState.value.orderConfirmState) {
|
||||
is OrderConfirmInitVm.OrderConfirmState.ChangeBattery -> ChangeBatteryScreen()
|
||||
is OrderConfirmInitVm.OrderConfirmState.ConfirmEle -> ConfirmEleScreen()
|
||||
is OrderConfirmInitVm.OrderConfirmState.ConfirmH5Success -> ConfirmH5SuccessScreen()
|
||||
is OrderConfirmInitVm.OrderConfirmState.Init -> {
|
||||
Box {
|
||||
LoadingManager.showLoading()
|
||||
}
|
||||
}
|
||||
when (uiState.value.orderConfirmState) {
|
||||
is OrderConfirmInitVm.OrderConfirmState.ChangeBattery -> ChangeBatteryScreen()
|
||||
is OrderConfirmInitVm.OrderConfirmState.ConfirmEle -> ConfirmEleScreen()
|
||||
is OrderConfirmInitVm.OrderConfirmState.ConfirmH5Success -> ConfirmH5SuccessScreen()
|
||||
is OrderConfirmInitVm.OrderConfirmState.Init -> {
|
||||
Box {
|
||||
LoadingManager.showLoading()
|
||||
}
|
||||
}
|
||||
|
||||
is OrderConfirmInitVm.OrderConfirmState.Failed -> {
|
||||
Box(modifier = Modifier.clickable {
|
||||
vm.dispatch(OrderConfirmInitVm.Action.Init)
|
||||
}) {
|
||||
Text("点击重试")
|
||||
}
|
||||
}
|
||||
is OrderConfirmInitVm.OrderConfirmState.Failed -> {
|
||||
Box(modifier = Modifier.clickable {
|
||||
vm.dispatch(OrderConfirmInitVm.Action.Init)
|
||||
}) {
|
||||
Text("点击重试")
|
||||
}
|
||||
}
|
||||
|
||||
is OrderConfirmInitVm.OrderConfirmState.PaymentInfo -> {
|
||||
ReceiveMoneyActivity.goReceiveMoney(context, userOrderId = uiState.value.orderInfo?.userOrderId
|
||||
?: 0, taskId = uiState.value.orderInfo?.taskId ?: 0)
|
||||
}
|
||||
is OrderConfirmInitVm.OrderConfirmState.PaymentInfo -> {
|
||||
ReceiveMoneyActivity.goReceiveMoney(context,
|
||||
userOrderId = uiState.value.orderInfo?.userOrderId ?: 0,
|
||||
taskId = uiState.value.orderInfo?.taskId ?: 0)
|
||||
}
|
||||
|
||||
else -> RealOrderConfirmActivity.goRealOrderConfirm(context)
|
||||
}
|
||||
else -> RealOrderConfirmActivity.goRealOrderConfirm(context)
|
||||
}
|
||||
|
||||
}
|
@ -17,110 +17,102 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class OrderConfirmInitVm : IServicingVm<OrderConfirmInitVm.Action, OrderConfirmInitVm.UiState>() {
|
||||
private val _uiState = MutableStateFlow(UiState())
|
||||
val uiState get() = _uiState
|
||||
override fun updateState(uiState: UiState) {
|
||||
_uiState.value = uiState
|
||||
}
|
||||
private val _uiState = MutableStateFlow(UiState())
|
||||
val uiState get() = _uiState
|
||||
override fun updateState(uiState : UiState) {
|
||||
_uiState.value = uiState
|
||||
}
|
||||
|
||||
override fun dispatch(action: Action) {
|
||||
when (action) {
|
||||
is Action.Init -> init()
|
||||
is Action.UpdateState -> updateState(action.uiState)
|
||||
}
|
||||
}
|
||||
override fun dispatch(action : Action) {
|
||||
when (action) {
|
||||
is Action.Init -> init()
|
||||
is Action.UpdateState -> updateState(action.uiState)
|
||||
}
|
||||
}
|
||||
|
||||
private fun init() {
|
||||
updateState(uiState.value.copy(orderInfo = getCurrentOrder()))
|
||||
queryPaymentInfo(uiState.value.orderInfo)
|
||||
}
|
||||
private fun init() {
|
||||
updateState(uiState.value.copy(orderInfo = getCurrentOrder()))
|
||||
queryPaymentInfo(uiState.value.orderInfo)
|
||||
}
|
||||
|
||||
private fun queryPaymentInfo(orderInfo: OrderInfo?) {
|
||||
LoadingManager.showLoading()
|
||||
val paymentInfoRequest = PaymentInfoRequest(orderInfo?.userOrderId, orderInfo?.taskId)
|
||||
val eleWorkOrderBean = RoomHelper.db?.eleWorkOrderDao()?.getEleWorkOrder(taskId = orderInfo?.taskId
|
||||
?: 0)
|
||||
RetrofitHelper.getDefaultService().paymentInfoQuery(paymentInfoRequest)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<PaymentInfoBean>() {
|
||||
override fun doSuccess(it: PaymentInfoBean?) {
|
||||
LoadingManager.hideLoading()
|
||||
updateState(uiState.value.copy(paymentInfoBean = it, orderInfo = orderInfo, eleWorkOrderBean = eleWorkOrderBean))
|
||||
if (it?.isPayment == true && it.tradeState != 2) {
|
||||
if (it.askPayment == true) {
|
||||
updateState(uiState.value.copy(showNoNeedPayDialog = true))
|
||||
return
|
||||
}
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.PaymentInfo))
|
||||
return
|
||||
}
|
||||
private fun queryPaymentInfo(orderInfo : OrderInfo?) {
|
||||
LoadingManager.showLoading()
|
||||
val paymentInfoRequest = PaymentInfoRequest(orderInfo?.userOrderId, orderInfo?.taskId)
|
||||
val eleWorkOrderBean =
|
||||
RoomHelper.db?.eleWorkOrderDao()?.getEleWorkOrder(taskId = orderInfo?.taskId ?: 0)
|
||||
RetrofitHelper.getDefaultService().paymentInfoQuery(paymentInfoRequest)
|
||||
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : BaseObserver<PaymentInfoBean>() {
|
||||
override fun doSuccess(it : PaymentInfoBean?) {
|
||||
LoadingManager.hideLoading()
|
||||
updateState(uiState.value.copy(paymentInfoBean = it,
|
||||
orderInfo = orderInfo,
|
||||
eleWorkOrderBean = eleWorkOrderBean))
|
||||
if (eleWorkOrderBean != null && eleWorkOrderBean.driverChoiceNoNeedReceiveMoney == true) {
|
||||
handlerOtherState(orderInfo, eleWorkOrderBean)
|
||||
return
|
||||
}
|
||||
if (it?.isPayment == true && it.tradeState != 2) {
|
||||
if (it.askPayment == true) {
|
||||
updateState(uiState.value.copy(showNoNeedPayDialog = true))
|
||||
return
|
||||
}
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.PaymentInfo))
|
||||
return
|
||||
}
|
||||
|
||||
if (orderInfo?.electronOrderState == 0 || orderInfo?.electronOrderState == 1
|
||||
|| orderInfo?.electronOrderState == 2
|
||||
) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ConfirmEle))
|
||||
return
|
||||
}
|
||||
handlerOtherState(orderInfo, eleWorkOrderBean)
|
||||
}
|
||||
|
||||
if (eleWorkOrderBean?.changeBattery == true) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ChangeBattery))
|
||||
return
|
||||
}
|
||||
if (eleWorkOrderBean?.hasCreatedEleWorkOrderPhoto == null || eleWorkOrderBean.hasCreatedEleWorkOrderPhoto != true) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ConfirmH5Success))
|
||||
return
|
||||
}
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.OrderConfirm))
|
||||
}
|
||||
override fun doFailure(code : Int, msg : String?) {
|
||||
LoadingManager.hideLoading()
|
||||
LogUtil.print("eleworkOrder", eleWorkOrderBean.toJson() ?: "")
|
||||
updateState(uiState.value.copy(orderInfo = orderInfo, eleWorkOrderBean = eleWorkOrderBean))
|
||||
handlerOtherState(orderInfo, eleWorkOrderBean)
|
||||
LogUtil.print("queryPaymentInfo", "failed=$msg request=${paymentInfoRequest.toJson()}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun doFailure(code: Int, msg: String?) {
|
||||
LoadingManager.hideLoading()
|
||||
LogUtil.print("eleworkOrder", eleWorkOrderBean.toJson() ?: "")
|
||||
updateState(uiState.value.copy(orderInfo = orderInfo, eleWorkOrderBean = eleWorkOrderBean))
|
||||
if (orderInfo?.electronOrderState == 0 || orderInfo?.electronOrderState == 1 || orderInfo?.electronOrderState == 2) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ConfirmEle))
|
||||
return
|
||||
}
|
||||
private fun handlerOtherState(orderInfo : OrderInfo?, eleWorkOrderBean : EleWorkOrderBean?) {
|
||||
if (orderInfo?.electronOrderState == 0 || orderInfo?.electronOrderState == 1 || orderInfo?.electronOrderState == 2) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ConfirmEle))
|
||||
return
|
||||
}
|
||||
|
||||
if (eleWorkOrderBean?.changeBattery == true) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ChangeBattery))
|
||||
return
|
||||
}
|
||||
if (eleWorkOrderBean?.changeBattery == true) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ChangeBattery))
|
||||
return
|
||||
}
|
||||
if (eleWorkOrderBean?.hasCreatedEleWorkOrderPhoto == null || eleWorkOrderBean.hasCreatedEleWorkOrderPhoto != true) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ConfirmH5Success))
|
||||
return
|
||||
}
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.OrderConfirm))
|
||||
}
|
||||
|
||||
if (eleWorkOrderBean?.hasCreatedEleWorkOrderPhoto == null || eleWorkOrderBean.hasCreatedEleWorkOrderPhoto != true) {
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.ConfirmH5Success))
|
||||
return
|
||||
}
|
||||
sealed class Action {
|
||||
data object Init : Action()
|
||||
data class UpdateState(val uiState : UiState) : Action()
|
||||
}
|
||||
|
||||
updateState(uiState.value.copy(orderConfirmState = OrderConfirmState.OrderConfirm))
|
||||
LogUtil.print("queryPaymentInfo", "failed=$msg request=${paymentInfoRequest.toJson()}")
|
||||
}
|
||||
})
|
||||
}
|
||||
data class UiState(
|
||||
val orderConfirmState : OrderConfirmState = OrderConfirmState.Init,
|
||||
val orderInfo : OrderInfo? = null,
|
||||
val eleWorkOrderBean : EleWorkOrderBean? = null,
|
||||
val goNextPage : UpdateTaskBean? = null,
|
||||
val isGoNextPageDialog : Boolean? = null,
|
||||
val paymentInfoBean : PaymentInfoBean? = null,
|
||||
val showNoNeedPayDialog : Boolean? = null,
|
||||
)
|
||||
|
||||
sealed class Action {
|
||||
data object Init : Action()
|
||||
data class UpdateState(val uiState: UiState) : Action()
|
||||
}
|
||||
|
||||
data class UiState(
|
||||
val orderConfirmState: OrderConfirmState = OrderConfirmState.Init,
|
||||
val orderInfo: OrderInfo? = null,
|
||||
val eleWorkOrderBean: EleWorkOrderBean? = null,
|
||||
val goNextPage: UpdateTaskBean? = null,
|
||||
val isGoNextPageDialog: Boolean? = null,
|
||||
val paymentInfoBean: PaymentInfoBean? = null,
|
||||
val showNoNeedPayDialog: Boolean? = null,
|
||||
)
|
||||
|
||||
sealed class OrderConfirmState {
|
||||
data object Init : OrderConfirmState()
|
||||
data object Failed : OrderConfirmState()
|
||||
data object PaymentInfo : OrderConfirmState()
|
||||
data object ConfirmEle : OrderConfirmState()
|
||||
data object ChangeBattery : OrderConfirmState()
|
||||
data object ConfirmH5Success : OrderConfirmState()
|
||||
data object OrderConfirm : OrderConfirmState()
|
||||
}
|
||||
sealed class OrderConfirmState {
|
||||
data object Init : OrderConfirmState()
|
||||
data object Failed : OrderConfirmState()
|
||||
data object PaymentInfo : OrderConfirmState()
|
||||
data object ConfirmEle : OrderConfirmState()
|
||||
data object ChangeBattery : OrderConfirmState()
|
||||
data object ConfirmH5Success : OrderConfirmState()
|
||||
data object OrderConfirm : OrderConfirmState()
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.za.ui.view
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Path
|
||||
import android.util.AttributeSet
|
||||
import android.widget.FrameLayout
|
||||
import androidx.camera.view.PreviewView
|
||||
import com.blankj.utilcode.util.ConvertUtils
|
||||
|
||||
class CirclePreviewContainer @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||
|
||||
private val path = Path()
|
||||
private var previewView: PreviewView? = null
|
||||
|
||||
init {
|
||||
setWillNotDraw(false)
|
||||
}
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
val centerX = w / 2f
|
||||
val centerY = h / 2f
|
||||
val radius = ConvertUtils.dp2px(150f).toFloat().coerceAtMost(w / 2f).coerceAtMost(h / 2f)
|
||||
path.reset()
|
||||
path.addCircle(centerX, centerY, radius, Path.Direction.CW)
|
||||
}
|
||||
|
||||
override fun dispatchDraw(canvas: Canvas) {
|
||||
canvas.save()
|
||||
canvas.clipPath(path)
|
||||
super.dispatchDraw(canvas)
|
||||
canvas.restore()
|
||||
}
|
||||
|
||||
override fun onFinishInflate() {
|
||||
super.onFinishInflate()
|
||||
if (childCount > 0) {
|
||||
val child = getChildAt(0)
|
||||
if (child is PreviewView) {
|
||||
previewView = child
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
servicing/src/main/res/drawable/preview_overlay_mask.xml
Normal file
21
servicing/src/main/res/drawable/preview_overlay_mask.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Dark semi-transparent background -->
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#00000000" />
|
||||
</shape>
|
||||
</item>
|
||||
<!-- Circle with light border -->
|
||||
<item android:gravity="center">
|
||||
<shape android:shape="oval">
|
||||
<size
|
||||
android:width="300dp"
|
||||
android:height="300dp" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="#FFFFFFFF" />
|
||||
<solid android:color="#00000000" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<com.za.ui.view.CirclePreviewContainer
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="300dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.camera.view.PreviewView
|
||||
android:id="@+id/viewFinder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</com.za.ui.view.CirclePreviewContainer>
|
||||
|
||||
<View
|
||||
android:id="@+id/previewOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/preview_overlay_mask" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/stepText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="50dp"
|
||||
android:background="#80000000"
|
||||
android:padding="16dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:text="请保持面部居中" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/confirmationLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/black"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<com.za.signature.view.CircleImageView
|
||||
android:id="@+id/previewImage"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="300dp"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="确认使用这张照片?"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/retryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="重试" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/confirmButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="确认" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Reference in New Issue
Block a user